diff options
author | Pixel <pixel@nobis-crew.org> | 2009-11-04 11:56:41 -0800 |
---|---|---|
committer | Pixel <pixel@nobis-crew.org> | 2009-11-04 11:59:33 -0800 |
commit | d577d991b97ae2b5ee1af23641bcffc3f83af5b2 (patch) | |
tree | 590639d50205d1bcfaff2a7d2dc6ebf3f373c7ed /iup/src |
Initial import. Contains the im, cd and iup librairies, and a "working" Makefile for them under linux.
Diffstat (limited to 'iup/src')
217 files changed, 69894 insertions, 0 deletions
diff --git a/iup/src/Makefile b/iup/src/Makefile new file mode 100755 index 0000000..028047f --- /dev/null +++ b/iup/src/Makefile @@ -0,0 +1,9 @@ + +.PHONY: do_all iup iupgtk +do_all: iup iupgtk + +iup: + @$(MAKE) --no-print-directory -f ../tecmake_compact.mak + +iupgtk: + @$(MAKE) --no-print-directory -f ../tecmake_compact.mak USE_GTK=Yes diff --git a/iup/src/config.mak b/iup/src/config.mak new file mode 100755 index 0000000..e857643 --- /dev/null +++ b/iup/src/config.mak @@ -0,0 +1,118 @@ +PROJNAME = iup +LIBNAME = iup +OPT = YES + +#ifdef DBG + DEFINES += IUP_ASSERT +#endif + +INCLUDES = ../include . + +SRC = iup_array.c iup_callback.c iup_dlglist.c iup_attrib.c iup_focus.c iup_font.c \ + iup_globalattrib.c iup_object.c iup_key.c iup_layout.c iup_ledlex.c iup_names.c iup_open.c \ + iup_ledparse.c iup_predial.c iup_register.c iup_scanf.c iup_show.c iup_str.c iup_table.c \ + iup_func.c iup_childtree.c iup.c iup_classattrib.c iup_dialog.c iup_assert.c iup_canvas.c \ + iup_messagedlg.c iup_timer.c iup_image.c iup_label.c iup_fill.c iup_zbox.c \ + iup_colordlg.c iup_fontdlg.c iup_filedlg.c iup_strmessage.c iup_menu.c iup_frame.c \ + iup_user.c iup_button.c iup_radio.c iup_toggle.c iup_progressbar.c iup_text.c iup_val.c \ + iup_box.c iup_hbox.c iup_vbox.c iup_cbox.c iup_class.c iup_classbase.c iup_maskmatch.c \ + iup_mask.c iup_maskparse.c iup_tabs.c iup_spin.c iup_list.c iup_getparam.c \ + iup_sbox.c iup_normalizer.c iup_tree.c + +ifdef USE_GTK + ifndef GTK_DEFAULT + # Build GTK version in IRIX,SunOS,AIX,Win32 + LIBNAME := iupgtk + endif + + DEFINES += GTK_DISABLE_DEPRECATED + INCLUDES += gtk + SRC += gtk/iupgtk_common.c gtk/iupgtk_focus.c gtk/iupgtk_font.c gtk/iupgtk_clipboard.c \ + gtk/iupgtk_globalattrib.c gtk/iupgtk_key.c gtk/iupgtk_tips.c \ + gtk/iupgtk_loop.c gtk/iupgtk_open.c gtk/iupgtk_messagedlg.c \ + gtk/iupgtk_dialog.c gtk/iupgtk_timer.c gtk/iupgtk_image.c gtk/iupgtk_label.c \ + gtk/iupgtk_colordlg.c gtk/iupgtk_fontdlg.c gtk/iupgtk_filedlg.c \ + gtk/iupgtk_button.c gtk/iupgtk_toggle.c gtk/iupgtk_progressbar.c \ + gtk/iupgtk_text.c gtk/iupgtk_val.c gtk/iupgtk_frame.c gtk/iupgtk_canvas.c \ + gtk/iupgtk_tabs.c gtk/iupgtk_menu.c gtk/iupgtk_list.c gtk/iupgtk_tree.c + + ifneq ($(findstring Win, $(TEC_SYSNAME)), ) + DEFINES += _WIN32_WINNT=0x0500 _WIN32_IE=0x0500 WINVER=0x0500 NOTREEVIEW + SRC += win/iupwindows_main.c win/iupwindows_help.c win/iupwindows_info.c + else + SRC += gtk/iupgtk_help.c mot/iupunix_info.c + endif + + ifdef USE_HILDON + DEFINES += HILDON + INCLUDES += /usr/include/hildon-1 + LIBS += hildon-1 + endif +else + ifneq ($(findstring Win, $(TEC_SYSNAME)), ) + + SRC += win/iupwin_common.c win/iupwin_brush.c win/iupwin_focus.c win/iupwin_font.c \ + win/iupwin_globalattrib.c win/iupwin_handle.c win/iupwin_key.c \ + win/iupwin_loop.c win/iupwin_open.c win/iupwin_tips.c win/iupwin_info.c \ + win/iupwin_dialog.c win/iupwin_messagedlg.c win/iupwin_timer.c \ + win/iupwin_image.c win/iupwin_label.c win/iupwin_canvas.c win/iupwin_frame.c \ + win/iupwin_colordlg.c win/iupwin_fontdlg.c win/iupwin_filedlg.c \ + win/iupwin_button.c win/iupwin_draw.c win/iupwin_toggle.c win/iupwin_clipboard.c \ + win/iupwin_progressbar.c win/iupwin_text.c win/iupwin_val.c \ + win/iupwin_tabs.c win/iupwin_menu.c win/iupwin_list.c win/iupwin_tree.c + + SRC += win/iupwindows_main.c win/iupwindows_help.c win/iupwindows_info.c + + INCLUDES += win + DEFINES += _WIN32_WINNT=0x0500 _WIN32_IE=0x0500 WINVER=0x0500 NOTREEVIEW + else + ifdef GTK_DEFAULT + # Build Motif version in Linux,Darwin,FreeBSD + LIBNAME := iupmot + endif + + SRC += mot/iupmot_common.c mot/iupmot_color.c mot/iupmot_focus.c mot/iupmot_font.c \ + mot/iupmot_key.c mot/iupmot_loop.c mot/iupmot_open.c mot/iupmot_tips.c \ + mot/iupmot_globalattrib.c mot/iupmot_dialog.c mot/iupmot_messagedlg.c \ + mot/iupmot_timer.c mot/iupmot_image.c mot/iupmot_label.c mot/iupmot_canvas.c \ + mot/iupmot_colordlg.c mot/iupmot_fontdlg.c mot/iupmot_filedlg.c mot/iupmot_frame.c \ + mot/iupmot_button.c mot/iupmot_toggle.c mot/iupmot_progressbar.c mot/iupmot_clipboard.c \ + mot/iupmot_text.c mot/iupmot_val.c mot/iupmot_tabs.c mot/iupmot_menu.c \ + mot/iupmot_list.c mot/iupmot_tree.c + + SRC += mot/iupunix_help.c mot/iupunix_info.c + + INCLUDES += mot + USE_MOTIF=Yes + endif +endif + +ifeq "$(TEC_SYSNAME)" "SunOS" + # Necessary or the fileopen will not work in SunOS (needs to be retested) + #DEFINES += NO_PATH_MODE_RELATIVE +endif + +ifneq ($(findstring dll, $(TEC_UNAME)), ) + DEFINES += IUP_DLL + SRC += iup_dll.rc + DEF_FILE = iup.def +endif + +ifeq "$(TEC_UNAME)" "vc6" + # Necessary because VC6 has an old WinSDK + #WINSDK = d:/lng/vc7/PlatformSDK + #INCLUDES += $(WINSDK)/include + #LDIR = $(WINSDK)/lib +endif + +ifeq "$(TEC_UNAME)" "dll" + # Necessary because VC6 has an old WinSDK + #WINSDK = d:/lng/vc7/PlatformSDK + #INCLUDES += $(WINSDK)/include + #LDIR = $(WINSDK)/lib +endif + +ifeq "$(TEC_UNAME)" "owc1" + # Necessary or IUP will not work in Open Watcom + DBG=Yes +endif diff --git a/iup/src/gtk/iupgtk_button.c b/iup/src/gtk/iupgtk_button.c new file mode 100755 index 0000000..18be87c --- /dev/null +++ b/iup/src/gtk/iupgtk_button.c @@ -0,0 +1,477 @@ +/** \file + * \brief Button Control + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_image.h" +#include "iup_button.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_image.h" +#include "iup_key.h" + +#include "iupgtk_drv.h" + + +#if !GTK_CHECK_VERSION(2, 6, 0) +static void gtk_button_set_image(GtkButton *button, GtkWidget *image) +{ +} +static GtkWidget* gtk_button_get_image(GtkButton *button) +{ + return NULL; +} +#endif + +void iupdrvButtonAddBorders(int *x, int *y) +{ +#ifdef WIN32 + int border_size = 2*5; +#else +#ifdef HILDON + int border_size = 2*7+1; /* borders are not symetric */ +#else + int border_size = 2*5+1; /* borders are not symetric */ +#endif +#endif + (*x) += border_size; + (*y) += border_size; +} + +static void gtk_button_children_callback(GtkWidget *widget, gpointer client_data) +{ + if (GTK_IS_LABEL(widget)) + { + GtkLabel **label = (GtkLabel**) client_data; + *label = (GtkLabel*)widget; + } +} + +static GtkLabel* gtkButtonGetLabel(Ihandle* ih) +{ + if (ih->data->type == IUP_BUTTON_TEXT) /* text only */ + return (GtkLabel*)gtk_bin_get_child((GtkBin*)ih->handle); + else if (ih->data->type == IUP_BUTTON_BOTH) /* both */ + { + /* when both is set, button contains an GtkAlignment, + that contains a GtkBox, that contains a label and an image */ + GtkContainer *container = (GtkContainer*)gtk_bin_get_child((GtkBin*)gtk_bin_get_child((GtkBin*)ih->handle)); + GtkLabel* label = NULL; + gtk_container_foreach(container, gtk_button_children_callback, &label); + return label; + } + return NULL; +} + +static int gtkButtonSetTitleAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type != IUP_BUTTON_IMAGE) /* text or both */ + { + GtkLabel* label = gtkButtonGetLabel(ih); + iupgtkSetMnemonicTitle(ih, label, value); + return 1; + } + + return 0; +} + +static int gtkButtonSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + GtkButton* button = (GtkButton*)ih->handle; + PangoAlignment alignment; + float xalign, yalign; + char value1[30]="", value2[30]=""; + + iupStrToStrStr(value, value1, value2, ':'); + + if (iupStrEqualNoCase(value1, "ARIGHT")) + { + xalign = 1.0f; + alignment = PANGO_ALIGN_RIGHT; + } + else if (iupStrEqualNoCase(value1, "ACENTER")) + { + xalign = 0.5f; + alignment = PANGO_ALIGN_CENTER; + } + else /* "ALEFT" */ + { + xalign = 0; + alignment = PANGO_ALIGN_LEFT; + } + + if (iupStrEqualNoCase(value2, "ABOTTOM")) + yalign = 1.0f; + else if (iupStrEqualNoCase(value2, "ATOP")) + yalign = 0; + else /* ACENTER (default) */ + yalign = 0.5f; + + gtk_button_set_alignment(button, xalign, yalign); + + if (ih->data->type == IUP_BUTTON_TEXT && !GTK_IS_COLOR_BUTTON(ih->handle)) /* text only */ + { + PangoLayout* layout = gtk_label_get_layout(gtkButtonGetLabel(ih)); + if (layout) pango_layout_set_alignment(layout, alignment); + } + + return 1; +} + +static int gtkButtonSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle) + { + if (ih->data->type == IUP_BUTTON_TEXT) /* text only */ + { + GtkMisc* misc = (GtkMisc*)gtk_bin_get_child((GtkBin*)ih->handle); + gtk_misc_set_padding(misc, ih->data->horiz_padding, ih->data->vert_padding); + } + else + { + GtkAlignment* alignment = (GtkAlignment*)gtk_bin_get_child((GtkBin*)ih->handle); + gtk_alignment_set_padding(alignment, ih->data->vert_padding, ih->data->vert_padding, + ih->data->horiz_padding, ih->data->horiz_padding); + } + } + return 0; +} + +#ifdef WIN32 +static int gtkButtonSetBgColorAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_BUTTON_TEXT && GTK_IS_COLOR_BUTTON(ih->handle)) + { + GdkColor color; + unsigned char r, g, b; + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + iupgdkColorSet(&color, r, g, b); + gtk_color_button_set_color((GtkColorButton*)ih->handle, &color); + return 1; + } + + return iupdrvBaseSetBgColorAttrib(ih, value); +} +#endif + +static int gtkButtonSetFgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + GtkLabel* label = gtkButtonGetLabel(ih); + if (!label) return 0; + + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + iupgtkBaseSetFgColor((GtkWidget*)label, r, g, b); + + return 1; +} + +static int gtkButtonSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + iupdrvSetStandardFontAttrib(ih, value); + + if (ih->handle) + { + GtkLabel* label = gtkButtonGetLabel(ih); + if (!label) return 1; + + gtk_widget_modify_font((GtkWidget*)label, (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih)); + if (ih->data->type == IUP_BUTTON_TEXT && !GTK_IS_COLOR_BUTTON(ih->handle)) /* text only */ + iupgtkFontUpdatePangoLayout(ih, gtk_label_get_layout(label)); + } + return 1; +} + +static void gtkButtonSetPixbuf(Ihandle* ih, const char* name, int make_inactive) +{ + GtkButton* button = (GtkButton*)ih->handle; + GtkImage* image = (GtkImage*)gtk_button_get_image(button); + + if (name && image) + { + GdkPixbuf* pixbuf = iupImageGetImage(name, ih, make_inactive); + GdkPixbuf* old_pixbuf = gtk_image_get_pixbuf(image); + if (pixbuf != old_pixbuf) + gtk_image_set_from_pixbuf(image, pixbuf); + return; + } + + /* if not defined */ +#if GTK_CHECK_VERSION(2, 8, 0) + if (image) + gtk_image_clear(image); +#endif +} + +static int gtkButtonSetImageAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type != IUP_BUTTON_TEXT) /* image or both */ + { + if (iupdrvIsActive(ih)) + gtkButtonSetPixbuf(ih, value, 0); + else + { + if (!iupAttribGet(ih, "IMINACTIVE")) + { + /* if not active and IMINACTIVE is not defined + then automaticaly create one based on IMAGE */ + gtkButtonSetPixbuf(ih, value, 1); /* make_inactive */ + } + } + return 1; + } + else + return 0; +} + +static int gtkButtonSetImInactiveAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type != IUP_BUTTON_TEXT) /* image or both */ + { + if (!iupdrvIsActive(ih)) + { + if (value) + gtkButtonSetPixbuf(ih, value, 0); + else + { + /* if not defined then automaticaly create one based on IMAGE */ + char* name = iupAttribGet(ih, "IMAGE"); + gtkButtonSetPixbuf(ih, name, 1); /* make_inactive */ + } + } + return 1; + } + else + return 0; +} + +static int gtkButtonSetActiveAttrib(Ihandle* ih, const char* value) +{ + /* update the inactive image if necessary */ + if (ih->data->type != IUP_BUTTON_TEXT) /* image or both */ + { + if (!iupStrBoolean(value)) + { + char* name = iupAttribGet(ih, "IMINACTIVE"); + if (name) + gtkButtonSetPixbuf(ih, name, 0); + else + { + /* if not defined then automaticaly create one based on IMAGE */ + name = iupAttribGet(ih, "IMAGE"); + gtkButtonSetPixbuf(ih, name, 1); /* make_inactive */ + } + } + else + { + /* must restore the normal image */ + char* name = iupAttribGet(ih, "IMAGE"); + gtkButtonSetPixbuf(ih, name, 0); + } + } + + return iupBaseSetActiveAttrib(ih, value); +} + +static int gtkButtonSetFocusOnClickAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + gtk_button_set_focus_on_click((GtkButton*)ih->handle, TRUE); + else + gtk_button_set_focus_on_click((GtkButton*)ih->handle, FALSE); + return 1; +} + +static gboolean gtkButtonEnterLeaveEvent(GtkWidget *widget, GdkEventCrossing *evt, Ihandle *ih) +{ + iupgtkEnterLeaveEvent(widget, evt, ih); + (void)widget; + + if (evt->type == GDK_ENTER_NOTIFY) + gtk_button_set_relief((GtkButton*)ih->handle, GTK_RELIEF_NORMAL); + else if (evt->type == GDK_LEAVE_NOTIFY) + gtk_button_set_relief((GtkButton*)ih->handle, GTK_RELIEF_NONE); + + return FALSE; +} + +static gboolean gtkButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih) +{ + if (iupgtkButtonEvent(widget, evt, ih)==TRUE) + return TRUE; + + if (ih->data->type != IUP_BUTTON_TEXT) /* image or both */ + { + char* name = iupAttribGet(ih, "IMPRESS"); + if (name) + { + if (evt->type == GDK_BUTTON_PRESS) + gtkButtonSetPixbuf(ih, name, 0); + else + { + name = iupAttribGet(ih, "IMAGE"); + gtkButtonSetPixbuf(ih, name, 0); + } + } + } + + return FALSE; +} + +static void gtkButtonClicked(GtkButton *widget, Ihandle* ih) +{ + Icallback cb = IupGetCallback(ih, "ACTION"); + if (cb) + { + if (cb(ih) == IUP_CLOSE) + IupExitLoop(); + } + (void)widget; +} + +static int gtkButtonMapMethod(Ihandle* ih) +{ + int impress; + char* value; + + ih->handle = gtk_button_new(); + if (!ih->handle) + return IUP_ERROR; + + value = iupAttribGet(ih, "IMAGE"); + if (value) + { + gtk_button_set_image((GtkButton*)ih->handle, gtk_image_new()); + ih->data->type = IUP_BUTTON_IMAGE; + + value = iupAttribGet(ih, "TITLE"); + if (value) + { + GtkSettings* settings = gtk_widget_get_settings(ih->handle); + g_object_set(settings, "gtk-button-images", (int)TRUE, NULL); + + gtk_button_set_label((GtkButton*)ih->handle, value); + ih->data->type |= IUP_BUTTON_TEXT; + +#if GTK_CHECK_VERSION(2, 10, 0) + gtk_button_set_image_position((GtkButton*)ih->handle, ih->data->img_position); /* IUP and GTK have the same Ids */ +#endif + } + } + else + { + char* title = iupAttribGet(ih, "TITLE"); + if (!title) + { +#ifdef WIN32 + if (iupAttribGet(ih, "BGCOLOR")) + { + gtk_widget_destroy(ih->handle); + ih->handle = gtk_color_button_new(); + } + else + gtk_button_set_label((GtkButton*)ih->handle, ""); +#else + gtk_button_set_label((GtkButton*)ih->handle, ""); +#endif + } + else + gtk_button_set_label((GtkButton*)ih->handle, title); + ih->data->type = IUP_BUTTON_TEXT; + } + + /* add to the parent, all GTK controls must call this. */ + iupgtkBaseAddToParent(ih); + + if (!iupAttribGetBoolean(ih, "CANFOCUS")) + GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS; + + value = iupAttribGet(ih, "IMPRESS"); + impress = (ih->data->type & IUP_BUTTON_IMAGE && value)? 1: 0; + if (!impress && iupAttribGetBoolean(ih, "FLAT")) + { + gtk_button_set_relief((GtkButton*)ih->handle, GTK_RELIEF_NONE); + + g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(gtkButtonEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(gtkButtonEnterLeaveEvent), ih); + } + else + { + if (impress && !iupAttribGetStr(ih, "IMPRESSBORDER")) + gtk_button_set_relief((GtkButton*)ih->handle, GTK_RELIEF_NONE); + else + gtk_button_set_relief((GtkButton*)ih->handle, GTK_RELIEF_NORMAL); + + g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + } + + g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih); + + g_signal_connect(G_OBJECT(ih->handle), "clicked", G_CALLBACK(gtkButtonClicked), ih); + g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkButtonEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkButtonEvent), ih); + + gtk_widget_realize(ih->handle); + + return IUP_NOERROR; +} + +void iupdrvButtonInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkButtonMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Overwrite Common */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, gtkButtonSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, gtkButtonSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + + /* Visual */ +#ifdef WIN32 + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkButtonSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); +#else + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); +#endif + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkButtonSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "TITLE", NULL, gtkButtonSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupButton only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, gtkButtonSetAlignmentAttrib, "ACENTER:ACENTER", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkButtonSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, gtkButtonSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMPRESS", NULL, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FOCUSONCLICK", NULL, gtkButtonSetFocusOnClickAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "PADDING", iupButtonGetPaddingAttrib, gtkButtonSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "MARKUP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT); +} diff --git a/iup/src/gtk/iupgtk_canvas.c b/iup/src/gtk/iupgtk_canvas.c new file mode 100755 index 0000000..daae4ad --- /dev/null +++ b/iup/src/gtk/iupgtk_canvas.c @@ -0,0 +1,624 @@ +/** \file + * \brief Canvas Control + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvinfo.h" +#include "iup_drvfont.h" +#include "iup_canvas.h" +#include "iup_key.h" + +#include "iupgtk_drv.h" + + +static int gtkCanvasScroll2Iup(GtkScrollType scroll, int vert) +{ + switch(scroll) + { + case GTK_SCROLL_STEP_UP: + return IUP_SBUP; + case GTK_SCROLL_STEP_DOWN: + return IUP_SBDN; + case GTK_SCROLL_PAGE_UP: + return IUP_SBPGUP; + case GTK_SCROLL_PAGE_DOWN: + return IUP_SBPGDN; + case GTK_SCROLL_STEP_LEFT: + return IUP_SBLEFT; + case GTK_SCROLL_STEP_RIGHT: + return IUP_SBRIGHT; + case GTK_SCROLL_PAGE_LEFT: + return IUP_SBPGLEFT; + case GTK_SCROLL_PAGE_RIGHT: + return IUP_SBPGRIGHT; + case GTK_SCROLL_STEP_BACKWARD: + return vert? IUP_SBUP: IUP_SBLEFT; + case GTK_SCROLL_STEP_FORWARD: + return vert? IUP_SBDN: IUP_SBRIGHT; + case GTK_SCROLL_PAGE_BACKWARD: + return vert? IUP_SBPGUP: IUP_SBPGLEFT; + case GTK_SCROLL_PAGE_FORWARD: + return vert? IUP_SBPGDN: IUP_SBPGRIGHT; + case GTK_SCROLL_JUMP: + case GTK_SCROLL_START: + case GTK_SCROLL_END: + return vert? IUP_SBPOSV: IUP_SBPOSH; + case GTK_SCROLL_NONE: + return -1; + } + + /* No IUP_SBDRAGV or IUP_SBDRAGH support in GTK */ + + return -1; +} + +static gboolean gtkCanvasHChangeValue(GtkRange *range, GtkScrollType scroll, double value, Ihandle *ih) +{ + double posx, posy; + IFniff cb; + + double xmin = iupAttribGetFloat(ih, "XMIN"); + double xmax = iupAttribGetFloat(ih, "XMAX"); + double dx = iupAttribGetFloat(ih, "DX"); + if (value < xmin) value = xmin; + if (value > xmax-dx) value = xmax-dx; + + posx = value; + ih->data->posx = (float)posx; + posy = ih->data->posy; + + cb = (IFniff)IupGetCallback(ih,"SCROLL_CB"); + if (cb) + { + int op = gtkCanvasScroll2Iup(scroll, 0); + if (op == -1) + return FALSE; + + cb(ih, op, (float)posx, (float)posy); + } + else + { + IFnff cb = (IFnff)IupGetCallback(ih,"ACTION"); + if (cb) + cb (ih, (float)posx, (float)posy); + } + + (void)range; + return FALSE; +} + +static gboolean gtkCanvasVChangeValue(GtkRange *range, GtkScrollType scroll, double value, Ihandle *ih) +{ + double posx, posy; + IFniff cb; + + double ymin = iupAttribGetFloat(ih, "YMIN"); + double ymax = iupAttribGetFloat(ih, "YMAX"); + double dy = iupAttribGetFloat(ih, "DY"); + if (value < ymin) value = ymin; + if (value > ymax-dy) value = ymax-dy; + + posy = value; + ih->data->posy = (float)posy; + posx = ih->data->posx; + + cb = (IFniff)IupGetCallback(ih,"SCROLL_CB"); + if (cb) + { + int op = gtkCanvasScroll2Iup(scroll, 1); + if (op == -1) + return FALSE; + + cb(ih, op, (float)posx, (float)posy); + } + else + { + IFnff cb = (IFnff)IupGetCallback(ih,"ACTION"); + if (cb) + cb (ih, (float)posx, (float)posy); + } + + (void)range; + return FALSE; +} + +static gboolean gtkCanvasScrollEvent(GtkWidget *widget, GdkEventScroll *evt, Ihandle *ih) +{ + IFnfiis wcb = (IFnfiis)IupGetCallback(ih, "WHEEL_CB"); + if (wcb) + { + int delta = evt->direction==GDK_SCROLL_UP||evt->direction==GDK_SCROLL_LEFT? 1: -1; + char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; + int button = evt->direction==GDK_SCROLL_UP||evt->direction==GDK_SCROLL_LEFT? 4: 5; + iupgtkButtonKeySetStatus(evt->state, button, status, 0); + + wcb(ih, (float)delta, (int)evt->x, (int)evt->y, status); + } + else + { + IFniff scb = (IFniff)IupGetCallback(ih,"SCROLL_CB"); + int delta = evt->direction==GDK_SCROLL_UP||evt->direction==GDK_SCROLL_LEFT? 1: -1; + + if (evt->direction==GDK_SCROLL_UP || evt->direction==GDK_SCROLL_DOWN) + { + float posy = ih->data->posy; + posy -= delta*iupAttribGetFloat(ih, "DY")/10.0f; + IupSetfAttribute(ih, "POSY", "%g", posy); + } + else + { + float posx = ih->data->posx; + posx -= delta*iupAttribGetFloat(ih, "DX")/10.0f; + IupSetfAttribute(ih, "POSX", "%g", posx); + } + + if (scb) + { + int scroll_gtk2iup[4] = {IUP_SBUP, IUP_SBDN, IUP_SBLEFT, IUP_SBRIGHT}; + int op = scroll_gtk2iup[evt->direction]; + scb(ih,op,ih->data->posx,ih->data->posy); + } + } + (void)widget; + return TRUE; +} + +static gboolean gtkCanvasButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih) +{ + if (evt->type == GDK_BUTTON_PRESS) + { + /* Force focus on canvas click */ + if (iupAttribGetBoolean(ih, "CANFOCUS")) + gtk_widget_grab_focus(ih->handle); + } + + return iupgtkButtonEvent(widget, evt, ih); +} + +static int gtkCanvasSetBgColorAttrib(Ihandle* ih, const char* value); + +static gboolean gtkCanvasExposeEvent(GtkWidget *widget, GdkEventExpose *evt, Ihandle *ih) +{ + IFnff cb = (IFnff)IupGetCallback(ih,"ACTION"); + if (cb) + { + if (!iupAttribGet(ih, "_IUPGTK_NO_BGCOLOR")) + gtkCanvasSetBgColorAttrib(ih, iupAttribGetStr(ih, "BGCOLOR")); /* reset to update window attributes */ + + iupAttribSetStrf(ih, "CLIPRECT", "%d %d %d %d", evt->area.x, evt->area.y, evt->area.x+evt->area.width-1, evt->area.y+evt->area.height-1); + cb(ih,ih->data->posx,ih->data->posy); + iupAttribSetStr(ih, "CLIPRECT", NULL); + } + + (void)widget; + return TRUE; /* stop other handlers */ +} + +static gboolean gtkCanvasConfigureEvent(GtkWidget *widget, GdkEventConfigure *evt, Ihandle *ih) +{ + IFnii cb = (IFnii)IupGetCallback(ih,"RESIZE_CB"); + if (cb) + cb(ih,evt->width,evt->height); + + (void)widget; + return FALSE; +} + +static GtkScrolledWindow* gtkCanvasGetScrolledWindow(Ihandle* ih) +{ + return (GtkScrolledWindow*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); +} + +static int gtkCanvasSetXAutoHideAttrib(Ihandle* ih, const char *value) +{ + GtkPolicyType vscrollbar_policy; + gtk_scrolled_window_get_policy(gtkCanvasGetScrolledWindow(ih), NULL, &vscrollbar_policy); + + if (ih->data->sb & IUP_SB_HORIZ) + { + GtkPolicyType hscrollbar_policy; + + if (iupStrBoolean(value)) + hscrollbar_policy = GTK_POLICY_AUTOMATIC; + else + hscrollbar_policy = GTK_POLICY_ALWAYS; + + gtk_scrolled_window_set_policy(gtkCanvasGetScrolledWindow(ih), hscrollbar_policy, vscrollbar_policy); + } + else + gtk_scrolled_window_set_policy(gtkCanvasGetScrolledWindow(ih), GTK_POLICY_NEVER, vscrollbar_policy); + + return 1; +} + +static int gtkCanvasSetYAutoHideAttrib(Ihandle* ih, const char *value) +{ + GtkPolicyType hscrollbar_policy; + gtk_scrolled_window_get_policy(gtkCanvasGetScrolledWindow(ih), &hscrollbar_policy, NULL); + + if (ih->data->sb & IUP_SB_VERT) + { + GtkPolicyType vscrollbar_policy; + + if (iupStrBoolean(value)) + vscrollbar_policy = GTK_POLICY_AUTOMATIC; + else + vscrollbar_policy = GTK_POLICY_ALWAYS; + + gtk_scrolled_window_set_policy(gtkCanvasGetScrolledWindow(ih), hscrollbar_policy, vscrollbar_policy); + } + else + gtk_scrolled_window_set_policy(gtkCanvasGetScrolledWindow(ih), hscrollbar_policy, GTK_POLICY_NEVER); + + return 1; +} + +static int gtkCanvasCheckScroll(double min, double max, double *page, double *pos) +{ + double old_pos = *pos; + double range = max-min; + if (*page > range) *page = range; + if (*page <= 0) *page = range/10.; + + if (*pos < min) *pos = min; + if (*pos > (max - *page)) *pos = max - *page; + + if (old_pos == *pos) + return 0; + else + return 1; +} + +static int gtkCanvasSetDXAttrib(Ihandle* ih, const char *value) +{ + if (ih->data->sb & IUP_SB_HORIZ) + { + double xmin, xmax, linex; + float dx; + int value_changed; + GtkAdjustment* sb_horiz = gtk_scrolled_window_get_hadjustment(gtkCanvasGetScrolledWindow(ih)); + if (!sb_horiz) return 1; + + if (!iupStrToFloat(value, &dx)) + return 1; + + xmin = iupAttribGetFloat(ih, "XMIN"); + xmax = iupAttribGetFloat(ih, "XMAX"); + + if (!iupAttribGet(ih,"LINEX")) + { + linex = dx/10; + if (linex==0) + linex = 1; + } + else + linex = iupAttribGetFloat(ih,"LINEX"); + + sb_horiz->lower = xmin; + sb_horiz->upper = xmax; + sb_horiz->step_increment = linex; + sb_horiz->page_size = dx; + + value_changed = gtkCanvasCheckScroll(xmin, xmax, &sb_horiz->page_size, &sb_horiz->value); + sb_horiz->page_increment = sb_horiz->page_size; + + gtk_adjustment_changed(sb_horiz); + + if (value_changed) + gtk_adjustment_value_changed(sb_horiz); + } + return 1; +} + +static int gtkCanvasSetDYAttrib(Ihandle* ih, const char *value) +{ + if (ih->data->sb & IUP_SB_VERT) + { + double ymin, ymax, liney; + float dy; + int value_changed; + GtkAdjustment* sb_vert = gtk_scrolled_window_get_vadjustment(gtkCanvasGetScrolledWindow(ih)); + if (!sb_vert) return 1; + + if (!iupStrToFloat(value, &dy)) + return 1; + + ymin = iupAttribGetFloat(ih, "YMIN"); + ymax = iupAttribGetFloat(ih, "YMAX"); + + if (!iupAttribGet(ih,"LINEY")) + { + liney = dy/10; + if (liney==0) + liney = 1; + } + else + liney = iupAttribGetFloat(ih,"LINEY"); + + sb_vert->lower = ymin; + sb_vert->upper = ymax; + sb_vert->step_increment = liney; + sb_vert->page_size = dy; + + value_changed = gtkCanvasCheckScroll(ymin, ymax, &sb_vert->page_size, &sb_vert->value); + sb_vert->page_increment = sb_vert->page_size; + + gtk_adjustment_changed(sb_vert); + + if (value_changed) + gtk_adjustment_value_changed(sb_vert); + } + return 1; +} + +static int gtkCanvasSetPosXAttrib(Ihandle* ih, const char *value) +{ + if (ih->data->sb & IUP_SB_HORIZ) + { + float posx, xmin, xmax, dx; + GtkAdjustment* sb_horiz = gtk_scrolled_window_get_hadjustment(gtkCanvasGetScrolledWindow(ih)); + if (!sb_horiz) return 1; + + if (!iupStrToFloat(value, &posx)) + return 1; + + xmin = iupAttribGetFloat(ih, "XMIN"); + xmax = iupAttribGetFloat(ih, "XMAX"); + dx = iupAttribGetFloat(ih, "DX"); + + if (posx < xmin) posx = xmin; + if (posx > (xmax - dx)) posx = xmax - dx; + ih->data->posx = posx; + + gtk_adjustment_set_value(sb_horiz, posx); + } + return 1; +} + +static int gtkCanvasSetPosYAttrib(Ihandle* ih, const char *value) +{ + if (ih->data->sb & IUP_SB_VERT) + { + float posy, ymin, ymax, dy; + GtkAdjustment* sb_vert = gtk_scrolled_window_get_vadjustment(gtkCanvasGetScrolledWindow(ih)); + if (!sb_vert) return 1; + + if (!iupStrToFloat(value, &posy)) + return 1; + + ymin = iupAttribGetFloat(ih, "YMIN"); + ymax = iupAttribGetFloat(ih, "YMAX"); + dy = iupAttribGetFloat(ih, "DY"); + + if (posy < ymin) posy = ymin; + if (posy > (ymax - dy)) posy = ymax - dy; + ih->data->posy = posy; + + gtk_adjustment_set_value(sb_vert, posy); + } + return 1; +} + +static int gtkCanvasSetBgColorAttrib(Ihandle* ih, const char* value) +{ + GtkScrolledWindow* scrolled_window = gtkCanvasGetScrolledWindow(ih); + unsigned char r, g, b; + + /* ignore given value, must use only from parent for the scrollbars */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + if (iupStrToRGB(parent_value, &r, &g, &b)) + { + GtkWidget* sb; + + iupgtkBaseSetBgColor((GtkWidget*)scrolled_window, r, g, b); + +#if GTK_CHECK_VERSION(2, 8, 0) + sb = gtk_scrolled_window_get_hscrollbar(scrolled_window); + if (sb) iupgtkBaseSetBgColor(sb, r, g, b); + sb = gtk_scrolled_window_get_vscrollbar(scrolled_window); + if (sb) iupgtkBaseSetBgColor(sb, r, g, b); +#endif + } + + if (!IupGetCallback(ih, "ACTION")) + { + /* enable automatic double buffering */ + gtk_widget_set_double_buffered(ih->handle, TRUE); + gtk_widget_set_double_buffered((GtkWidget*)scrolled_window, TRUE); + return iupdrvBaseSetBgColorAttrib(ih, value); + } + else + { + /* disable automatic double buffering */ + gtk_widget_set_double_buffered(ih->handle, FALSE); + gtk_widget_set_double_buffered((GtkWidget*)scrolled_window, FALSE); + gdk_window_set_back_pixmap(ih->handle->window, NULL, FALSE); + iupAttribSetStr(ih, "_IUPGTK_NO_BGCOLOR", "1"); + return 1; + } +} + +static char* gtkCanvasGetDrawableAttrib(Ihandle* ih) +{ + return (char*)ih->handle->window; +} + +static void gtkCanvasDummyLogFunc(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) +{ + /* does nothing */ + (void)log_domain; + (void)log_level; + (void)message; + (void)user_data; +} + +static int gtkCanvasMapMethod(Ihandle* ih) +{ + GtkScrolledWindow* scrolled_window; + void* visual; + + if (!ih->parent) + return IUP_ERROR; + + ih->data->sb = iupBaseGetScrollbar(ih); + + visual = (void*)IupGetAttribute(ih, "VISUAL"); /* defined by the OpenGL Canvas in X11 or NULL */ + if (visual) + iupgtkPushVisualAndColormap(visual, (void*)iupAttribGet(ih, "COLORMAP")); + + ih->handle = gtk_drawing_area_new(); + + if (visual) + gtk_widget_pop_colormap(); + + if (!ih->handle) + return IUP_ERROR; + + scrolled_window = (GtkScrolledWindow*)gtk_scrolled_window_new(NULL, NULL); + if (!scrolled_window) + return IUP_ERROR; + + { + /* to avoid the "cannot add non scrollable widget" warning */ +#if GTK_CHECK_VERSION(2, 6, 0) + GLogFunc def_func = g_log_set_default_handler(gtkCanvasDummyLogFunc, NULL); +#endif + gtk_container_add((GtkContainer*)scrolled_window, ih->handle); +#if GTK_CHECK_VERSION(2, 6, 0) + g_log_set_default_handler(def_func, NULL); +#endif + } + + gtk_widget_show((GtkWidget*)scrolled_window); + + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)scrolled_window); + + /* add to the parent, all GTK controls must call this. */ + iupgtkBaseAddToParent(ih); + + g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "key-release-event", G_CALLBACK(iupgtkKeyReleaseEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih); + + g_signal_connect(G_OBJECT(ih->handle), "expose-event", G_CALLBACK(gtkCanvasExposeEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkCanvasButtonEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkCanvasButtonEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "motion-notify-event",G_CALLBACK(iupgtkMotionNotifyEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "scroll-event",G_CALLBACK(gtkCanvasScrollEvent), ih); + +#if GTK_CHECK_VERSION(2, 8, 0) + g_signal_connect(G_OBJECT(gtk_scrolled_window_get_hscrollbar(scrolled_window)), "change-value",G_CALLBACK(gtkCanvasHChangeValue), ih); + g_signal_connect(G_OBJECT(gtk_scrolled_window_get_vscrollbar(scrolled_window)), "change-value",G_CALLBACK(gtkCanvasVChangeValue), ih); +#endif + + /* To receive mouse events on a drawing area, you will need to enable them. */ + gtk_widget_add_events(ih->handle, GDK_EXPOSURE_MASK| + GDK_POINTER_MOTION_MASK|GDK_BUTTON_MOTION_MASK| + GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK| + GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK| + GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK| + GDK_FOCUS_CHANGE_MASK|GDK_STRUCTURE_MASK); + + /* To receive keyboard events, you will need to set the GTK_CAN_FOCUS flag on the drawing area. */ + if (ih->iclass->is_interactive) + { + if (iupAttribGetBoolean(ih, "CANFOCUS")) + GTK_WIDGET_FLAGS(ih->handle) |= GTK_CAN_FOCUS; + } + + if (iupAttribGetBoolean(ih, "BORDER")) + gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_IN); + else + gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_NONE); + + gtk_widget_realize((GtkWidget*)scrolled_window); + gtk_widget_realize(ih->handle); + + /* must be connected after realize or a RESIZE_CB will happen before MAP_CB + works only for the GtkDrawingArea. */ + g_signal_connect(G_OBJECT(ih->handle), "configure-event", G_CALLBACK(gtkCanvasConfigureEvent), ih); + + /* configure for DRAG&DROP */ + if (IupGetCallback(ih, "DROPFILES_CB")) + iupAttribSetStr(ih, "DRAGDROP", "YES"); + + /* update a mnemonic in a label if necessary */ + iupgtkUpdateMnemonic(ih); + + /* configure scrollbar */ + if (ih->data->sb) + { + GtkPolicyType hscrollbar_policy = GTK_POLICY_NEVER, vscrollbar_policy = GTK_POLICY_NEVER; + if (ih->data->sb & IUP_SB_HORIZ) + hscrollbar_policy = GTK_POLICY_AUTOMATIC; + if (ih->data->sb & IUP_SB_VERT) + vscrollbar_policy = GTK_POLICY_AUTOMATIC; + gtk_scrolled_window_set_policy(scrolled_window, hscrollbar_policy, vscrollbar_policy); + } + else + gtk_scrolled_window_set_policy(scrolled_window, GTK_POLICY_NEVER, GTK_POLICY_NEVER); + + /* force the update of BGCOLOR here, to let derived classes ignore it if ACTION is defined */ + gtkCanvasSetBgColorAttrib(ih, iupAttribGetStr(ih, "BGCOLOR")); + + return IUP_NOERROR; +} + +void iupdrvCanvasInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkCanvasMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkCanvasSetBgColorAttrib, "255 255 255", NULL, IUPAF_DEFAULT); /* force new default value */ + + /* IupCanvas only */ + iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CURSOR", NULL, iupdrvBaseSetCursorAttrib, IUPAF_SAMEASSYSTEM, "ARROW", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DRAWSIZE", iupdrvBaseGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "DX", NULL, gtkCanvasSetDXAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "DY", NULL, gtkCanvasSetDYAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "POSX", iupCanvasGetPosXAttrib, gtkCanvasSetPosXAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "POSY", iupCanvasGetPosYAttrib, gtkCanvasSetPosYAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "XAUTOHIDE", NULL, gtkCanvasSetXAutoHideAttrib, "YES", NULL, IUPAF_DEFAULT); /* force new default value */ + iupClassRegisterAttribute(ic, "YAUTOHIDE", NULL, gtkCanvasSetYAutoHideAttrib, "YES", NULL, IUPAF_DEFAULT); /* force new default value */ + + iupClassRegisterAttribute(ic, "DRAWABLE", gtkCanvasGetDrawableAttrib, NULL, NULL, NULL, IUPAF_NO_STRING); + //iupClassRegisterAttribute(ic, "CD_GDK", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + + /* IupCanvas Windows or X only */ +#ifdef WIN32 + iupClassRegisterAttribute(ic, "HWND", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT); +#else + iupClassRegisterAttribute(ic, "XWINDOW", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "XDISPLAY", (IattribGetFunc)iupdrvGetDisplay, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); +#endif +} + diff --git a/iup/src/gtk/iupgtk_clipboard.c b/iup/src/gtk/iupgtk_clipboard.c new file mode 100755 index 0000000..f07a3e6 --- /dev/null +++ b/iup/src/gtk/iupgtk_clipboard.c @@ -0,0 +1,125 @@ +/** \file + * \brief Clipboard for the GTK Driver. + * + * See Copyright Notice in "iup.h" + */ + + +#include <stdio.h> +#include <stdlib.h> + +#include <gtk/gtk.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_image.h" + +#include "iupgtk_drv.h" + + +static int gtkClipboardSetTextAttrib(Ihandle *ih, const char *value) +{ + GtkClipboard *clipboard = gtk_clipboard_get_for_display(gdk_display_get_default(), gdk_atom_intern("CLIPBOARD", FALSE)); + gtk_clipboard_set_text(clipboard, value, -1); + (void)ih; + return 0; +} + +static char* gtkClipboardGetTextAttrib(Ihandle *ih) +{ + GtkClipboard *clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)); + (void)ih; + return iupgtkStrConvertFromUTF8(gtk_clipboard_wait_for_text(clipboard)); +} + +static int gtkClipboardSetImageAttrib(Ihandle *ih, const char *value) +{ +#if GTK_CHECK_VERSION(2, 6, 0) + GtkClipboard *clipboard = gtk_clipboard_get (gdk_atom_intern("CLIPBOARD", FALSE)); + GdkPixbuf *pixbuf = (GdkPixbuf*)iupImageGetImage(value, ih, 0); + if (pixbuf) + gtk_clipboard_set_image (clipboard, pixbuf); +#endif + return 0; +} + +static int gtkClipboardSetNativeImageAttrib(Ihandle *ih, const char *value) +{ +#if GTK_CHECK_VERSION(2, 6, 0) + GtkClipboard *clipboard; + (void)ih; + + if (!value) + return 0; + + clipboard = gtk_clipboard_get (gdk_atom_intern("CLIPBOARD", FALSE)); + + gtk_clipboard_set_image (clipboard, (GdkPixbuf*)value); +#endif + return 0; +} + +static char* gtkClipboardGetNativeImageAttrib(Ihandle *ih) +{ +#if GTK_CHECK_VERSION(2, 6, 0) + GtkClipboard *clipboard = gtk_clipboard_get (gdk_atom_intern("CLIPBOARD", FALSE)); + (void)ih; + return (char*)gtk_clipboard_wait_for_image (clipboard); +#else + return NULL; +#endif +} + +static char* gtkClipboardGetTextAvailableAttrib(Ihandle *ih) +{ + GtkClipboard *clipboard = gtk_clipboard_get (gdk_atom_intern("CLIPBOARD", FALSE)); + (void)ih; + if (gtk_clipboard_wait_is_text_available(clipboard)) + return "YES"; + else + return "NO"; +} + +static char* gtkClipboardGetImageAvailableAttrib(Ihandle *ih) +{ +#if GTK_CHECK_VERSION(2, 6, 0) + GtkClipboard *clipboard = gtk_clipboard_get (gdk_atom_intern("CLIPBOARD", FALSE)); + (void)ih; + if (gtk_clipboard_wait_is_image_available(clipboard)) + return "YES"; + else + return "NO"; +#else + return NULL; +#endif +} + +/******************************************************************************/ + +Ihandle* IupClipboard(void) +{ + return IupCreate("clipboard"); +} + +Iclass* iupClipboardGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "clipboard"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPECONTROL; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 0; + + /* Attribute functions */ + iupClassRegisterAttribute(ic, "TEXT", gtkClipboardGetTextAttrib, gtkClipboardSetTextAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NATIVEIMAGE", gtkClipboardGetNativeImageAttrib, gtkClipboardSetNativeImageAttrib, NULL, NULL, IUPAF_NO_STRING|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkClipboardSetImageAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TEXTAVAILABLE", gtkClipboardGetTextAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGEAVAILABLE", gtkClipboardGetImageAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} diff --git a/iup/src/gtk/iupgtk_colordlg.c b/iup/src/gtk/iupgtk_colordlg.c new file mode 100755 index 0000000..9177f91 --- /dev/null +++ b/iup/src/gtk/iupgtk_colordlg.c @@ -0,0 +1,211 @@ +/** \file + * \brief IupColorDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> + +#include <string.h> +#include <memory.h> +#include <stdio.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_dialog.h" + +#include "iupgtk_drv.h" + + +static char* gtkColorDlgPaletteToString(const char* palette) +{ + char iup_str[20], *gtk_str, *palette_p; + char* str = iupStrGetMemory(300); + int off = 0, inc; + GdkColor color; + + gtk_str = iupStrDup(palette); + iupStrReplace(gtk_str, ':', 0); + + while (palette && *palette) + { + if (!gdk_color_parse (gtk_str, &color)) + return NULL; + + inc = sprintf(iup_str, "%d %d %d;", (int)iupCOLOR16TO8(color.red), (int)iupCOLOR16TO8(color.green), (int)iupCOLOR16TO8(color.blue)); + memcpy(str+off, iup_str, inc); + off += inc; + palette_p = strchr(palette, ':'); + if (palette_p) + { + palette_p++; + gtk_str += palette_p-palette; + } + palette = palette_p; + } + str[off-1] = 0; /* remove last separator */ + return str; +} + +static void gtkColorDlgGetPalette(Ihandle* ih, GtkColorSelection* colorsel) +{ + char *palette, *str; + + GtkSettings *settings = gtk_widget_get_settings(GTK_WIDGET(colorsel)); + g_object_get(settings, "gtk-color-palette", &palette, NULL); + + str = gtkColorDlgPaletteToString(palette); + if (str) iupAttribStoreStr(ih, "COLORTABLE", str); + g_free(palette); +} + +static char* gtkColorDlgStringToPalette(const char* str) +{ + char gtk_str[20]; + char* palette = iupStrGetMemory(200); + int off = 0; + unsigned char r, g, b; + + while (str && *str) + { + if (!iupStrToRGB(str, &r, &g, &b)) + return NULL; + + sprintf(gtk_str, "#%02X%02X%02X:", (int)r, (int)g, (int)b); + memcpy(palette+off, gtk_str, 8); + off += 8; + str = strchr(str, ';'); + if (str) str++; + } + palette[off-1] = 0; /* remove last separator */ + return palette; +} + +static void gtkColorDlgSetPalette(GtkColorSelection* colorsel, char* str) +{ + GtkSettings *settings = gtk_widget_get_settings(GTK_WIDGET(colorsel)); + gchar* palette = gtkColorDlgStringToPalette(str); + if (palette) + gtk_settings_set_string_property(settings, + "gtk-color-palette", + palette, + "gtk_color_selection_palette_to_string"); +} + +static int gtkColorDlgPopup(Ihandle* ih, int x, int y) +{ + InativeHandle* parent = iupDialogGetNativeParent(ih); + GtkColorSelectionDialog* dialog; + GtkColorSelection* colorsel; + GdkColor color; + char *value; + unsigned char r = 0, g = 0, b = 0, a = 255; + int response, ret; + + iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */ + iupAttribSetInt(ih, "_IUPDLG_Y", y); + + dialog = (GtkColorSelectionDialog*)gtk_color_selection_dialog_new(iupgtkStrConvertToUTF8(iupAttribGet(ih, "TITLE"))); + if (!dialog) + return IUP_ERROR; + + if (parent) + gtk_window_set_transient_for((GtkWindow*)dialog, (GtkWindow*)parent); + + ret = iupStrToRGBA(iupAttribGet(ih, "VALUE"), &r, &g, &b, &a); + + colorsel = (GtkColorSelection*)dialog->colorsel; + iupgdkColorSet(&color, r, g, b); + gtk_color_selection_set_current_color(colorsel, &color); + + value = iupAttribGetStr(ih, "ALPHA"); + if (value) + { + int alpha; + if (iupStrToInt(value, &alpha)) + { + if (alpha<0) alpha=0; + if (alpha>255) alpha=255; + gtk_color_selection_set_has_opacity_control(colorsel, TRUE); + gtk_color_selection_set_current_alpha(colorsel, iupCOLOR8TO16(alpha)); + } + } + else if (iupAttribGetBoolean(ih, "SHOWALPHA") || ret == 4) + { + gtk_color_selection_set_has_opacity_control(colorsel, TRUE); + gtk_color_selection_set_current_alpha(colorsel, iupCOLOR8TO16(a)); + } + else + gtk_color_selection_set_has_opacity_control(colorsel, FALSE); + + value = iupAttribGetStr(ih, "COLORTABLE"); + if (value) + { + gtk_color_selection_set_has_palette (colorsel, TRUE); + gtkColorDlgSetPalette(colorsel, value); + } + else if (iupAttribGetBoolean(ih, "SHOWCOLORTABLE")) + gtk_color_selection_set_has_palette (colorsel, TRUE); + else + gtk_color_selection_set_has_palette (colorsel, FALSE); + + if (IupGetCallback(ih, "HELP_CB")) + gtk_widget_show(dialog->help_button); + + /* initialize the widget */ + gtk_widget_realize(GTK_WIDGET(dialog)); + + ih->handle = GTK_WIDGET(dialog); + iupDialogUpdatePosition(ih); + ih->handle = NULL; + + do + { + response = gtk_dialog_run(GTK_DIALOG(dialog)); + + if (response == GTK_RESPONSE_HELP) + { + Icallback cb = IupGetCallback(ih, "HELP_CB"); + if (cb && cb(ih) == IUP_CLOSE) + response = GTK_RESPONSE_CANCEL; + } + } while (response == GTK_RESPONSE_HELP); + + if (response == GTK_RESPONSE_OK) + { + GdkColor color; + gtk_color_selection_get_current_color(colorsel, &color); + IupSetAttribute(ih, "STATUS", "1"); + + if (gtk_color_selection_get_has_opacity_control(colorsel)) + { + int alpha = gtk_color_selection_get_current_alpha(colorsel); + iupAttribSetInt(ih, "ALPHA", (int)iupCOLOR16TO8(alpha)); + iupAttribSetStrf(ih, "VALUE", "%d %d %d %d", (int)iupCOLOR16TO8(color.red), (int)iupCOLOR16TO8(color.green), (int)iupCOLOR16TO8(color.blue), (int)iupCOLOR16TO8(alpha)); + } + else + iupAttribSetStrf(ih, "VALUE", "%d %d %d", (int)iupCOLOR16TO8(color.red), (int)iupCOLOR16TO8(color.green), (int)iupCOLOR16TO8(color.blue)); + + if (gtk_color_selection_get_has_palette(colorsel)) + gtkColorDlgGetPalette(ih, colorsel); + } + else + { + iupAttribSetStr(ih, "ALPHA", NULL); + iupAttribSetStr(ih, "VALUE", NULL); + iupAttribSetStr(ih, "COLORTABLE", NULL); + iupAttribSetStr(ih, "STATUS", NULL); + } + + gtk_widget_destroy(GTK_WIDGET(dialog)); + + return IUP_NOERROR; +} + +void iupdrvColorDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = gtkColorDlgPopup; +} diff --git a/iup/src/gtk/iupgtk_common.c b/iup/src/gtk/iupgtk_common.c new file mode 100755 index 0000000..40368f2 --- /dev/null +++ b/iup/src/gtk/iupgtk_common.c @@ -0,0 +1,830 @@ +/** \file + * \brief GTK Base Functions + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#include <gtk/gtk.h> + +#include "iup.h" +#include "iupcbs.h" +#include "iupkey.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_key.h" +#include "iup_str.h" +#include "iup_class.h" +#include "iup_attrib.h" +#include "iup_focus.h" +#include "iup_key.h" +#include "iup_image.h" +#include "iup_drv.h" + +#include "iupgtk_drv.h" + + +/* WARNING: in GTK there are many controls that are not native windows, + so "->window" will NOT return a native window exclusive of that control, + in fact it can return a base native window shared by many controls. + IupCanvas is a special case that uses an exclusive native window. */ + +/* GTK only has abssolute positioning using a GtkFixed container, + so all elements returned by iupChildTreeGetNativeParentHandle should be a GtkFixed. + If not looks in the native parent. */ +static GtkFixed* gtkGetFixedParent(Ihandle* ih) +{ + GtkWidget* widget = iupChildTreeGetNativeParentHandle(ih); + while (widget && !GTK_IS_FIXED(widget)) + widget = gtk_widget_get_parent(widget); + return (GtkFixed*)widget; +} + +void iupgtkUpdateMnemonic(Ihandle* ih) +{ + GtkLabel* label = (GtkLabel*)iupAttribGet(ih, "_IUPGTK_LABELMNEMONIC"); + if (label) gtk_label_set_mnemonic_widget(label, ih->handle); +} + +void iupdrvActivate(Ihandle* ih) +{ + gtk_widget_activate(ih->handle); +} + +void iupdrvReparent(Ihandle* ih) +{ + GtkFixed* fixed = gtkGetFixedParent(ih); + GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + gtk_widget_reparent(widget, (GtkWidget*)fixed); +} + +void iupgtkBaseAddToParent(Ihandle* ih) +{ + GtkFixed* fixed = gtkGetFixedParent(ih); + GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + + gtk_fixed_put(fixed, widget, 0, 0); +} + +void iupdrvBaseLayoutUpdateMethod(Ihandle *ih) +{ + GtkFixed* fixed = gtkGetFixedParent(ih); + GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + + gtk_fixed_move(fixed, widget, ih->x, ih->y); + gtk_widget_set_size_request(widget, ih->currentwidth, ih->currentheight); +} + +void iupdrvBaseUnMapMethod(Ihandle* ih) +{ + GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + gtk_widget_unrealize(widget); + gtk_widget_destroy(widget); /* To match the call to gtk_*****_new */ +} + +void iupdrvDisplayUpdate(Ihandle *ih) +{ + /* Post a REDRAW */ + gtk_widget_queue_draw(ih->handle); +} + +void iupdrvDisplayRedraw(Ihandle *ih) +{ + GdkWindow* window = ih->handle->window; + /* Post a REDRAW */ + gtk_widget_queue_draw(ih->handle); + /* Force a REDRAW */ + if (window) + gdk_window_process_updates(window, FALSE); +} + +void iupdrvScreenToClient(Ihandle* ih, int *x, int *y) +{ + gint win_x = 0, win_y = 0; + GdkWindow* window = ih->handle->window; + if (window) + gdk_window_get_origin(window, &win_x, &win_y); + *x = *x - win_x; + *y = *y - win_y; +} + +gboolean iupgtkShowHelp(GtkWidget *widget, GtkWidgetHelpType *arg1, Ihandle *ih) +{ + Icallback cb; + (void)widget; + (void)arg1; + + cb = IupGetCallback(ih, "HELP_CB"); + if (cb && cb(ih) == IUP_CLOSE) + IupExitLoop(); + + return FALSE; +} + +gboolean iupgtkEnterLeaveEvent(GtkWidget *widget, GdkEventCrossing *evt, Ihandle *ih) +{ + Icallback cb = NULL; + (void)widget; + + if (evt->type == GDK_ENTER_NOTIFY) + cb = IupGetCallback(ih, "ENTERWINDOW_CB"); + else if (evt->type == GDK_LEAVE_NOTIFY) + cb = IupGetCallback(ih, "LEAVEWINDOW_CB"); + + if (cb) + cb(ih); + + return FALSE; +} + +int iupgtkSetMnemonicTitle(Ihandle* ih, GtkLabel* label, const char* value) +{ + char c = '_'; + char* str; + + if (!value) + value = ""; + + str = iupStrProcessMnemonic(value, &c, 1); /* replace & by c, the returned value of c is ignored in GTK */ + if (str != value) + { + gtk_label_set_text_with_mnemonic(label, iupgtkStrConvertToUTF8(str)); + free(str); + return 1; + } + else + { + if (iupAttribGetBoolean(ih, "MARKUP")) + gtk_label_set_markup(label, iupgtkStrConvertToUTF8(str)); + else + gtk_label_set_text(label, iupgtkStrConvertToUTF8(str)); + } + return 0; +} + +int iupdrvBaseSetZorderAttrib(Ihandle* ih, const char* value) +{ + if (iupdrvIsVisible(ih)) + { + GdkWindow* window = ih->handle->window; + if (iupStrEqualNoCase(value, "TOP")) + gdk_window_raise(window); + else + gdk_window_lower(window); + } + + return 0; +} + +void iupdrvSetVisible(Ihandle* ih, int visible) +{ + GtkWidget* container = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (visible) + { + if (container) gtk_widget_show(container); + gtk_widget_show(ih->handle); + } + else + { + if (container) gtk_widget_hide(container); + gtk_widget_hide(ih->handle); + } +} + +int iupdrvIsVisible(Ihandle* ih) +{ + if (GTK_WIDGET_VISIBLE(ih->handle)) + { + /* if marked as visible, since we use gtk_widget_hide and NOT gtk_widget_hide_all + must check its parents. */ + Ihandle* parent = ih->parent; + while (parent) + { + if (parent->iclass->nativetype != IUP_TYPEVOID) + { + if (!GTK_WIDGET_VISIBLE(parent->handle)) + return 0; + } + + parent = parent->parent; + } + return 1; + } + else + return 0; +} + +int iupdrvIsActive(Ihandle *ih) +{ + return (GTK_WIDGET_IS_SENSITIVE(ih->handle)); +} + +void iupdrvSetActive(Ihandle* ih, int enable) +{ + GtkWidget* container = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (container) gtk_widget_set_sensitive(container, enable); + gtk_widget_set_sensitive(ih->handle, enable); +} + +char* iupdrvBaseGetXAttrib(Ihandle *ih) +{ + GdkWindow* window = ih->handle->window; + GtkWidget* container = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (container) window = container->window; + + if (window) + { + char* str = iupStrGetMemory(20); + int x, y; + gdk_window_get_origin(window, &x, &y); + x += ih->handle->allocation.x; + sprintf(str, "%d", x); + return str; + } + else + return NULL; +} + +char* iupdrvBaseGetYAttrib(Ihandle *ih) +{ + GdkWindow* window = ih->handle->window; + GtkWidget* container = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (container) window = container->window; + + if (window) + { + char* str = iupStrGetMemory(20); + int x, y; + gdk_window_get_origin(window, &x, &y); + y += ih->handle->allocation.y; + sprintf(str, "%d", y); + return str; + } + else + return NULL; +} + +char* iupdrvBaseGetClientSizeAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(20); + int w, h; + GdkWindow* window = ih->handle->window; + + if (window) + gdk_drawable_get_size(window, &w, &h); + else + return NULL; + + sprintf(str, "%dx%d", w, h); + return str; +} + +static GdkColor gtkDarkerColor(GdkColor *color) +{ + GdkColor dark_color = {0L,0,0,0}; + + dark_color.red = (color->red*9)/10; + dark_color.green = (color->green*9)/10; + dark_color.blue = (color->blue*9)/10; + + return dark_color; +} + +static guint16 gtkCROP16(int x) +{ + if (x > 65535) return 65535; + return (guint16)x; +} + +static GdkColor gtkLighterColor(GdkColor *color) +{ + GdkColor light_color = {0L,0,0,0}; + + light_color.red = gtkCROP16(((int)color->red*11)/10); + light_color.green = gtkCROP16(((int)color->green*11)/10); + light_color.blue = gtkCROP16(((int)color->blue*11)/10); + + return light_color; +} + +void iupgtkBaseSetBgColor(InativeHandle* handle, unsigned char r, unsigned char g, unsigned char b) +{ + GtkRcStyle *rc_style; + GdkColor color; + + iupgdkColorSet(&color, r, g, b); + + rc_style = gtk_widget_get_modifier_style(handle); + rc_style->base[GTK_STATE_NORMAL] = rc_style->bg[GTK_STATE_NORMAL] = rc_style->bg[GTK_STATE_INSENSITIVE] = color; + rc_style->bg[GTK_STATE_ACTIVE] = rc_style->base[GTK_STATE_ACTIVE] = gtkDarkerColor(&color); + rc_style->base[GTK_STATE_PRELIGHT] = rc_style->bg[GTK_STATE_PRELIGHT] = rc_style->base[GTK_STATE_INSENSITIVE] = gtkLighterColor(&color); + + rc_style->color_flags[GTK_STATE_NORMAL] |= GTK_RC_BASE | GTK_RC_BG; + rc_style->color_flags[GTK_STATE_ACTIVE] |= GTK_RC_BASE | GTK_RC_BG; + rc_style->color_flags[GTK_STATE_PRELIGHT] |= GTK_RC_BASE | GTK_RC_BG; + rc_style->color_flags[GTK_STATE_INSENSITIVE] |= GTK_RC_BASE | GTK_RC_BG; + + gtk_widget_modify_style(handle, rc_style); +} + +int iupdrvBaseSetBgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + iupgtkBaseSetBgColor(ih->handle, r, g, b); + + /* DO NOT NEED TO UPDATE GTK IMAGES SINCE THEY DO NOT DEPEND ON BGCOLOR */ + + return 1; +} + +void iupgtkBaseSetFgGdkColor(InativeHandle* handle, GdkColor *color) +{ + GtkRcStyle *rc_style; + + rc_style = gtk_widget_get_modifier_style(handle); + rc_style->fg[GTK_STATE_ACTIVE] = rc_style->fg[GTK_STATE_NORMAL] = rc_style->fg[GTK_STATE_PRELIGHT] = *color; + rc_style->text[GTK_STATE_ACTIVE] = rc_style->text[GTK_STATE_NORMAL] = rc_style->text[GTK_STATE_PRELIGHT] = *color; + rc_style->color_flags[GTK_STATE_NORMAL] |= GTK_RC_TEXT | GTK_RC_FG; + rc_style->color_flags[GTK_STATE_ACTIVE] |= GTK_RC_TEXT | GTK_RC_FG; + rc_style->color_flags[GTK_STATE_PRELIGHT] |= GTK_RC_TEXT | GTK_RC_FG; + + /* do not set at CHILD_CONTAINER */ + gtk_widget_modify_style(handle, rc_style); +} + +void iupgtkBaseSetFgColor(InativeHandle* handle, unsigned char r, unsigned char g, unsigned char b) +{ + GdkColor color; + iupgdkColorSet(&color, r, g, b); + iupgtkBaseSetFgGdkColor(handle, &color); +} + +int iupdrvBaseSetFgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + iupgtkBaseSetFgColor(ih->handle, r, g, b); + + return 1; +} + +static GdkCursor* gtkEmptyCursor(Ihandle* ih) +{ + /* creates an empty cursor */ + GdkColor cursor_color = {0L,0,0,0}; + char bitsnull[1] = {0x00}; + + GdkWindow* window = ih->handle->window; + GdkPixmap* pixmapnull = gdk_bitmap_create_from_data( + (GdkDrawable*)window, + bitsnull, + 1,1); + GdkCursor* cur = gdk_cursor_new_from_pixmap( + pixmapnull, + pixmapnull, + &cursor_color, + &cursor_color, + 0,0); + + g_object_unref(pixmapnull); + + return cur; +} + +static GdkCursor* gtkGetCursor(Ihandle* ih, const char* name) +{ + static struct { + const char* iupname; + int sysname; + } table[] = { + { "NONE", 0}, + { "NULL", 0}, + { "ARROW", GDK_LEFT_PTR}, + { "BUSY", GDK_WATCH}, + { "CROSS", GDK_CROSSHAIR}, + { "HAND", GDK_HAND2}, + { "HELP", GDK_QUESTION_ARROW}, + { "IUP", GDK_QUESTION_ARROW}, + { "MOVE", GDK_FLEUR}, + { "PEN", GDK_PENCIL}, + { "RESIZE_N", GDK_TOP_SIDE}, + { "RESIZE_S", GDK_BOTTOM_SIDE}, + { "RESIZE_NS", GDK_SB_V_DOUBLE_ARROW}, + { "RESIZE_W", GDK_LEFT_SIDE}, + { "RESIZE_E", GDK_RIGHT_SIDE}, + { "RESIZE_WE", GDK_SB_H_DOUBLE_ARROW}, + { "RESIZE_NE", GDK_TOP_RIGHT_CORNER}, + { "RESIZE_SE", GDK_BOTTOM_RIGHT_CORNER}, + { "RESIZE_NW", GDK_TOP_LEFT_CORNER}, + { "RESIZE_SW", GDK_BOTTOM_LEFT_CORNER}, + { "TEXT", GDK_XTERM}, + { "UPARROW", GDK_CENTER_PTR} + }; + + GdkCursor* cur; + char str[50]; + int i, count = sizeof(table)/sizeof(table[0]); + + /* check the cursor cache first (per control)*/ + sprintf(str, "_IUPGTK_CURSOR_%s", name); + cur = (GdkCursor*)iupAttribGet(ih, str); + if (cur) + return cur; + + /* check the pre-defined IUP names first */ + for (i = 0; i < count; i++) + { + if (iupStrEqualNoCase(name, table[i].iupname)) + { + if (table[i].sysname) + cur = gdk_cursor_new(table[i].sysname); + else + cur = gtkEmptyCursor(ih); + + break; + } + } + + if (i == count) + { + /* check for a name defined cursor */ + cur = iupImageGetCursor(name); + } + + /* save the cursor in cache */ + iupAttribSetStr(ih, str, (char*)cur); + + return cur; +} + +int iupdrvBaseSetCursorAttrib(Ihandle* ih, const char* value) +{ + GdkCursor* cur = gtkGetCursor(ih, value); + if (cur) + { + GdkWindow* window = ih->handle->window; + if (window) + gdk_window_set_cursor(window, cur); + return 1; + } + return 0; +} + +void iupgdkColorSet(GdkColor* color, unsigned char r, unsigned char g, unsigned char b) +{ + color->red = iupCOLOR8TO16(r); + color->green = iupCOLOR8TO16(g); + color->blue = iupCOLOR8TO16(b); + color->pixel = 0; +} + +static void gtkDragDataReceived(GtkWidget* w, GdkDragContext* context, int x, int y, + GtkSelectionData* seldata, guint info, guint time, Ihandle* ih) +{ + gchar **uris = NULL; + int i, count; + + IFnsiii cb = (IFnsiii)IupGetCallback(ih, "DROPFILES_CB"); + if (!cb) return; + +#if GTK_CHECK_VERSION(2, 6, 0) + uris = g_uri_list_extract_uris((char*)seldata->data); +#endif + + if (!uris) + return; + + count = 0; + while (uris[count]) + count++; + + for (i=0; i<count; i++) + { + char* filename = uris[i]; + if (iupStrEqualPartial(filename, "file://")) + { + filename += strlen("file://"); + if (filename[2] == ':') /* in Windows there is an extra '/' at the begining. */ + filename++; + } + if (cb(ih, filename, count-i-1, x, y) == IUP_IGNORE) + break; + } + + g_strfreev (uris); + (void)time; + (void)info; + (void)w; + (void)context; +} + +int iupgtkSetDragDropAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + { + GtkTargetEntry dragtypes[] = { { "text/uri-list", 0, 0 } }; + gtk_drag_dest_set(ih->handle, GTK_DEST_DEFAULT_ALL, dragtypes, + sizeof(dragtypes) / sizeof(dragtypes[0]), GDK_ACTION_COPY); + g_signal_connect(G_OBJECT(ih->handle), "drag_data_received", G_CALLBACK(gtkDragDataReceived), ih); + } + else + { + gtk_drag_dest_unset(ih->handle); + } + return 1; +} + +int iupdrvGetScrollbarSize(void) +{ + static int size = 0; + + if (size == 0) + { + GtkRequisition requisition; + GtkWidget* win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + GtkWidget* sb = gtk_vscrollbar_new(NULL); + gtk_container_add((GtkContainer*)win, sb); + gtk_widget_realize(win); + gtk_widget_size_request(sb, &requisition); + size = requisition.width; + gtk_widget_destroy(win); + } + + return size; +} + +void iupdrvDrawFocusRect(Ihandle* ih, void* _gc, int x, int y, int w, int h) +{ + GdkWindow* window = ih->handle->window; + GtkStyle *style = gtk_widget_get_style(ih->handle); + (void)_gc; + + gtk_paint_focus(style, window, GTK_WIDGET_STATE(ih->handle), NULL, ih->handle, NULL, x, y, w, h); +} + +void iupdrvBaseRegisterCommonAttrib(Iclass* ic) +{ +#ifdef WIN32 + iupClassRegisterAttribute(ic, "HFONT", iupgtkGetFontIdAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); +#else + iupClassRegisterAttribute(ic, "XFONTID", iupgtkGetFontIdAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); +#endif + iupClassRegisterAttribute(ic, "PANGOFONTDESC", iupgtkGetPangoFontDescAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); +} + +static int gtkStrIsAscii(const char* str) +{ + while(*str) + { + int c = *str; + if (c < 0) + return 0; + str++; + } + return 1; +} + +static char* gtkStrToUTF8(const char *str, const char* charset) +{ + return g_convert(str, -1, "UTF-8", charset, NULL, NULL, NULL); +} + +static char* gtkStrFromUTF8(const char *str, const char* charset) +{ + return g_convert(str, -1, charset, "UTF-8", NULL, NULL, NULL); +} + +static char* gktLastConvertUTF8 = NULL; + +void iupgtkReleaseConvertUTF8(void) +{ + if (gktLastConvertUTF8) + g_free(gktLastConvertUTF8); +} + +char* iupgtkStrConvertToUTF8(const char* str) /* From IUP to GTK */ +{ + if (!str || *str == 0) + return (char*)str; + + if (iupgtk_utf8autoconvert) /* this means str is in current locale */ + { + const char *charset = NULL; + if (g_get_charset(&charset)==TRUE) /* current locale is already UTF-8 */ + { + if (g_utf8_validate(str, -1, NULL)) + return (char*)str; + else + { + if (gktLastConvertUTF8) + g_free(gktLastConvertUTF8); + gktLastConvertUTF8 = gtkStrToUTF8(str, "ISO8859-1"); /* if string is not UTF-8, assume ISO8859-1 */ + if (!gktLastConvertUTF8) return (char*)str; + return gktLastConvertUTF8; + } + } + else + { + if (gtkStrIsAscii(str) || !charset) + return (char*)str; + else if (charset) + { + if (gktLastConvertUTF8) + g_free(gktLastConvertUTF8); + gktLastConvertUTF8 = gtkStrToUTF8(str, charset); + if (!gktLastConvertUTF8) return (char*)str; + return gktLastConvertUTF8; + } + } + } + return (char*)str; +} + +char* iupgtkStrConvertFromUTF8(const char* str) /* From GTK to IUP */ +{ + if (!str || *str == 0) + return (char*)str; + + if (iupgtk_utf8autoconvert) /* this means str is in current locale */ + { + const gchar *charset = NULL; + if (g_get_charset(&charset)==TRUE) /* current locale is already UTF-8 */ + { + if (g_utf8_validate(str, -1, NULL)) + return (char*)str; + else + { + if (gktLastConvertUTF8) + g_free(gktLastConvertUTF8); + gktLastConvertUTF8 = gtkStrFromUTF8(str, "ISO8859-1"); /* if string is not UTF-8, assume ISO8859-1 */ + if (!gktLastConvertUTF8) return (char*)str; + return gktLastConvertUTF8; + } + } + else + { + if (gtkStrIsAscii(str) || !charset) + return (char*)str; + else if (charset) + { + if (gktLastConvertUTF8) + g_free(gktLastConvertUTF8); + gktLastConvertUTF8 = gtkStrFromUTF8(str, charset); + if (!gktLastConvertUTF8) return (char*)str; + return gktLastConvertUTF8; + } + } + } + return (char*)str; +} + +static gboolean gtkGetFilenameCharset(const gchar **filename_charset) +{ + const gchar **charsets = NULL; + gboolean is_utf8 = FALSE; + +#if GTK_CHECK_VERSION(2, 6, 0) + is_utf8 = g_get_filename_charsets (&charsets); +#endif + + if (filename_charset && charsets) + *filename_charset = charsets[0]; + + return is_utf8; +} + +char* iupgtkStrConvertToFilename(const char* str) /* From IUP to Filename */ +{ + if (!str || *str == 0) + return (char*)str; + + if (iupgtk_utf8autoconvert) /* this means str is in current locale */ + return (char*)str; + else + { + const gchar *charset = NULL; + if (gtkGetFilenameCharset(&charset)==TRUE) /* current locale is already UTF-8 */ + { + if (g_utf8_validate(str, -1, NULL)) + return (char*)str; + else + { + if (gktLastConvertUTF8) + g_free(gktLastConvertUTF8); + gktLastConvertUTF8 = gtkStrFromUTF8(str, "ISO8859-1"); /* if string is not UTF-8, assume ISO8859-1 */ + if (!gktLastConvertUTF8) return (char*)str; + return gktLastConvertUTF8; + } + } + else + { + if (gtkStrIsAscii(str) || !charset) + return (char*)str; + else if (charset) + { + if (gktLastConvertUTF8) + g_free(gktLastConvertUTF8); + gktLastConvertUTF8 = gtkStrFromUTF8(str, charset); + if (!gktLastConvertUTF8) return (char*)str; + return gktLastConvertUTF8; + } + } + } + return (char*)str; +} + +char* iupgtkStrConvertFromFilename(const char* str) /* From Filename to IUP */ +{ + if (!str || *str == 0) + return (char*)str; + + if (iupgtk_utf8autoconvert) /* this means str is in current locale */ + return (char*)str; + else + { + const char *charset = NULL; + if (gtkGetFilenameCharset(&charset)==TRUE) /* current locale is already UTF-8 */ + { + if (g_utf8_validate(str, -1, NULL)) + return (char*)str; + else + { + if (gktLastConvertUTF8) + g_free(gktLastConvertUTF8); + gktLastConvertUTF8 = gtkStrToUTF8(str, "ISO8859-1"); /* if string is not UTF-8, assume ISO8859-1 */ + if (!gktLastConvertUTF8) return (char*)str; + return gktLastConvertUTF8; + } + } + else + { + if (gtkStrIsAscii(str) || !charset) + return (char*)str; + else if (charset) + { + if (gktLastConvertUTF8) + g_free(gktLastConvertUTF8); + gktLastConvertUTF8 = gtkStrToUTF8(str, charset); + if (!gktLastConvertUTF8) return (char*)str; + return gktLastConvertUTF8; + } + } + } + return (char*)str; +} + +gboolean iupgtkMotionNotifyEvent(GtkWidget *widget, GdkEventMotion *evt, Ihandle *ih) +{ + IFniis cb = (IFniis)IupGetCallback(ih,"MOTION_CB"); + if (cb) + { + char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; + iupgtkButtonKeySetStatus(evt->state, 0, status, 0); + cb(ih, (int)evt->x, (int)evt->y, status); + } + + (void)widget; + return FALSE; +} + +gboolean iupgtkButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih) +{ + IFniiiis cb = (IFniiiis)IupGetCallback(ih,"BUTTON_CB"); + if (cb) + { + int doubleclick = 0, ret, press = 1; + int b = IUP_BUTTON1+(evt->button-1); + char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; + + if (evt->type == GDK_BUTTON_RELEASE) + press = 0; + + if (evt->type == GDK_2BUTTON_PRESS) + doubleclick = 1; + + iupgtkButtonKeySetStatus(evt->state, evt->button, status, doubleclick); + + ret = cb(ih, b, press, (int)evt->x, (int)evt->y, status); + if (ret==IUP_CLOSE) + IupExitLoop(); + else if (ret==IUP_IGNORE) + return TRUE; + } + + (void)widget; + return FALSE; +} diff --git a/iup/src/gtk/iupgtk_dialog.c b/iup/src/gtk/iupgtk_dialog.c new file mode 100755 index 0000000..46c0ce1 --- /dev/null +++ b/iup/src/gtk/iupgtk_dialog.c @@ -0,0 +1,1023 @@ +/** \file + * \brief IupDialog class + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> + +#ifdef HILDON +#include <hildon/hildon-program.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> +#include <time.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_class.h" +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_dlglist.h" +#include "iup_attrib.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_drvinfo.h" +#include "iup_focus.h" +#include "iup_str.h" +#define _IUPDLG_PRIVATE +#include "iup_dialog.h" +#include "iup_image.h" + +#include "iupgtk_drv.h" + + +static void gtkDialogSetMinMax(Ihandle* ih, int min_w, int min_h, int max_w, int max_h); + +/**************************************************************** + Utilities +****************************************************************/ + +int iupdrvDialogIsVisible(Ihandle* ih) +{ + return iupdrvIsVisible(ih); +} + +void iupdrvDialogUpdateSize(Ihandle* ih) +{ + int width, height; + gtk_window_get_size((GtkWindow*)ih->handle, &width, &height); + ih->currentwidth = width; + ih->currentheight = height; +} + +void iupdrvDialogGetSize(InativeHandle* handle, int *w, int *h) +{ + int width, height; + gtk_window_get_size((GtkWindow*)handle, &width, &height); + if (w) *w = width; + if (h) *h = height; +} + +void iupdrvDialogSetVisible(Ihandle* ih, int visible) +{ + if (visible) + gtk_widget_show(ih->handle); + else + gtk_widget_hide(ih->handle); +} + +void iupdrvDialogGetPosition(InativeHandle* handle, int *x, int *y) +{ + gtk_window_get_position((GtkWindow*)handle, x, y); +} + +void iupdrvDialogSetPosition(Ihandle *ih, int x, int y) +{ + gtk_window_move((GtkWindow*)ih->handle, x, y); +} + +static int gtkDialogGetMenuSize(Ihandle* ih) +{ +#ifdef HILDON + return 0; +#else + if (ih->data->menu) + return iupdrvMenuGetMenuBarSize(ih->data->menu); + else + return 0; +#endif +} + +static int gtkDialogGetWindowDecor(Ihandle* ih, int *win_border, int *win_caption) +{ + int x, y, frame_x, frame_y; + gdk_window_get_origin(ih->handle->window, &x, &y); + gdk_window_get_root_origin(ih->handle->window, &frame_x, &frame_y); + *win_border = x-frame_x; + *win_caption = y-frame_y-*win_border; + return 1; /* just for compatibility with iupdrvGetWindowDecor */ +} + +void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu) +{ +#ifdef HILDON + /* In Hildon, borders have fixed dimensions, but are drawn as part + of the client area! */ + if (border) + *border = (iupAttribGetBoolean(ih, "HILDONWINDOW") && !iupAttribGetBoolean(ih, "FULLSCREEN")) ? 12 : 0; + if (caption) + *caption = 0; + if (menu) + *menu = 0; +#else + static int native_border = 0; + static int native_caption = 0; + + int has_caption = iupAttribGetBoolean(ih, "MAXBOX") || + iupAttribGetBoolean(ih, "MINBOX") || + iupAttribGetBoolean(ih, "MENUBOX") || + IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ + + int has_border = has_caption || + iupAttribGetBoolean(ih, "RESIZE") || + iupAttribGetBoolean(ih, "BORDER"); + + *menu = gtkDialogGetMenuSize(ih); + + if (ih->handle && iupdrvIsVisible(ih)) + { + int win_border, win_caption; + + if (gtkDialogGetWindowDecor(ih, &win_border, &win_caption)) + { +#ifdef WIN32 + if (*menu) + win_caption -= *menu; +#endif + + *border = 0; + if (has_border) + *border = win_border; + + *caption = 0; + if (has_caption) + *caption = win_caption; + + if (!native_border && *border) + native_border = win_border; + + if (!native_caption && *caption) + native_caption = win_caption; + } + } + + /* I could not set the size of the window including the decorations when the dialog is hidden */ + /* So we have to estimate the size of borders and caption when the dialog is hidden */ + + *border = 0; + if (has_border) + { + if (native_border) + *border = native_border; + else + *border = 5; + } + + *caption = 0; + if (has_caption) + { + if (native_caption) + *caption = native_caption; + else + *caption = 20; + } +#endif +} + +int iupdrvDialogSetPlacement(Ihandle* ih) +{ + char* placement; + int old_state = ih->data->show_state; + ih->data->show_state = IUP_SHOW; + + if (iupAttribGetBoolean(ih, "FULLSCREEN")) + { + gtk_window_fullscreen((GtkWindow*)ih->handle); + return 1; + } + + placement = iupAttribGet(ih, "PLACEMENT"); + if (!placement) + { + if (old_state == IUP_MAXIMIZE || old_state == IUP_MINIMIZE) + ih->data->show_state = IUP_RESTORE; + + gtk_window_unmaximize((GtkWindow*)ih->handle); + gtk_window_deiconify((GtkWindow*)ih->handle); + return 0; + } + + if (iupStrEqualNoCase(placement, "MINIMIZED")) + { + ih->data->show_state = IUP_MINIMIZE; + gtk_window_iconify((GtkWindow*)ih->handle); + } + else if (iupStrEqualNoCase(placement, "MAXIMIZED")) + { + ih->data->show_state = IUP_MAXIMIZE; + gtk_window_maximize((GtkWindow*)ih->handle); + } + else if (iupStrEqualNoCase(placement, "FULL")) + { + int width, height, x, y; + int border, caption, menu; + iupdrvDialogGetDecoration(ih, &border, &caption, &menu); + + /* position the decoration outside the screen */ + x = -(border); + y = -(border+caption+menu); + + /* the dialog client area will cover the task bar */ + iupdrvGetFullSize(&width, &height); + + height += menu; /* menu is inside the client area. */ + + /* set the new size and position */ + /* The resize evt will update the layout */ + gtk_window_move((GtkWindow*)ih->handle, x, y); + gtk_window_resize((GtkWindow*)ih->handle, width, height); + + if (old_state == IUP_MAXIMIZE || old_state == IUP_MINIMIZE) + ih->data->show_state = IUP_RESTORE; + } + + iupAttribSetStr(ih, "PLACEMENT", NULL); /* reset to NORMAL */ + + return 1; +} + + +/**************************************************************** + Callbacks and Events +****************************************************************/ + + +gboolean iupgtkDialogDeleteEvent(GtkWidget *widget, GdkEvent *evt, Ihandle *ih) +{ + Icallback cb; + (void)widget; + (void)evt; + + /* even when ACTIVE=NO the dialog gets this evt */ + if (!iupdrvIsActive(ih)) + return TRUE; + + cb = IupGetCallback(ih, "CLOSE_CB"); + if (cb) + { + int ret = cb(ih); + if (ret == IUP_IGNORE) + return TRUE; + if (ret == IUP_CLOSE) + IupExitLoop(); + } + + IupHide(ih); /* default: close the window */ + + return TRUE; /* do not propagate */ +} + +static gboolean gtkDialogConfigureEvent(GtkWidget *widget, GdkEventConfigure *evt, Ihandle *ih) +{ + int old_width, old_height, old_x, old_y; + gint x, y; + (void)widget; + +#ifndef HILDON + /* In hildon the menu is not a menubar */ + if (ih->data->menu && ih->data->menu->handle) + gtk_widget_set_size_request(ih->data->menu->handle, evt->width, -1); +#endif + + if (ih->data->ignore_resize) return FALSE; + + old_width = iupAttribGetInt(ih, "_IUPGTK_OLD_WIDTH"); + old_height = iupAttribGetInt(ih, "_IUPGTK_OLD_HEIGHT"); + + /* Check the size change, because configure is called also for position changes */ + if (evt->width != old_width || evt->height != old_height) + { + IFnii cb; + int border, caption, menu; + iupAttribSetInt(ih, "_IUPGTK_OLD_WIDTH", evt->width); + iupAttribSetInt(ih, "_IUPGTK_OLD_HEIGHT", evt->height); + + iupdrvDialogGetDecoration(ih, &border, &caption, &menu); + + /* update dialog size */ +#ifdef HILDON + /* In Hildon, the configure event contains the window size, not the client area size */ + ih->currentwidth = evt->width; + ih->currentheight = evt->height; +#else + ih->currentwidth = evt->width + 2*border; + ih->currentheight = evt->height + 2*border + caption; /* menu is inside the window client area */ +#endif + + cb = (IFnii)IupGetCallback(ih, "RESIZE_CB"); + if (!cb || cb(ih, evt->width, evt->height - menu)!=IUP_IGNORE) /* width and height here are for the client area */ + { + ih->data->ignore_resize = 1; + IupRefresh(ih); + ih->data->ignore_resize = 0; + } + } + + old_x = iupAttribGetInt(ih, "_IUPGTK_OLD_X"); + old_y = iupAttribGetInt(ih, "_IUPGTK_OLD_Y"); + gtk_window_get_position((GtkWindow*)ih->handle, &x, &y); /* ignore evt->x and evt->y because they are the clientpos and not X/Y */ + + /* Check the position change, because configure is called also for size changes */ + if (x != old_x || y != old_y) + { + IFnii cb; + iupAttribSetInt(ih, "_IUPGTK_OLD_X", x); + iupAttribSetInt(ih, "_IUPGTK_OLD_Y", y); + + cb = (IFnii)IupGetCallback(ih, "MOVE_CB"); + if (cb) + cb(ih, x, y); + } + + return FALSE; +} + +static gboolean gtkDialogWindowStateEvent(GtkWidget *widget, GdkEventWindowState *evt, Ihandle *ih) +{ + int state = -1; + (void)widget; + + if ((evt->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) && /* if flag changed and */ + (evt->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) && /* is now set */ + !(evt->new_window_state & GDK_WINDOW_STATE_WITHDRAWN)) /* is visible */ + state = IUP_MAXIMIZE; + else if ((evt->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && + (evt->new_window_state & GDK_WINDOW_STATE_ICONIFIED) && + !(evt->new_window_state & GDK_WINDOW_STATE_WITHDRAWN)) + state = IUP_MINIMIZE; + else if ((evt->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && + (evt->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) && + !(evt->new_window_state & GDK_WINDOW_STATE_WITHDRAWN)) + state = IUP_MAXIMIZE; + else if (((evt->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) && /* maximized changed */ + !(evt->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) && /* not maximized */ + !(evt->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) && /* is visible */ + !(evt->new_window_state & GDK_WINDOW_STATE_ICONIFIED)) /* not minimized */ + || /* OR */ + ((evt->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && /* minimized changed */ + !(evt->new_window_state & GDK_WINDOW_STATE_ICONIFIED) && /* not minimized */ + !(evt->new_window_state & GDK_WINDOW_STATE_WITHDRAWN) && /* is visible */ + !(evt->new_window_state & GDK_WINDOW_STATE_MAXIMIZED))) /* not maximized */ + state = IUP_RESTORE; + + if (state < 0) + return FALSE; + + if (ih->data->show_state != state) + { + IFni cb; + ih->data->show_state = state; + + cb = (IFni)IupGetCallback(ih, "SHOW_CB"); + if (cb && cb(ih, state) == IUP_CLOSE) + IupExitLoop(); + } + + return FALSE; +} + +static gboolean gtkDialogChildDestroyEvent(GtkWidget *widget, Ihandle *ih) +{ + /* It seems that the documentation for this callback is not correct */ + /* The second parameter must be the user_data or it will fail. */ + (void)widget; + + /* If the IUP dialog was not destroyed, destroy it here. */ + if (iupObjectCheck(ih)) + IupDestroy(ih); + + /* this callback is usefull to destroy children dialogs when the parent is destroyed. */ + /* The application is responsable for destroying the children before this happen. */ + + return FALSE; +} + + +/**************************************************************** + Idialog Methods +****************************************************************/ + + +/* replace the common dialog SetChildrenPosition method because of + the menu that it is inside the dialog. */ +static void gtkDialogSetChildrenPositionMethod(Ihandle* ih, int x, int y) +{ + int menu_h = gtkDialogGetMenuSize(ih); + (void)x; + (void)y; + + /* Child coordinates are relative to client left-top corner. */ + iupBaseSetPosition(ih->firstchild, 0, menu_h); +} + +static void* gtkDialogGetInnerNativeContainerHandleMethod(Ihandle* ih, Ihandle* child) +{ + (void)child; + return (void*)gtk_bin_get_child((GtkBin*)ih->handle); +} + +static int gtkDialogMapMethod(Ihandle* ih) +{ + int decorations = 0; + int functions = 0; + InativeHandle* parent; + GtkWidget* fixed; + +#ifdef HILDON + if (iupAttribGetBoolean(ih, "HILDONWINDOW")) + { + HildonProgram *program = HILDON_PROGRAM(hildon_program_get_instance()); + ih->handle = hildon_window_new(); + if (ih->handle) + hildon_program_add_window(program, HILDON_WINDOW(ih->handle)); + } + else + { + iupAttribSetStr(ih, "DIALOGHINT", "YES"); /* otherwise not displayed correctly */ + ih->handle = gtk_window_new(GTK_WINDOW_TOPLEVEL); + } +#else + ih->handle = gtk_window_new(GTK_WINDOW_TOPLEVEL); +#endif + if (!ih->handle) + return IUP_ERROR; + + parent = iupDialogGetNativeParent(ih); + if (parent) + { + gtk_window_set_transient_for((GtkWindow*)ih->handle, (GtkWindow*)parent); + + /* manually remove child windows when parent is destroyed */ + g_signal_connect(G_OBJECT(parent), "destroy", G_CALLBACK(gtkDialogChildDestroyEvent), ih); + } + + g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih); + + /* The iupgtkKeyPressEvent of the control with the focus will propagate the key up to the dialog. */ + /* Inside iupgtkKeyPressEvent we test this to avoid duplicate calls. */ + g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih); + + g_signal_connect(G_OBJECT(ih->handle), "configure-event", G_CALLBACK(gtkDialogConfigureEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "window-state-event", G_CALLBACK(gtkDialogWindowStateEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "delete-event", G_CALLBACK(iupgtkDialogDeleteEvent), ih); + + gtk_window_set_default_size((GtkWindow*)ih->handle, 100, 100); /* set this to avoid size calculation problems */ + + if (iupAttribGetBoolean(ih, "DIALOGHINT")) + gtk_window_set_type_hint(GTK_WINDOW(ih->handle), GDK_WINDOW_TYPE_HINT_DIALOG); + + /* the container that will receive the child element. */ + fixed = gtk_fixed_new(); + gtk_container_add((GtkContainer*)ih->handle, fixed); + gtk_widget_show(fixed); + + /* initialize the widget */ + gtk_widget_realize(ih->handle); + + if (iupAttribGetBoolean(ih, "DIALOGFRAME")) { + iupAttribSetStr(ih, "RESIZE", "NO"); + } + + if (!iupAttribGetBoolean(ih, "RESIZE")) { + iupAttribSetStr(ih, "MAXBOX", "NO"); /* Must also remove these, so RESIZE=NO can work */ + iupAttribSetStr(ih, "MINBOX", "NO"); + } + + if (IupGetAttribute(ih, "TITLE")) { /* must use IupGetAttribute to check from the native implementation */ + functions |= GDK_FUNC_MOVE; + decorations |= GDK_DECOR_TITLE; + } + + if (iupAttribGetBoolean(ih, "MENUBOX")) { + functions |= GDK_FUNC_CLOSE; + decorations |= GDK_DECOR_MENU; + } + + if (iupAttribGetBoolean(ih, "MINBOX")) { + functions |= GDK_FUNC_MINIMIZE; + decorations |= GDK_DECOR_MINIMIZE; + } + + if (iupAttribGetBoolean(ih, "MAXBOX")) { + functions |= GDK_FUNC_MAXIMIZE; + decorations |= GDK_DECOR_MAXIMIZE; + } + + if (iupAttribGetBoolean(ih, "RESIZE")) { + functions |= GDK_FUNC_RESIZE; + decorations |= GDK_DECOR_RESIZEH; + } + + if (iupAttribGetBoolean(ih, "BORDER")) + decorations |= GDK_DECOR_BORDER; + + if (decorations == 0) + gtk_window_set_decorated((GtkWindow*)ih->handle, FALSE); + else + { + GdkWindow* window = ih->handle->window; + if (window) + { + gdk_window_set_decorations(window, (GdkWMDecoration)decorations); + gdk_window_set_functions(window, (GdkWMFunction)functions); + } + } + + /* configure for DRAG&DROP */ + if (IupGetCallback(ih, "DROPFILES_CB")) + iupAttribSetStr(ih, "DRAGDROP", "YES"); + + { + /* Reset the DLGBGCOLOR global attribute + if it is the first time a dialog is created. + The value returned by gtk_style_new is not accurate. */ + GtkStyle* style = gtk_widget_get_style(ih->handle); + if (style && IupGetGlobal("_IUP_RESET_GLOBALCOLORS")) + { + iupgtkUpdateGlobalColors(style); + IupSetGlobal("_IUP_RESET_GLOBALCOLORS", NULL); + } + } + + /* configure the size range */ + gtkDialogSetMinMax(ih, 1, 1, 65535, 65535); /* MINSIZE and MAXSIZE default values */ + + /* Ignore VISIBLE before mapping */ + iupAttribSetStr(ih, "VISIBLE", NULL); + + return IUP_NOERROR; +} + +static void gtkDialogUnMapMethod(Ihandle* ih) +{ + GtkWidget* fixed; +#if GTK_CHECK_VERSION(2, 10, 0) + GtkStatusIcon* status_icon; +#endif + + if (ih->data->menu) + { + ih->data->menu->handle = NULL; /* the dialog will destroy the native menu */ + IupDestroy(ih->data->menu); + } + +#if GTK_CHECK_VERSION(2, 10, 0) + status_icon = (GtkStatusIcon*)iupAttribGet(ih, "_IUPDLG_STATUSICON"); + if (status_icon) + g_object_unref(status_icon); +#endif + + fixed = gtk_bin_get_child((GtkBin*)ih->handle); + gtk_widget_unrealize(fixed); + gtk_widget_destroy(fixed); + + gtk_widget_unrealize(ih->handle); /* To match the call to gtk_widget_realize */ + gtk_widget_destroy(ih->handle); /* To match the call to gtk_window_new */ +} + +static void gtkDialogLayoutUpdateMethod(Ihandle *ih) +{ + int border, caption, menu; + int width, height; + + if (ih->data->ignore_resize || + iupAttribGet(ih, "_IUPGTK_FS_STYLE")) + return; + + /* for dialogs the position is not updated here */ + ih->data->ignore_resize = 1; + + iupdrvDialogGetDecoration(ih, &border, &caption, &menu); + + /* set size excluding the border */ + width = ih->currentwidth - 2*border; + height = ih->currentheight - 2*border - caption; /* menu is inside the client area. */ + gtk_window_resize((GtkWindow*)ih->handle, width, height); + + if (!iupAttribGetBoolean(ih, "RESIZE")) + { + GdkGeometry geometry; + geometry.min_width = width; + geometry.min_height = height; + geometry.max_width = width; + geometry.max_height = height; + gtk_window_set_geometry_hints((GtkWindow*)ih->handle, ih->handle, + &geometry, (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE)); + } + + ih->data->ignore_resize = 0; +} + + +/**************************************************************************** + Attributes +****************************************************************************/ + +static void gtkDialogSetMinMax(Ihandle* ih, int min_w, int min_h, int max_w, int max_h) +{ + /* The minmax size restricts the client area */ + GdkGeometry geometry; + int decorwidth = 0, decorheight = 0; + iupDialogGetDecorSize(ih, &decorwidth, &decorheight); + + geometry.min_width = 1; + if (min_w > decorwidth) + geometry.min_width = min_w-decorwidth; + + geometry.min_height = 1; + if (min_h > decorheight) + geometry.min_height = min_h-decorheight; + + geometry.max_width = 65535; + if (max_w > decorwidth && max_w > geometry.min_width) + geometry.max_width = max_w-decorwidth; + + geometry.max_height = 65535; + if (max_h > decorheight && max_w > geometry.min_height) + geometry.max_height = max_h-decorheight; + + gtk_window_set_geometry_hints((GtkWindow*)ih->handle, ih->handle, + &geometry, (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE)); +} + +static int gtkDialogSetMinSizeAttrib(Ihandle* ih, const char* value) +{ + int min_w = 1, min_h = 1; /* MINSIZE default value */ + int max_w = 65535, max_h = 65535; /* MAXSIZE default value */ + iupStrToIntInt(value, &min_w, &min_h, 'x'); + + /* if MAXSIZE also set, must be also updated here */ + iupStrToIntInt(iupAttribGet(ih, "MAXSIZE"), &max_w, &max_h, 'x'); + + gtkDialogSetMinMax(ih, min_w, min_h, max_w, max_h); + return 1; +} + +static int gtkDialogSetMaxSizeAttrib(Ihandle* ih, const char* value) +{ + int min_w = 1, min_h = 1; /* MINSIZE default value */ + int max_w = 65535, max_h = 65535; /* MAXSIZE default value */ + iupStrToIntInt(value, &max_w, &max_h, 'x'); + + /* if MINSIZE also set, must be also updated here */ + iupStrToIntInt(iupAttribGet(ih, "MINSIZE"), &min_w, &min_h, 'x'); + + gtkDialogSetMinMax(ih, min_w, min_h, max_w, max_h); + return 1; +} + +static char* gtkDialogGetXAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(20); + + gint x = 0; + gtk_window_get_position((GtkWindow*)ih->handle, &x, NULL); + + sprintf(str, "%d", x); + return str; +} + +static char* gtkDialogGetYAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(20); + + gint y = 0; + gtk_window_get_position((GtkWindow*)ih->handle, NULL, &y); + + sprintf(str, "%d", y); + return str; +} + +static int gtkDialogSetTitleAttrib(Ihandle* ih, const char* value) +{ + if (!value) + value = ""; + gtk_window_set_title((GtkWindow*)ih->handle, iupgtkStrConvertToUTF8(value)); + return 0; +} + +static char* gtkDialogGetTitleAttrib(Ihandle* ih) +{ + const char* title = gtk_window_get_title((GtkWindow*)ih->handle); + + if (!title || title[0] == 0) + return NULL; + else + return iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(title)); +} + +static char* gtkDialogGetClientSizeAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(20); + + int width, height; + gtk_window_get_size((GtkWindow*)ih->handle, &width, &height); + height -= gtkDialogGetMenuSize(ih); + + sprintf(str, "%dx%d", width, height); + return str; +} + +static int gtkDialogSetFullScreenAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + { + if (!iupAttribGet(ih, "_IUPGTK_FS_STYLE")) + { + /* save the previous decoration attributes */ + /* during fullscreen these attributes can be consulted by the application */ + iupAttribStoreStr(ih, "_IUPGTK_FS_MAXBOX", iupAttribGet(ih, "MAXBOX")); + iupAttribStoreStr(ih, "_IUPGTK_FS_MINBOX", iupAttribGet(ih, "MINBOX")); + iupAttribStoreStr(ih, "_IUPGTK_FS_MENUBOX",iupAttribGet(ih, "MENUBOX")); + iupAttribStoreStr(ih, "_IUPGTK_FS_RESIZE", iupAttribGet(ih, "RESIZE")); + iupAttribStoreStr(ih, "_IUPGTK_FS_BORDER", iupAttribGet(ih, "BORDER")); + iupAttribStoreStr(ih, "_IUPGTK_FS_TITLE", IupGetAttribute(ih, "TITLE")); /* must use IupGetAttribute to check from the native implementation */ + + /* remove the decorations attributes */ + iupAttribSetStr(ih, "MAXBOX", "NO"); + iupAttribSetStr(ih, "MINBOX", "NO"); + iupAttribSetStr(ih, "MENUBOX", "NO"); + IupSetAttribute(ih, "TITLE", NULL); iupAttribSetStr(ih, "TITLE", NULL); /* remove from the hash table if we are during IupMap */ + iupAttribSetStr(ih, "RESIZE", "NO"); + iupAttribSetStr(ih, "BORDER", "NO"); + + if (iupdrvIsVisible(ih)) + gtk_window_fullscreen((GtkWindow*)ih->handle); + + iupAttribSetStr(ih, "_IUPGTK_FS_STYLE", "YES"); + } + } + else + { + char* fs_style = iupAttribGet(ih, "_IUPGTK_FS_STYLE"); + if (fs_style) + { + iupAttribSetStr(ih, "_IUPGTK_FS_STYLE", NULL); + + /* restore the decorations attributes */ + iupAttribStoreStr(ih, "MAXBOX", iupAttribGet(ih, "_IUPGTK_FS_MAXBOX")); + iupAttribStoreStr(ih, "MINBOX", iupAttribGet(ih, "_IUPGTK_FS_MINBOX")); + iupAttribStoreStr(ih, "MENUBOX",iupAttribGet(ih, "_IUPGTK_FS_MENUBOX")); + IupSetAttribute(ih, "TITLE", iupAttribGet(ih, "_IUPGTK_FS_TITLE")); /* must use IupSetAttribute to update the native implementation */ + iupAttribStoreStr(ih, "RESIZE", iupAttribGet(ih, "_IUPGTK_FS_RESIZE")); + iupAttribStoreStr(ih, "BORDER", iupAttribGet(ih, "_IUPGTK_FS_BORDER")); + + if (iupdrvIsVisible(ih)) + gtk_window_unfullscreen((GtkWindow*)ih->handle); + + /* remove auxiliar attributes */ + iupAttribSetStr(ih, "_IUPGTK_FS_MAXBOX", NULL); + iupAttribSetStr(ih, "_IUPGTK_FS_MINBOX", NULL); + iupAttribSetStr(ih, "_IUPGTK_FS_MENUBOX",NULL); + iupAttribSetStr(ih, "_IUPGTK_FS_RESIZE", NULL); + iupAttribSetStr(ih, "_IUPGTK_FS_BORDER", NULL); + iupAttribSetStr(ih, "_IUPGTK_FS_TITLE", NULL); + } + } + return 1; +} + +static int gtkDialogSetTopMostAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + gtk_window_set_keep_above((GtkWindow*)ih->handle, TRUE); + else + gtk_window_set_keep_above((GtkWindow*)ih->handle, FALSE); + return 1; +} + +#if GTK_CHECK_VERSION(2, 12, 0) +static int gtkDialogSetOpacityAttrib(Ihandle *ih, const char *value) +{ + int opacity; + if (!iupStrToInt(value, &opacity)) + return 0; + + gtk_window_set_opacity((GtkWindow*)ih->handle, (double)opacity/255.0); + return 1; +} +#endif + +static int gtkDialogSetIconAttrib(Ihandle* ih, const char *value) +{ + if (!value) + gtk_window_set_icon((GtkWindow*)ih->handle, NULL); + else + { + GdkPixbuf* icon = (GdkPixbuf*)iupImageGetIcon(value); + if (icon) + gtk_window_set_icon((GtkWindow*)ih->handle, icon); + } + return 1; +} + +static int gtkDialogSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + if (iupdrvBaseSetBgColorAttrib(ih, value)) + { + GtkStyle *style = gtk_widget_get_style(ih->handle); + if (style->bg_pixmap[GTK_STATE_NORMAL]) + { + style = gtk_style_copy(style); + style->bg_pixmap[GTK_STATE_NORMAL] = NULL; + gtk_widget_set_style(ih->handle, style); + } + return 1; + } + else + { + GdkPixbuf* pixbuf = iupImageGetImage(value, ih, 0); + if (pixbuf) + { + GdkPixmap* pixmap; + GtkStyle *style; + + gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap, NULL, 255); + + style = gtk_style_copy(gtk_widget_get_style(ih->handle)); + style->bg_pixmap[GTK_STATE_NORMAL] = pixmap; + gtk_widget_set_style(ih->handle, style); + + return 1; + } + } + + return 0; +} + +#if GTK_CHECK_VERSION(2, 10, 0) +static int gtkDialogTaskDoubleClick(int button) +{ + static int last_button = -1; + static GTimer* timer = NULL; + if (last_button == -1 || last_button != button) + { + last_button = button; + if (timer) + g_timer_destroy(timer); + timer = g_timer_new(); + return 0; + } + else + { + double seconds; + + if (!timer) /* just in case */ + return 0; + + seconds = g_timer_elapsed(timer, NULL); + if (seconds < 0.4) + { + /* reset state */ + g_timer_destroy(timer); + timer = NULL; + last_button = -1; + return 1; + } + else + { + g_timer_reset(timer); + return 0; + } + } +} + +static void gtkDialogTaskAction(GtkStatusIcon *status_icon, Ihandle *ih) +{ + /* from GTK source code it is called only when button==1 and pressed==1 */ + int button = 1; + int pressed = 1; + int dclick = gtkDialogTaskDoubleClick(button); + IFniii cb = (IFniii)IupGetCallback(ih, "TRAYCLICK_CB"); + if (cb && cb(ih, button, pressed, dclick) == IUP_CLOSE) + IupExitLoop(); + (void)status_icon; +} + +static void gtkDialogTaskPopupMenu(GtkStatusIcon *status_icon, guint gbutton, guint activate_time, Ihandle *ih) +{ + /* from GTK source code it is called only when button==3 and pressed==1 */ + int button = 3; + int pressed = 1; + int dclick = gtkDialogTaskDoubleClick(button); + IFniii cb = (IFniii)IupGetCallback(ih, "TRAYCLICK_CB"); + if (cb && cb(ih, button, pressed, dclick) == IUP_CLOSE) + IupExitLoop(); + (void)activate_time; + (void)gbutton; + (void)status_icon; +} + +static GtkStatusIcon* gtkDialogGetStatusIcon(Ihandle *ih) +{ + GtkStatusIcon* status_icon = (GtkStatusIcon*)iupAttribGet(ih, "_IUPDLG_STATUSICON"); + if (!status_icon) + { + status_icon = gtk_status_icon_new(); + + g_signal_connect(G_OBJECT(status_icon), "activate", G_CALLBACK(gtkDialogTaskAction), ih); + g_signal_connect(G_OBJECT(status_icon), "popup-menu", G_CALLBACK(gtkDialogTaskPopupMenu), ih); + + iupAttribSetStr(ih, "_IUPDLG_STATUSICON", (char*)status_icon); + } + return status_icon; +} + +static int gtkDialogSetTrayAttrib(Ihandle *ih, const char *value) +{ + GtkStatusIcon* status_icon = gtkDialogGetStatusIcon(ih); + gtk_status_icon_set_visible(status_icon, iupStrBoolean(value)); + return 1; +} + +static int gtkDialogSetTrayTipAttrib(Ihandle *ih, const char *value) +{ + GtkStatusIcon* status_icon = gtkDialogGetStatusIcon(ih); +#if GTK_CHECK_VERSION(2, 16, 0) + if (value) + { + gtk_status_icon_set_has_tooltip(status_icon, TRUE); + gtk_status_icon_set_tooltip_text(status_icon, value); + } + else + gtk_status_icon_set_has_tooltip(status_icon, FALSE); +#else + gtk_status_icon_set_tooltip(status_icon, value); +#endif + return 1; +} + +static int gtkDialogSetTrayImageAttrib(Ihandle *ih, const char *value) +{ + GtkStatusIcon* status_icon = gtkDialogGetStatusIcon(ih); + GdkPixbuf* icon = (GdkPixbuf*)iupImageGetIcon(value); + gtk_status_icon_set_from_pixbuf(status_icon, icon); + return 1; +} +#endif /* GTK_CHECK_VERSION(2, 10, 0) */ + +void iupdrvDialogInitClass(Iclass* ic) +{ + /* Driver Dependent Class methods */ + ic->Map = gtkDialogMapMethod; + ic->UnMap = gtkDialogUnMapMethod; + ic->LayoutUpdate = gtkDialogLayoutUpdateMethod; + ic->GetInnerNativeContainerHandle = gtkDialogGetInnerNativeContainerHandleMethod; + ic->SetChildrenPosition = gtkDialogSetChildrenPositionMethod; + + /* Callback Windows and GTK Only */ + iupClassRegisterCallback(ic, "TRAYCLICK_CB", "iii"); + + /* Driver Dependent Attribute functions */ + +#ifdef WIN32 + iupClassRegisterAttribute(ic, "HWND", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT); +#else + iupClassRegisterAttribute(ic, "XWINDOW", iupgtkGetNativeWindowHandle, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING); +#endif + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, "DLGBGCOLOR", NULL, IUPAF_DEFAULT); /* force new default value */ + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "X", gtkDialogGetXAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "Y", gtkDialogGetYAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + + /* Base Container */ + iupClassRegisterAttribute(ic, "CLIENTSIZE", gtkDialogGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + + /* Special */ + iupClassRegisterAttribute(ic, "TITLE", gtkDialogGetTitleAttrib, gtkDialogSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupDialog only */ + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, gtkDialogSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ICON", NULL, gtkDialogSetIconAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FULLSCREEN", NULL, gtkDialogSetFullScreenAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MINSIZE", NULL, gtkDialogSetMinSizeAttrib, IUPAF_SAMEASSYSTEM, "1x1", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MAXSIZE", NULL, gtkDialogSetMaxSizeAttrib, IUPAF_SAMEASSYSTEM, "65535x65535", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SAVEUNDER", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); /* saveunder not supported in GTK */ + + /* IupDialog Windows and GTK Only */ + iupClassRegisterAttribute(ic, "TOPMOST", NULL, gtkDialogSetTopMostAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DIALOGHINT", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); +#if GTK_CHECK_VERSION(2, 12, 0) + iupClassRegisterAttribute(ic, "OPACITY", NULL, gtkDialogSetOpacityAttrib, NULL, NULL, IUPAF_NO_INHERIT); +#endif +#if GTK_CHECK_VERSION(2, 10, 0) + iupClassRegisterAttribute(ic, "TRAY", NULL, gtkDialogSetTrayAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TRAYIMAGE", NULL, gtkDialogSetTrayImageAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TRAYTIP", NULL, gtkDialogSetTrayTipAttrib, NULL, NULL, IUPAF_NO_INHERIT); +#endif +} diff --git a/iup/src/gtk/iupgtk_drv.h b/iup/src/gtk/iupgtk_drv.h new file mode 100755 index 0000000..ade2a4a --- /dev/null +++ b/iup/src/gtk/iupgtk_drv.h @@ -0,0 +1,82 @@ +/** \file + * \brief GTK Driver + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPGTK_DRV_H +#define __IUPGTK_DRV_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* global variables, declared in iupgtk_globalattrib.c */ +extern int iupgtk_utf8autoconvert; + + +/* common */ +gboolean iupgtkEnterLeaveEvent(GtkWidget *widget, GdkEventCrossing *evt, Ihandle* ih); +gboolean iupgtkShowHelp(GtkWidget *widget, GtkWidgetHelpType *arg1, Ihandle* ih); +GtkFixed* iupgtkBaseGetFixed(Ihandle* ih); +void iupgtkBaseAddToParent(Ihandle* ih); +void iupgdkColorSet(GdkColor* color, unsigned char r, unsigned char g, unsigned char b); +int iupgtkSetDragDropAttrib(Ihandle* ih, const char* value); +int iupgtkSetMnemonicTitle(Ihandle* ih, GtkLabel* label, const char* value); +char* iupgtkStrConvertToUTF8(const char* str); +char* iupgtkStrConvertFromUTF8(const char* str); +void iupgtkReleaseConvertUTF8(void); +char* iupgtkStrConvertFromFilename(const char* str); +char* iupgtkStrConvertToFilename(const char* str); +void iupgtkUpdateMnemonic(Ihandle* ih); +gboolean iupgtkMotionNotifyEvent(GtkWidget *widget, GdkEventMotion *evt, Ihandle *ih); +gboolean iupgtkButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih); +void iupgtkBaseSetBgColor(InativeHandle* handle, unsigned char r, unsigned char g, unsigned char b); +void iupgtkBaseSetFgColor(InativeHandle* handle, unsigned char r, unsigned char g, unsigned char b); +void iupgtkBaseSetFgGdkColor(InativeHandle* handle, GdkColor *color); + + +/* focus */ +gboolean iupgtkFocusInOutEvent(GtkWidget *widget, GdkEventFocus *evt, Ihandle* ih); + + +/* key */ +gboolean iupgtkKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle* ih); +gboolean iupgtkKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle* ih); +void iupgtkButtonKeySetStatus(guint state, unsigned int but, char* status, int doubleclick); +void iupgtkKeyEncode(int key, guint *keyval, guint *state); + + +/* font */ +char* iupgtkGetPangoFontDescAttrib(Ihandle *ih); +char* iupgtkGetFontIdAttrib(Ihandle *ih); +PangoFontDescription* iupgtkGetPangoFontDesc(const char* value); +char* iupgtkFindPangoFontDesc(PangoFontDescription* fontdesc); +void iupgtkFontUpdatePangoLayout(Ihandle* ih, PangoLayout* layout); +void iupgtkFontUpdateObjectPangoLayout(Ihandle* ih, gpointer object); + +/* There are PANGO_SCALE Pango units in one device unit. + For an output backend where a device unit is a pixel, + a size value of 10 * PANGO_SCALE gives 10 pixels. */ +#define IUPGTK_PANGOUNITS2PIXELS(_x) (((_x) + PANGO_SCALE/2) / PANGO_SCALE) +#define IUPGTK_PIXELS2PANGOUNITS(_x) ((_x) * PANGO_SCALE) + + +/* open */ +char* iupgtkGetNativeWindowHandle(Ihandle* ih); +void iupgtkPushVisualAndColormap(void* visual, void* colormap); +void* iupgtkGetNativeGraphicsContext(GtkWidget* widget); +void iupgtkReleaseNativeGraphicsContext(GtkWidget* widget, void* gc); +void iupgtkUpdateGlobalColors(GtkStyle* style); + + +/* dialog */ +gboolean iupgtkDialogDeleteEvent(GtkWidget *widget, GdkEvent *evt, Ihandle *ih); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/gtk/iupgtk_filedlg.c b/iup/src/gtk/iupgtk_filedlg.c new file mode 100755 index 0000000..5426910 --- /dev/null +++ b/iup/src/gtk/iupgtk_filedlg.c @@ -0,0 +1,536 @@ +/** \file + * \brief IupFileDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> + +#include <stdlib.h> +#include <string.h> +#include <memory.h> +#include <stdio.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drvinfo.h" +#include "iup_dialog.h" +#include "iup_strmessage.h" +#include "iup_array.h" +#include "iup_drvinfo.h" + +#include "iupgtk_drv.h" + + +static void iupStrRemoveChar(char* str, char c) +{ + char* p = str; + while (*str) + { + if (*str != c) + { + *p = *str; + p++; + } + + str++; + } + *p = 0; +} + +static void gtkFileDlgGetNextFilter(char** str, char** name, char** pattern) +{ + int len; + *name = *str; + + len = strlen(*name); + *pattern = (*name)+len+1; + + len = strlen(*pattern); + *str = (*pattern)+len+1; + + iupStrReplace(*pattern, ';', 0); /* remove other patterns */ +} + +static void gtkFileDlgGetMultipleFiles(Ihandle* ih, GSList* list) +{ + int len, cur_len, dir_len = -1; + char *filename, *all_names; + Iarray* names_array = iupArrayCreate(1024, 1); /* just set an initial size, but count is 0 */ + + while (list) + { + filename = (char*)list->data; + len = strlen(filename); + + if (dir_len == -1) + { + dir_len = len; + + while (dir_len && (filename[dir_len] != '/' && filename[dir_len] != '\\')) + dir_len--; + + cur_len = iupArrayCount(names_array); + all_names = iupArrayAdd(names_array, dir_len+1); + memcpy(all_names+cur_len, filename, dir_len); + all_names[cur_len+dir_len] = '|'; + + dir_len++; /* skip separator */ + } + len -= dir_len; /* remove directory */ + + cur_len = iupArrayCount(names_array); + all_names = iupArrayAdd(names_array, len+1); + memcpy(all_names+cur_len, filename+dir_len, len); + all_names[cur_len+len] = '|'; + + g_free(filename); + list = list->next; + } + + cur_len = iupArrayCount(names_array); + all_names = iupArrayInc(names_array); + all_names[cur_len+1] = 0; + + iupAttribStoreStr(ih, "VALUE", iupgtkStrConvertFromFilename(all_names)); + + iupArrayDestroy(names_array); +} + +#ifdef WIN32 +#include <gdk/gdkwin32.h> +#else +#include <gdk/gdkx.h> +#endif + +static void gtkFileDlgUpdatePreviewGLCanvas(Ihandle* ih) +{ + Ihandle* glcanvas = IupGetAttributeHandle(ih, "PREVIEWGLCANVAS"); + if (glcanvas) + { +#ifdef WIN32 + iupAttribSetStr(glcanvas, "HWND", iupAttribGet(ih, "HWND")); +#else + iupAttribSetStr(glcanvas, "XWINDOW", iupAttribGet(ih, "XWINDOW")); +#endif + glcanvas->iclass->Map(glcanvas); + } +} + +static void gtkFileDlgPreviewRealize(GtkWidget *widget, Ihandle *ih) +{ + iupAttribSetStr(ih, "PREVIEWDC", iupgtkGetNativeGraphicsContext(widget)); + iupAttribSetStr(ih, "WID", (char*)widget); + +#ifdef WIN32 + iupAttribSetStr(ih, "HWND", (char*)GDK_WINDOW_HWND(widget->window)); +#else + iupAttribSetStr(ih, "XWINDOW", (char*)GDK_WINDOW_XID(widget->window)); + iupAttribSetStr(ih, "XDISPLAY", (char*)iupdrvGetDisplay()); +#endif + gtkFileDlgUpdatePreviewGLCanvas(ih); +} + +static void gtkFileDlgRealize(GtkWidget *widget, Ihandle *ih) +{ + IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + cb(ih, NULL, "INIT"); + + (void)widget; +} + +static gboolean gtkFileDlgPreviewConfigureEvent(GtkWidget *widget, GdkEventConfigure *evt, Ihandle *ih) +{ + iupAttribSetInt(ih, "PREVIEWWIDTH", evt->width); + iupAttribSetInt(ih, "PREVIEWHEIGHT", evt->height); + + (void)widget; + return FALSE; +} + +static gboolean gtkFileDlgPreviewExposeEvent(GtkWidget *widget, GdkEventExpose *evt, Ihandle *ih) +{ + GtkFileChooser *file_chooser = (GtkFileChooser*)iupAttribGet(ih, "_IUPDLG_FILE_CHOOSER"); + char *filename = gtk_file_chooser_get_preview_filename(file_chooser); + + IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + if (iupdrvIsFile(filename)) + cb(ih, iupgtkStrConvertFromFilename(filename), "PAINT"); + else + cb(ih, NULL, "PAINT"); + + g_free (filename); + + (void)evt; + (void)widget; + return TRUE; /* stop other handlers */ +} + +static void gtkFileDlgUpdatePreview(GtkFileChooser *file_chooser, Ihandle* ih) +{ + char *filename = gtk_file_chooser_get_preview_filename(file_chooser); + + if (iupdrvIsFile(filename)) + { + IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + cb(ih, iupgtkStrConvertFromFilename(filename), "SELECT"); + } + + g_free (filename); + + gtk_file_chooser_set_preview_widget_active(file_chooser, TRUE); +} + +static int gtkFileDlgPopup(Ihandle* ih, int x, int y) +{ + InativeHandle* parent = iupDialogGetNativeParent(ih); + GtkWidget* dialog; + GtkWidget* preview_canvas = NULL; + GtkFileChooserAction action; + IFnss file_cb; + char* value; + int response, filter_count = 0; + + iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */ + iupAttribSetInt(ih, "_IUPDLG_Y", y); + + value = iupAttribGetStr(ih, "DIALOGTYPE"); + if (iupStrEqualNoCase(value, "SAVE")) + action = GTK_FILE_CHOOSER_ACTION_SAVE; + else if (iupStrEqualNoCase(value, "DIR")) + action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; + else + action = GTK_FILE_CHOOSER_ACTION_OPEN; + + value = iupAttribGet(ih, "TITLE"); + if (!value) + { + GtkStockItem item; + + if (action == GTK_FILE_CHOOSER_ACTION_SAVE) + value = GTK_STOCK_SAVE_AS; + else + value = GTK_STOCK_OPEN; + + gtk_stock_lookup(value, &item); + value = item.label; + + iupAttribStoreStr(ih, "TITLE", iupgtkStrConvertFromUTF8(value)); + value = iupAttribGet(ih, "TITLE"); + iupStrRemoveChar(value, '_'); + } + + dialog = gtk_file_chooser_dialog_new(iupgtkStrConvertToUTF8(value), (GtkWindow*)parent, action, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + NULL); + if (!dialog) + return IUP_ERROR; + + if (action == GTK_FILE_CHOOSER_ACTION_SAVE) + gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_SAVE, GTK_RESPONSE_OK); + else if (action == GTK_FILE_CHOOSER_ACTION_OPEN) + gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OPEN, GTK_RESPONSE_OK); + else + gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OK, GTK_RESPONSE_OK); + + if (IupGetCallback(ih, "HELP_CB")) + gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_HELP, GTK_RESPONSE_HELP); + +#if GTK_CHECK_VERSION(2, 6, 0) + if (iupAttribGetBoolean(ih, "SHOWHIDDEN")) + gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog), TRUE); +#endif + + if (iupAttribGetBoolean(ih, "MULTIPLEFILES") && action == GTK_FILE_CHOOSER_ACTION_OPEN) + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE); + +#if GTK_CHECK_VERSION(2, 8, 0) + if (!iupAttribGetBoolean(ih, "NOOVERWRITEPROMPT") && action == GTK_FILE_CHOOSER_ACTION_SAVE) + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); +#endif + + /* just check for the path inside FILE */ + value = iupAttribGet(ih, "FILE"); + if (value && (value[0] == '/' || value[1] == ':')) + { + char* dir = iupStrFileGetPath(value); + int len = strlen(dir); + iupAttribStoreStr(ih, "DIRECTORY", dir); + free(dir); + iupAttribStoreStr(ih, "FILE", value+len); + } + + value = iupAttribGet(ih, "DIRECTORY"); + if (value) + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), iupgtkStrConvertToFilename(value)); + + value = iupAttribGet(ih, "FILE"); + if (value) + { + if (action == GTK_FILE_CHOOSER_ACTION_SAVE) + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), iupgtkStrConvertToFilename(value)); + else + { + if (iupdrvIsFile(value)) /* check if file exists */ + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), iupgtkStrConvertToFilename(value)); + } + } + + value = iupAttribGet(ih, "EXTFILTER"); + if (value) + { + char *name, *pattern, *filters = iupStrDup(value), *p; + char atrib[30]; + int i; + int filter_index = iupAttribGetInt(ih, "FILTERUSED"); + if (!filter_index) + filter_index = 1; + + filter_count = iupStrReplace(filters, '|', 0) / 2; + + p = filters; + for (i=0; i<filter_count; i++) + { + GtkFileFilter *filter = gtk_file_filter_new(); + + gtkFileDlgGetNextFilter(&p, &name, &pattern); + + gtk_file_filter_set_name(filter, iupgtkStrConvertToUTF8(name)); + gtk_file_filter_add_pattern(filter, pattern); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); + + sprintf(atrib, "_IUPDLG_FILTER%d", i+1); + iupAttribSetStr(ih, atrib, (char*)filter); + + if (i+1 == filter_index) + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter); + } + + free(filters); + } + else + { + value = iupAttribGet(ih, "FILTER"); + if (value) + { + GtkFileFilter *filter = gtk_file_filter_new(); + char* info = iupAttribGet(ih, "FILTERINFO"); + if (!info) + info = value; + + gtk_file_filter_set_name(filter, iupgtkStrConvertToUTF8(info)); + gtk_file_filter_add_pattern(filter, value); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); + } + } + + file_cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + if (file_cb && action != GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) + { + g_signal_connect(GTK_FILE_CHOOSER(dialog), "update-preview", G_CALLBACK(gtkFileDlgUpdatePreview), ih); + g_signal_connect(dialog, "realize", G_CALLBACK(gtkFileDlgRealize), ih); + + if (iupAttribGetBoolean(ih, "SHOWPREVIEW")) + { + GtkWidget* frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); + gtk_widget_set_size_request(frame, 180, 150); + + preview_canvas = gtk_drawing_area_new(); + gtk_widget_set_double_buffered(preview_canvas, FALSE); + gtk_container_add(GTK_CONTAINER(frame), preview_canvas); + gtk_widget_show(preview_canvas); + + g_signal_connect(preview_canvas, "configure-event", G_CALLBACK(gtkFileDlgPreviewConfigureEvent), ih); + g_signal_connect(preview_canvas, "expose-event", G_CALLBACK(gtkFileDlgPreviewExposeEvent), ih); + g_signal_connect(preview_canvas, "realize", G_CALLBACK(gtkFileDlgPreviewRealize), ih); + + iupAttribSetStr(ih, "_IUPDLG_FILE_CHOOSER", (char*)dialog); + + gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog), frame); + } + } + + /* initialize the widget */ + gtk_widget_realize(GTK_WIDGET(dialog)); + + ih->handle = GTK_WIDGET(dialog); + iupDialogUpdatePosition(ih); + ih->handle = NULL; /* reset handle */ + + do + { + response = gtk_dialog_run(GTK_DIALOG(dialog)); + + if (response == GTK_RESPONSE_HELP) + { + Icallback cb = IupGetCallback(ih, "HELP_CB"); + if (cb && cb(ih) == IUP_CLOSE) + response = GTK_RESPONSE_CANCEL; + } + else if (response == GTK_RESPONSE_OK) + { + char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + int file_exist = iupdrvIsFile(filename); + int dir_exist = iupdrvIsDirectory(filename); + g_free(filename); + + if (action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) + { + if (!dir_exist) + { + iupStrMessageShowError(ih, "IUP_INVALIDDIR"); + response = GTK_RESPONSE_HELP; /* to leave the dialog open */ + continue; + } + } + else if (!iupAttribGetBoolean(ih, "MULTIPLEFILES")) + { + if (dir_exist) + { + iupStrMessageShowError(ih, "IUP_FILEISDIR"); + response = GTK_RESPONSE_HELP; /* to leave the dialog open */ + continue; + } + + if (!file_exist) /* if do not exist check ALLOWNEW */ + { + value = iupAttribGet(ih, "ALLOWNEW"); + if (!value) + { + if (action == GTK_FILE_CHOOSER_ACTION_SAVE) + value = "YES"; + else + value = "NO"; + } + + if (!iupStrBoolean(value)) + { + iupStrMessageShowError(ih, "IUP_FILENOTEXIST"); + response = GTK_RESPONSE_HELP; /* to leave the dialog open */ + continue; + } + } + + if (file_cb) + { + char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + int ret = file_cb(ih, iupgtkStrConvertFromFilename(filename), "OK"); + g_free(filename); + + if (ret == IUP_IGNORE) + { + response = GTK_RESPONSE_HELP; /* to leave the dialog open */ + continue; + } + } + } + } + } while (response == GTK_RESPONSE_HELP); + + if (file_cb) + { + if (iupAttribGetBoolean(ih, "SHOWPREVIEW")) + iupgtkReleaseNativeGraphicsContext(preview_canvas, (void*)iupAttribGet(ih, "PREVIEWDC")); + + file_cb(ih, NULL, "FINISH"); + } + + if (response == GTK_RESPONSE_OK) + { + int file_exist, dir_exist; + + if (filter_count) + { + int i; + char atrib[30]; + GtkFileFilter* filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog)); + + for (i=0; i<filter_count; i++) + { + sprintf(atrib, "_IUPDLG_FILTER%d", i+1); + if (filter == (GtkFileFilter*)iupAttribGet(ih, atrib)) + iupAttribSetInt(ih, "FILTERUSED", i+1); + } + } + + if (iupAttribGetBoolean(ih, "MULTIPLEFILES")) + { + GSList* file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); + + if (file_list->next) /* if more than one file */ + gtkFileDlgGetMultipleFiles(ih, file_list); + else + { + char* filename = (char*)file_list->data; + iupAttribStoreStr(ih, "VALUE", iupgtkStrConvertFromFilename(filename)); + g_free(filename); + } + + g_slist_free(file_list); + file_exist = 1; + dir_exist = 0; + } + else + { + char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + iupAttribStoreStr(ih, "VALUE", iupgtkStrConvertFromFilename(filename)); + file_exist = iupdrvIsFile(filename); + dir_exist = iupdrvIsDirectory(filename); + g_free(filename); + } + + if (dir_exist) + { + iupAttribSetStr(ih, "FILEEXIST", NULL); + iupAttribSetStr(ih, "STATUS", "0"); + } + else + { + if (file_exist) /* check if file exists */ + { + iupAttribSetStr(ih, "FILEEXIST", "YES"); + iupAttribSetStr(ih, "STATUS", "0"); + } + else + { + iupAttribSetStr(ih, "FILEEXIST", "NO"); + iupAttribSetStr(ih, "STATUS", "1"); + } + } + + if (action != GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER && !iupAttribGetBoolean(ih, "NOCHANGEDIR")) /* do change the current directory */ + { + /* GtkFileChooser does not change the current directory */ + char* dir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog)); + if (dir) iupdrvSetCurrentDirectory(dir); + g_free(dir); + } + } + else + { + iupAttribSetStr(ih, "FILTERUSED", NULL); + iupAttribSetStr(ih, "VALUE", NULL); + iupAttribSetStr(ih, "FILEEXIST", NULL); + iupAttribSetStr(ih, "STATUS", "-1"); + } + + gtk_widget_destroy(GTK_WIDGET(dialog)); + + return IUP_NOERROR; +} + +void iupdrvFileDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = gtkFileDlgPopup; + + /* IupFileDialog Windows and GTK Only */ + iupClassRegisterAttribute(ic, "EXTFILTER", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FILTERINFO", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FILTERUSED", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MULTIPLEFILES", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); +} diff --git a/iup/src/gtk/iupgtk_focus.c b/iup/src/gtk/iupgtk_focus.c new file mode 100755 index 0000000..fa596ba --- /dev/null +++ b/iup/src/gtk/iupgtk_focus.c @@ -0,0 +1,44 @@ +/** \file + * \brief GTK Focus + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> + +#include <stdio.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_focus.h" +#include "iup_attrib.h" +#include "iup_drv.h" +#include "iup_assert.h" +#include "iup_drv.h" + +#include "iupgtk_drv.h" + + +void iupdrvSetFocus(Ihandle *ih) +{ + gtk_widget_grab_focus(ih->handle); +} + +gboolean iupgtkFocusInOutEvent(GtkWidget *widget, GdkEventFocus *evt, Ihandle *ih) +{ + (void)widget; + + if (evt->in) + { + /* even when ACTIVE=NO the dialog gets this evt */ + if (!iupdrvIsActive(ih)) + return TRUE; + + iupCallGetFocusCb(ih); + } + else + iupCallKillFocusCb(ih); + + return FALSE; +} diff --git a/iup/src/gtk/iupgtk_font.c b/iup/src/gtk/iupgtk_font.c new file mode 100755 index 0000000..f7ff348 --- /dev/null +++ b/iup/src/gtk/iupgtk_font.c @@ -0,0 +1,413 @@ +/** \file + * \brief GTK Font mapping + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <gtk/gtk.h> + +#include "iup.h" + +#include "iup_str.h" +#include "iup_attrib.h" +#include "iup_array.h" +#include "iup_object.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_assert.h" + +#include "iupgtk_drv.h" + + +typedef struct _IgtkFont +{ + char standardfont[200]; + PangoFontDescription* fontdesc; + PangoAttribute* strikethrough; + PangoAttribute* underline; + PangoLayout* layout; + int charwidth, charheight; +} IgtkFont; + +static Iarray* gtk_fonts = NULL; +static PangoContext *gtk_fonts_context = NULL; + +static void gtkFontUpdate(IgtkFont* gtkfont) +{ + PangoAttrList *attrs; + + pango_layout_set_font_description(gtkfont->layout, gtkfont->fontdesc); + + attrs = pango_layout_get_attributes(gtkfont->layout); + if (!attrs) + { + attrs = pango_attr_list_new(); + pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->strikethrough)); + pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->underline)); + pango_layout_set_attributes(gtkfont->layout, attrs); + } + else + { + pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->strikethrough)); + pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->underline)); + } +} + +static IgtkFont* gtkFindFont(const char *standardfont) +{ + PangoFontMetrics* metrics; + PangoFontDescription* fontdesc; + int i, + is_underline = 0, + is_strikeout = 0, + count = iupArrayCount(gtk_fonts); + + IgtkFont* fonts = (IgtkFont*)iupArrayGetData(gtk_fonts); + + /* Check if the standardfont already exists in cache */ + for (i = 0; i < count; i++) + { + if (iupStrEqualNoCase(standardfont, fonts[i].standardfont)) + return &fonts[i]; + } + + /* not found, create a new one */ + { + int size = 0, is_pango = 0; + int is_bold = 0, + is_italic = 0; + char typeface[1024]; + const char* mapped_name; + + /* parse the old Windows format first */ + if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + return NULL; + else + is_pango = 1; + } + } + + mapped_name = iupFontGetPangoName(typeface); + if (mapped_name) + strcpy(typeface, mapped_name); + + if (is_pango && !is_underline && !is_strikeout && size>0) + fontdesc = pango_font_description_from_string(standardfont); + else + { + char new_standardfont[200]; + if (size<0) + { + double res = ((double)gdk_screen_get_width(gdk_screen_get_default()) / (double)gdk_screen_get_width_mm(gdk_screen_get_default())); /* pixels/mm */ + /* 1 point = 1/72 inch 1 inch = 25.4 mm */ + /* pixel = ((point/72)*25.4)*pixel/mm */ + size = (int)((-size/res)*2.83464567 + 0.5); /* from pixels to points */ + } + + sprintf(new_standardfont, "%s, %s%s%d", typeface, is_bold?"Bold ":"", is_italic?"Italic ":"", size); + + fontdesc = pango_font_description_from_string(new_standardfont); + } + } + + if (!fontdesc) + return NULL; + + /* create room in the array */ + fonts = (IgtkFont*)iupArrayInc(gtk_fonts); + + strcpy(fonts[i].standardfont, standardfont); + fonts[i].fontdesc = fontdesc; + fonts[i].strikethrough = pango_attr_strikethrough_new(is_strikeout? TRUE: FALSE); + fonts[i].underline = pango_attr_underline_new(is_underline? PANGO_UNDERLINE_SINGLE: PANGO_UNDERLINE_NONE); + fonts[i].layout = pango_layout_new(gtk_fonts_context); + + metrics = pango_context_get_metrics(gtk_fonts_context, fontdesc, pango_context_get_language(gtk_fonts_context)); + fonts[i].charheight = pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics); + fonts[i].charheight = IUPGTK_PANGOUNITS2PIXELS(fonts[i].charheight); + fonts[i].charwidth = pango_font_metrics_get_approximate_char_width(metrics); + fonts[i].charwidth = IUPGTK_PANGOUNITS2PIXELS(fonts[i].charwidth); + pango_font_metrics_unref(metrics); + + gtkFontUpdate(&(fonts[i])); + + return &fonts[i]; +} + +static PangoLayout* gtkFontGetWidgetPangoLayout(Ihandle *ih) +{ + int inherit; + char *def_value; + /* only check the native implementation */ + return (PangoLayout*)iupClassObjectGetAttribute(ih, "PANGOLAYOUT", &def_value, &inherit); +} + +static IgtkFont* gtkFontCreateNativeFont(Ihandle* ih, const char* value) +{ + IgtkFont *gtkfont = gtkFindFont(value); + if (!gtkfont) + { + iupERROR1("Failed to create Font: %s", value); + return NULL; + } + + iupAttribSetStr(ih, "_IUP_GTKFONT", (char*)gtkfont); + return gtkfont; +} + +static IgtkFont* gtkFontGet(Ihandle *ih) +{ + IgtkFont* gtkfont = (IgtkFont*)iupAttribGet(ih, "_IUP_GTKFONT"); + if (!gtkfont) + gtkfont = gtkFontCreateNativeFont(ih, iupGetFontAttrib(ih)); + return gtkfont; +} + +void iupgtkFontUpdatePangoLayout(Ihandle* ih, PangoLayout* layout) +{ + IgtkFont* gtkfont; + PangoAttrList *attrs; + + if (!layout) + return; + + gtkfont = gtkFontGet(ih); + if (!gtkfont) + return; + + attrs = pango_layout_get_attributes(layout); + if (!attrs) + { + attrs = pango_attr_list_new(); + pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->strikethrough)); + pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->underline)); + pango_layout_set_attributes(layout, attrs); + } + else + { + pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->strikethrough)); + pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->underline)); + } +} + +void iupgtkFontUpdateObjectPangoLayout(Ihandle* ih, gpointer object) +{ + PangoAttrList *attrs; + + IgtkFont* gtkfont = gtkFontGet(ih); + if (!gtkfont) + return; + + g_object_get(object, "attributes", &attrs, NULL); + if (!attrs) + { + attrs = pango_attr_list_new(); + pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->strikethrough)); + pango_attr_list_insert(attrs, pango_attribute_copy(gtkfont->underline)); + g_object_set(object, "attributes", attrs, NULL); + } + else + { + pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->strikethrough)); + pango_attr_list_change(attrs, pango_attribute_copy(gtkfont->underline)); + } +} + +char* iupdrvGetSystemFont(void) +{ + static char systemfont[200] = ""; + GtkStyle* style; + GtkWidget* widget = gtk_invisible_new(); + gtk_widget_realize(widget); + style = gtk_widget_get_style(widget); + if (!style || !style->font_desc) + strcpy(systemfont, "Sans, 10"); + else + { + char* desc = pango_font_description_to_string(style->font_desc); + strcpy(systemfont, desc); + g_free(desc); + } + gtk_widget_unrealize(widget); + gtk_widget_destroy(widget); + return systemfont; +} + +char* iupgtkFindPangoFontDesc(PangoFontDescription* fontdesc) +{ + int i, count = iupArrayCount(gtk_fonts); + IgtkFont* fonts = (IgtkFont*)iupArrayGetData(gtk_fonts); + + /* Check if the standardfont already exists in cache */ + for (i = 0; i < count; i++) + { + if (pango_font_description_equal(fontdesc, fonts[i].fontdesc)) + return fonts[i].standardfont; + } + + return NULL; +} + +PangoFontDescription* iupgtkGetPangoFontDesc(const char* value) +{ + IgtkFont *gtkfont = gtkFindFont(value); + if (!gtkfont) + { + iupERROR1("Failed to create Font: %s", value); + return NULL; + } + return gtkfont->fontdesc; +} + +char* iupgtkGetPangoFontDescAttrib(Ihandle *ih) +{ + IgtkFont* gtkfont = gtkFontGet(ih); + if (!gtkfont) + return NULL; + else + return (char*)gtkfont->fontdesc; +} + +char* iupgtkGetFontIdAttrib(Ihandle *ih) +{ + IgtkFont* gtkfont = gtkFontGet(ih); + if (!gtkfont) + return NULL; + else + { + GdkFont* gdk_font = gdk_font_from_description(gtkfont->fontdesc); + return (char*)gdk_font_id(gdk_font); /* In UNIX will return an X Font ID, in Win32 will return an HFONT */ + } +} + +int iupdrvSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + IgtkFont* gtkfont = gtkFontCreateNativeFont(ih, value); + if (!gtkfont) + return 1; + + /* If FONT is changed, must update the SIZE attribute */ + iupBaseUpdateSizeFromFont(ih); + + /* FONT attribute must be able to be set before mapping, + so the font is enable for size calculation. */ + if (ih->handle && (ih->iclass->nativetype != IUP_TYPEVOID)) + { + gtk_widget_modify_font(ih->handle, gtkfont->fontdesc); + iupgtkFontUpdatePangoLayout(ih, gtkFontGetWidgetPangoLayout(ih)); + } + + return 1; +} + +void iupdrvFontGetMultiLineStringSize(Ihandle* ih, const char* str, int *w, int *h) +{ + int max_w; + + IgtkFont* gtkfont = gtkFontGet(ih); + if (!gtkfont) + { + if (w) *w = 0; + if (h) *h = 0; + return; + } + + if (!str) + { + if (w) *w = 0; + if (h) *h = gtkfont->charheight * 1; + return; + } + + max_w = 0; + if (str[0]) + { + int dummy_h; + + pango_layout_set_attributes(gtkfont->layout, NULL); + + if (iupAttribGetBoolean(ih, "MARKUP")) + pango_layout_set_markup(gtkfont->layout, iupgtkStrConvertToUTF8(str), -1); + else + pango_layout_set_text(gtkfont->layout, iupgtkStrConvertToUTF8(str), -1); + + pango_layout_get_pixel_size(gtkfont->layout, &max_w, &dummy_h); + } + + if (w) *w = max_w; + if (h) *h = gtkfont->charheight * iupStrLineCount(str); +} + +int iupdrvFontGetStringWidth(Ihandle* ih, const char* str) +{ + IgtkFont* gtkfont; + int len, w; + char* line_end; + + if (!str || str[0]==0) + return 0; + + gtkfont = gtkFontGet(ih); + if (!gtkfont) + return 0; + + line_end = strchr(str, '\n'); + if (line_end) + len = line_end-str; + else + len = strlen(str); + + if (iupAttribGetBoolean(ih, "MARKUP")) + pango_layout_set_markup(gtkfont->layout, iupgtkStrConvertToUTF8(str), len); + else + pango_layout_set_text(gtkfont->layout, iupgtkStrConvertToUTF8(str), len); + + pango_layout_get_pixel_size(gtkfont->layout, &w, NULL); + return w; +} + +void iupdrvFontGetCharSize(Ihandle* ih, int *charwidth, int *charheight) +{ + IgtkFont* gtkfont = gtkFontGet(ih); + if (!gtkfont) + { + if (charwidth) *charwidth = 0; + if (charheight) *charheight = 0; + return; + } + + if (charheight) + *charheight = gtkfont->charheight; + + if (charwidth) + *charwidth = gtkfont->charwidth; +} + +void iupdrvFontInit(void) +{ + gtk_fonts = iupArrayCreate(50, sizeof(IgtkFont)); + gtk_fonts_context = gdk_pango_context_get(); + pango_context_set_language(gtk_fonts_context, gtk_get_default_language()); +} + +void iupdrvFontFinish(void) +{ + int i, count = iupArrayCount(gtk_fonts); + IgtkFont* fonts = (IgtkFont*)iupArrayGetData(gtk_fonts); + for (i = 0; i < count; i++) + { + pango_font_description_free(fonts[i].fontdesc); + pango_attribute_destroy(fonts[i].strikethrough); + pango_attribute_destroy(fonts[i].underline); + } + iupArrayDestroy(gtk_fonts); + g_object_unref(gtk_fonts_context); +} diff --git a/iup/src/gtk/iupgtk_fontdlg.c b/iup/src/gtk/iupgtk_fontdlg.c new file mode 100755 index 0000000..5769cbc --- /dev/null +++ b/iup/src/gtk/iupgtk_fontdlg.c @@ -0,0 +1,91 @@ +/** \file + * \brief IupFontDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> + +#include <string.h> +#include <memory.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_dialog.h" + +#include "iupgtk_drv.h" + + +static int gtkFontDlgPopup(Ihandle* ih, int x, int y) +{ + InativeHandle* parent = iupDialogGetNativeParent(ih); + GtkFontSelectionDialog* dialog; + int response; + char* preview_text; + + iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */ + iupAttribSetInt(ih, "_IUPDLG_Y", y); + + dialog = (GtkFontSelectionDialog*)gtk_font_selection_dialog_new(iupgtkStrConvertToUTF8(iupAttribGet(ih, "TITLE"))); + if (!dialog) + return IUP_ERROR; + + if (parent) + gtk_window_set_transient_for((GtkWindow*)dialog, (GtkWindow*)parent); + + gtk_font_selection_dialog_set_font_name(dialog, iupAttribGet(ih, "VALUE")); + + preview_text = iupAttribGet(ih, "PREVIEWTEXT"); + if (preview_text) + gtk_font_selection_dialog_set_preview_text(dialog, preview_text); + + if (IupGetCallback(ih, "HELP_CB")) + gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_HELP, GTK_RESPONSE_HELP); + + /* initialize the widget */ + gtk_widget_realize(GTK_WIDGET(dialog)); + + ih->handle = GTK_WIDGET(dialog); + iupDialogUpdatePosition(ih); + ih->handle = NULL; + + do + { + response = gtk_dialog_run(GTK_DIALOG(dialog)); + + if (response == GTK_RESPONSE_HELP) + { + Icallback cb = IupGetCallback(ih, "HELP_CB"); + if (cb && cb(ih) == IUP_CLOSE) + response = GTK_RESPONSE_CANCEL; + } + } while (response == GTK_RESPONSE_HELP); + + if (response == GTK_RESPONSE_OK) + { + char* fontname = gtk_font_selection_dialog_get_font_name(dialog); + iupAttribStoreStr(ih, "VALUE", fontname); + g_free(fontname); + iupAttribSetStr(ih, "STATUS", "1"); + } + else + { + iupAttribSetStr(ih, "VALUE", NULL); + iupAttribSetStr(ih, "STATUS", NULL); + } + + gtk_widget_destroy(GTK_WIDGET(dialog)); + + return IUP_NOERROR; +} + +void iupdrvFontDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = gtkFontDlgPopup; + + /* IupFontDialog GTK Only */ + iupClassRegisterAttribute(ic, "PREVIEWTEXT", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); +} diff --git a/iup/src/gtk/iupgtk_frame.c b/iup/src/gtk/iupgtk_frame.c new file mode 100755 index 0000000..022c6c7 --- /dev/null +++ b/iup/src/gtk/iupgtk_frame.c @@ -0,0 +1,155 @@ +/** \file + * \brief Frame Control + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_dialog.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" + +#include "iupgtk_drv.h" + + +void iupdrvFrameGetDecorOffset(Ihandle* ih, int *x, int *y) +{ + (void)ih; + *x = 0; + *y = 0; +} + +static char* gtkFrameGetTitleAttrib(Ihandle* ih) +{ + GtkFrame* frame = (GtkFrame*)ih->handle; + return iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_frame_get_label(frame))); +} + +static int gtkFrameSetTitleAttrib(Ihandle* ih, const char* value) +{ + GtkFrame* frame = (GtkFrame*)ih->handle; + gtk_frame_set_label(frame, iupgtkStrConvertToUTF8(value)); + return 0; +} + +static int gtkFrameSetBgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + GtkWidget* label = gtk_frame_get_label_widget((GtkFrame*)ih->handle); + + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + if (label) + iupgtkBaseSetBgColor(label, r, g, b); + + iupgtkBaseSetBgColor(ih->handle, r, g, b); + + return 1; +} + +static int gtkFrameSetFgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + GtkWidget* label = gtk_frame_get_label_widget((GtkFrame*)ih->handle); + if (!label) return 0; + + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + iupgtkBaseSetFgColor(label, r, g, b); + + return 1; +} + +static int gtkFrameSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + iupdrvSetStandardFontAttrib(ih, value); + + if (ih->handle) + { + GtkWidget* label = gtk_frame_get_label_widget((GtkFrame*)ih->handle); + if (!label) return 1; + + gtk_widget_modify_font(label, (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih)); + iupgtkFontUpdatePangoLayout(ih, gtk_label_get_layout((GtkLabel*)label)); + } + return 1; +} + +static void* gtkFrameGetInnerNativeContainerHandleMethod(Ihandle* ih, Ihandle* child) +{ + (void)child; + return (void*)gtk_bin_get_child((GtkBin*)ih->handle); +} + +static int gtkFrameMapMethod(Ihandle* ih) +{ + char *value, *title; + GtkWidget *fixed; + + if (!ih->parent) + return IUP_ERROR; + + title = iupAttribGet(ih, "TITLE"); + + ih->handle = gtk_frame_new(NULL); + if (!ih->handle) + return IUP_ERROR; + + if (title) + iupAttribSetStr(ih, "_IUPFRAME_HAS_TITLE", "1"); + else + { + value = iupAttribGetStr(ih, "SUNKEN"); + if (iupStrBoolean(value)) + gtk_frame_set_shadow_type((GtkFrame*)ih->handle, GTK_SHADOW_IN); + else + gtk_frame_set_shadow_type((GtkFrame*)ih->handle, GTK_SHADOW_ETCHED_IN); + } + + /* the container that will receive the child element. */ + fixed = gtk_fixed_new(); + gtk_container_add((GtkContainer*)ih->handle, fixed); + gtk_widget_show(fixed); + + /* Add to the parent, all GTK controls must call this. */ + iupgtkBaseAddToParent(ih); + + gtk_widget_realize(ih->handle); + + return IUP_NOERROR; +} + +void iupdrvFrameInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkFrameMapMethod; + ic->GetInnerNativeContainerHandle = gtkFrameGetInnerNativeContainerHandleMethod; + + /* Driver Dependent Attribute functions */ + + /* Overwrite Common */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, gtkFrameSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkFrameSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkFrameSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "TITLE", gtkFrameGetTitleAttrib, gtkFrameSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +} diff --git a/iup/src/gtk/iupgtk_globalattrib.c b/iup/src/gtk/iupgtk_globalattrib.c new file mode 100755 index 0000000..eebe799 --- /dev/null +++ b/iup/src/gtk/iupgtk_globalattrib.c @@ -0,0 +1,211 @@ +/** \file + * \brief GTK Driver iupdrvSetGlobal + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <string.h> + +#include <gtk/gtk.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvinfo.h" +#include "iup_strmessage.h" + +#include "iupgtk_drv.h" + + +int iupgtk_utf8autoconvert = 1; + +static void gtkGlobalSendKey(int key, int press) +{ + Ihandle* focus; + gint nkeys = 0; + GdkKeymapKey *keys; + GdkEventKey evt; + memset(&evt, 0, sizeof(GdkEventKey)); + evt.send_event = TRUE; + + focus = IupGetFocus(); + if (!focus) + return; + evt.window = focus->handle->window; + + iupgtkKeyEncode(key, &evt.keyval, &evt.state); + if (!evt.keyval) + return; + + if (!gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), evt.keyval, &keys, &nkeys)) + return; + evt.hardware_keycode = (guint16)keys[0].keycode; + evt.group = (guint8)keys[0].group; + + if (press & 0x01) + { + evt.type = GDK_KEY_PRESS; + gdk_display_put_event(gdk_display_get_default(), (GdkEvent*)&evt); + } + + if (press & 0x02) + { + evt.type = GDK_KEY_RELEASE; + gdk_display_put_event(gdk_display_get_default(), (GdkEvent*)&evt); + } +} + +int iupdrvSetGlobal(const char *name, const char *value) +{ + if (iupStrEqual(name, "LANGUAGE")) + { + iupStrMessageUpdateLanguage(value); + return 1; + } + if (iupStrEqual(name, "CURSORPOS")) + { +#if GTK_CHECK_VERSION(2, 8, 0) + int x, y; + if (iupStrToIntInt(value, &x, &y, 'x') == 2) + gdk_display_warp_pointer(gdk_display_get_default(), gdk_screen_get_default(), x, y); +#endif + return 0; + } + if (iupStrEqual(name, "UTF8AUTOCONVERT")) + { + if (!value || iupStrBoolean(value)) + iupgtk_utf8autoconvert = 1; + else + iupgtk_utf8autoconvert = 0; + return 0; + } + if (iupStrEqual(name, "KEYPRESS")) + { + int key; + if (iupStrToInt(value, &key)) + gtkGlobalSendKey(key, 0x01); + return 0; + } + if (iupStrEqual(name, "KEYRELEASE")) + { + int key; + if (iupStrToInt(value, &key)) + gtkGlobalSendKey(key, 0x02); + return 0; + } + if (iupStrEqual(name, "KEY")) + { + int key; + if (iupStrToInt(value, &key)) + gtkGlobalSendKey(key, 0x03); + return 0; + } + return 1; +} + +char *iupdrvGetGlobal(const char *name) +{ + if (iupStrEqual(name, "CURSORPOS")) + { + char *str = iupStrGetMemory(50); + int x, y; + iupdrvGetCursorPos(&x, &y); + sprintf(str, "%dx%d", (int)x, (int)y); + return str; + } + if (iupStrEqual(name, "SHIFTKEY")) + { + char key[5]; + iupdrvGetKeyState(key); + if (key[0] == 'S') + return "ON"; + else + return "OFF"; + } + if (iupStrEqual(name, "CONTROLKEY")) + { + char key[5]; + iupdrvGetKeyState(key); + if (key[1] == 'C') + return "ON"; + else + return "OFF"; + } + if (iupStrEqual(name, "MODKEYSTATE")) + { + char *str = iupStrGetMemory(5); + iupdrvGetKeyState(str); + return str; + } + if (iupStrEqual(name, "SCREENSIZE")) + { + char *str = iupStrGetMemory(50); + int w, h; + iupdrvGetScreenSize(&w, &h); + sprintf(str, "%dx%d", w, h); + return str; + } + if (iupStrEqual(name, "FULLSIZE")) + { + char *str = iupStrGetMemory(50); + int w, h; + iupdrvGetFullSize(&w, &h); + sprintf(str, "%dx%d", w, h); + return str; + } + if (iupStrEqual(name, "SCREENDEPTH")) + { + char *str = iupStrGetMemory(50); + int bpp = iupdrvGetScreenDepth(); + sprintf(str, "%d", bpp); + return str; + } + if (iupStrEqual(name, "VIRTUALSCREEN")) + { + char *str = iupStrGetMemory(50); + GdkScreen *screen = gdk_screen_get_default(); + GdkWindow *root = gdk_screen_get_root_window(gdk_screen_get_default()); + int x = 0; + int y = 0; + int w = gdk_screen_get_width(screen); + int h = gdk_screen_get_height(screen); + gdk_window_get_root_origin(root, &x, &y); + sprintf(str, "%d %d %d %d", x, y, w, h); + return str; + } + if (iupStrEqual(name, "MONITORSINFO")) + { + int i; + GdkScreen *screen = gdk_screen_get_default(); + int monitors_count = gdk_screen_get_n_monitors(screen); + char *str = iupStrGetMemory(monitors_count*50); + char* pstr = str; + GdkRectangle rect; + + for (i=0; i < monitors_count; i++) + { + gdk_screen_get_monitor_geometry(screen, i, &rect); + pstr += sprintf(pstr, "%d %d %d %d\n", rect.x, rect.y, rect.width, rect.height); + } + + return str; + } + if (iupStrEqual(name, "TRUECOLORCANVAS")) + { + if (gdk_visual_get_best_depth() > 8) + return "YES"; + else + return "NO"; + } + if (iupStrEqual(name, "UTF8AUTOCONVERT")) + { + if (iupgtk_utf8autoconvert) + return "YES"; + else + return "NO"; + } + return NULL; +} diff --git a/iup/src/gtk/iupgtk_help.c b/iup/src/gtk/iupgtk_help.c new file mode 100755 index 0000000..270677f --- /dev/null +++ b/iup/src/gtk/iupgtk_help.c @@ -0,0 +1,52 @@ +/** \file + * \brief GTK Driver IupHelp for non Windows systems + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <glib.h> + +#include "iup.h" + +#include "iup_str.h" + +int IupHelp(const char *url) +{ + GError *error = NULL; + gchar *argv[3]; + int ret; + char *browser = getenv("IUP_HELPAPP"); + if (!browser) + browser = IupGetGlobal("HELPAPP"); + + if (!browser) + { + char* system = IupGetGlobal("SYSTEM"); + if (iupStrEqualNoCase(system, "Linux") || + iupStrEqualNoCase(system, "FreeBSD")) + browser = "firefox"; + else if (iupStrEqualNoCase(system, "Darwin")) + browser = "safari"; + else if (iupStrEqualPartial(system, "CYGWIN")) + browser = "iexplore"; + else + browser = "netscape"; + } + + argv[0] = browser; + argv[1] = (gchar*)url; + argv[2] = NULL; + + ret = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error); + + if (error) + g_error_free(error); + + if (!ret) + return -1; + return 1; +} diff --git a/iup/src/gtk/iupgtk_image.c b/iup/src/gtk/iupgtk_image.c new file mode 100755 index 0000000..b261974 --- /dev/null +++ b/iup/src/gtk/iupgtk_image.c @@ -0,0 +1,430 @@ +/** \file + * \brief Image Resource. + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> + +#include <stdio.h> +#include <stdlib.h> +#include <memory.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_image.h" +#include "iup_drvinfo.h" + +#include "iupgtk_drv.h" + + +void iupdrvImageGetRawData(void* handle, unsigned char* imgdata) +{ + GdkPixbuf* pixbuf = (GdkPixbuf*)handle; + int w, h, y, x, bpp; + guchar *pixdata, *pixline_data; + int rowstride, channels, planesize; + unsigned char *r, *g, *b, *a; + + if (!iupdrvImageGetInfo(handle, &w, &h, &bpp)) + return; + + if (bpp==8) + return; + + pixdata = gdk_pixbuf_get_pixels(pixbuf); + rowstride = gdk_pixbuf_get_rowstride(pixbuf); + channels = gdk_pixbuf_get_n_channels(pixbuf); + + /* planes are separated in imgdata */ + planesize = w*h; + r = imgdata; + g = imgdata+planesize; + b = imgdata+2*planesize; + a = imgdata+3*planesize; + for (y=0; y<h; y++) + { + int lineoffset = (h-1 - y)*w; /* imgdata is bottom up */ + pixline_data = pixdata + y * rowstride; + for(x=0;x<w;x++) + { + int pos = x*channels; + r[lineoffset+x] = pixline_data[pos]; + g[lineoffset+x] = pixline_data[pos+1]; + b[lineoffset+x] = pixline_data[pos+2]; + + if (bpp == 32) + a[lineoffset+x] = pixline_data[pos+3]; + } + } +} + +void* iupdrvImageCreateImageRaw(int width, int height, int bpp, iupColor* colors, int colors_count, unsigned char *imgdata) +{ + GdkPixbuf* pixbuf; + guchar *pixdata, *pixline_data; + int rowstride, channels; + unsigned char *line_data; + int x, y, has_alpha = (bpp==32); + (void)colors_count; + + pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8, width, height); + if (!pixbuf) + return NULL; + + pixdata = gdk_pixbuf_get_pixels(pixbuf); + rowstride = gdk_pixbuf_get_rowstride(pixbuf); + channels = gdk_pixbuf_get_n_channels(pixbuf); + + /* GdkPixbuf is top-bottom */ + /* imgdata is bottom up */ + + if (bpp == 8) + { + for (y=0; y<height; y++) + { + pixline_data = pixdata + y * rowstride; + line_data = imgdata + (height-1 - y) * width; /* imgdata is bottom up */ + + for (x=0; x<width; x++) + { + unsigned char index = line_data[x]; + iupColor* c = &colors[index]; + guchar *r = &pixline_data[channels*x], + *g = r+1, + *b = g+1; + + *r = c->r; + *g = c->g; + *b = c->b; + } + } + } + else /* bpp == 32 or bpp == 24 */ + { + /* planes are separated in imgdata */ + int planesize = width*height; + unsigned char *r = imgdata, + *g = imgdata+planesize, + *b = imgdata+2*planesize, + *a = imgdata+3*planesize; + for (y=0; y<height; y++) + { + int lineoffset = (height-1 - y)*width; /* imgdata is bottom up */ + pixline_data = pixdata + y * rowstride; + for(x=0;x<width;x++) + { + int pos = x*channels; + pixline_data[pos] = r[lineoffset+x]; + pixline_data[pos+1] = g[lineoffset+x]; + pixline_data[pos+2] = b[lineoffset+x]; + + if (bpp == 32) + pixline_data[pos+3] = a[lineoffset+x]; + } + } + } + + return pixbuf; +} + +void* iupdrvImageCreateImage(Ihandle *ih, const char* bgcolor, int make_inactive) +{ + GdkPixbuf* pixbuf; + guchar *pixdata, *pixline_data; + int rowstride, channels; + unsigned char *imgdata, *line_data, bg_r=0, bg_g=0, bg_b=0; + int x, y, i, bpp, colors_count = 0, has_alpha = 0; + iupColor colors[256]; + + bpp = iupAttribGetInt(ih, "BPP"); + + if (bpp == 8) + has_alpha = iupImageInitColorTable(ih, colors, &colors_count); + else if (bpp == 32) + has_alpha = 1; + + pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8, ih->currentwidth, ih->currentheight); + if (!pixbuf) + return NULL; + + pixdata = gdk_pixbuf_get_pixels(pixbuf); + rowstride = gdk_pixbuf_get_rowstride(pixbuf); + channels = gdk_pixbuf_get_n_channels(pixbuf); + imgdata = (unsigned char*)iupAttribGetStr(ih, "WID"); + + if (make_inactive) + iupStrToRGB(bgcolor, &bg_r, &bg_g, &bg_b); + + if (bpp == 8) + { + if (make_inactive) + { + for (i=0;i<colors_count;i++) + { + if (colors[i].a == 0) + { + colors[i].r = bg_r; + colors[i].g = bg_g; + colors[i].b = bg_b; + colors[i].a = 255; + } + + iupImageColorMakeInactive(&(colors[i].r), &(colors[i].g), &(colors[i].b), + bg_r, bg_g, bg_b); + } + } + + for (y=0; y<ih->currentheight; y++) + { + pixline_data = pixdata + y * rowstride; + line_data = imgdata + y * ih->currentwidth; + + for (x=0; x<ih->currentwidth; x++) + { + unsigned char index = line_data[x]; + iupColor* c = &colors[index]; + guchar *r = &pixline_data[channels*x], + *g = r+1, + *b = g+1, + *a = b+1; + + *r = c->r; + *g = c->g; + *b = c->b; + + if (has_alpha) + *a = c->a; + } + } + } + else /* bpp == 32 or bpp == 24 */ + { + for (y=0; y<ih->currentheight; y++) + { + pixline_data = pixdata + y * rowstride; + line_data = imgdata + y * ih->currentwidth*channels; + + memcpy(pixline_data, line_data, ih->currentwidth*channels); + + if (make_inactive) + { + for (x=0; x<ih->currentwidth; x++) + { + guchar *r = &pixline_data[channels*x], + *g = r+1, + *b = g+1, + *a = b+1; + + if (has_alpha) + { + if (*a != 255) + { + *r = iupALPHABLEND(*r, bg_r, *a); + *g = iupALPHABLEND(*g, bg_g, *a); + *b = iupALPHABLEND(*b, bg_b, *a); + } + else + *a = 255; + } + + iupImageColorMakeInactive(r, g, b, + bg_r, bg_g, bg_b); + } + } + } + } + + return pixbuf; +} + +void* iupdrvImageCreateIcon(Ihandle *ih) +{ + return iupdrvImageCreateImage(ih, NULL, 0); +} + +void* iupdrvImageCreateCursor(Ihandle *ih) +{ + GdkCursor *cursor; + int hx, hy, bpp; + + hx=0; hy=0; + iupStrToIntInt(iupAttribGet(ih, "HOTSPOT"), &hx, &hy, ':'); + + bpp = iupAttribGetInt(ih, "BPP"); + + if (bpp == 8 && !iupAttribGet(ih, "3")) + { + GdkPixmap *source, *mask; + GdkColor fg, bg; + unsigned char r, g, b; + char *sbits, *mbits, *sb, *mb; + int y, x, line_size = (ih->currentwidth+7)/8; + int size_bytes = line_size*ih->currentheight; + unsigned char* imgdata = (unsigned char*)iupAttribGetStr(ih, "WID"); + + r = 255; g = 255; b = 255; + iupStrToRGB(iupAttribGet(ih, "1"), &r, &g, &b ); + iupgdkColorSet(&fg, r, g, b); + + r = 0; g = 0; b = 0; + iupStrToRGB(iupAttribGet(ih, "2"), &r, &g, &b ); + iupgdkColorSet(&bg, r, g, b); + + sbits = (char*)malloc(2*size_bytes); + if (!sbits) return NULL; + memset(sbits, 0, 2*size_bytes); + mbits = sbits + size_bytes; + + sb = sbits; + mb = mbits; + for (y=0; y<ih->currentheight; y++) + { + for (x=0; x<ih->currentwidth; x++) + { + int byte = x/8; + int bit = x%8; + int index = (int)imgdata[y*ih->currentwidth+x]; + /* index==0 is transparent */ + if (index == 1) + sb[byte] = (char)(sb[byte] | (1<<bit)); + if (index != 0) + mb[byte] = (char)(mb[byte] | (1<<bit)); + } + + sb += line_size; + mb += line_size; + } + + source = gdk_bitmap_create_from_data(NULL, sbits, ih->currentwidth, ih->currentheight); + mask = gdk_bitmap_create_from_data(NULL, mbits, ih->currentwidth, ih->currentheight); + + cursor = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, hx, hy); + + gdk_pixmap_unref(source); + gdk_pixmap_unref(mask); + free(sbits); + } + else + { + GdkPixbuf* pixbuf = iupdrvImageCreateImage(ih, NULL, 0); + cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf, hx, hy); + g_object_unref(pixbuf); + } + + return cursor; +} + +void* iupdrvImageCreateMask(Ihandle *ih) +{ + int bpp; + GdkPixmap *mask; + char *bits, *sb; + int y, x, line_size = (ih->currentwidth+7)/8; + int size_bytes = line_size*ih->currentheight; + unsigned char* imgdata = (unsigned char*)iupAttribGetStr(ih, "WID"); + unsigned char colors[256]; + + bpp = iupAttribGetInt(ih, "BPP"); + if (bpp > 8) + return NULL; + + bits = (char*)malloc(size_bytes); + if (!bits) return NULL; + memset(bits, 0, size_bytes); + + iupImageInitNonBgColors(ih, colors); + + sb = bits; + for (y=0; y<ih->currentheight; y++) + { + for (x=0; x<ih->currentwidth; x++) + { + int byte = x/8; + int bit = x%8; + int index = (int)imgdata[y*ih->currentwidth+x]; + if (colors[index]) + sb[byte] = (char)(sb[byte] | (1<<bit)); + } + + sb += line_size; + } + + mask = gdk_bitmap_create_from_data(NULL, bits, ih->currentwidth, ih->currentheight); + + free(bits); + + return mask; +} + +void* iupdrvImageLoad(const char* name, int type) +{ + if (type == IUPIMAGE_CURSOR) +#if GTK_CHECK_VERSION(2, 8, 0) + return gdk_cursor_new_from_name(gdk_display_get_default(), name); +#else + return NULL; +#endif + else + { + GtkIconTheme *icon_theme; + GdkPixbuf *pixbuf = NULL; + + icon_theme = gtk_icon_theme_get_default(); + if (gtk_icon_theme_has_icon(icon_theme, name)) + { + GError *error = NULL; + pixbuf = gtk_icon_theme_load_icon(icon_theme, name, + 24, /* size */ + 0, /* flags */ + &error); + if (error) + g_error_free(error); + } + + if (!pixbuf) + { + GError *error = NULL; + pixbuf = gdk_pixbuf_new_from_file(name, &error); + if (error) + g_error_free(error); + } + + return pixbuf; + } +} + +int iupdrvImageGetInfo(void* handle, int *w, int *h, int *bpp) +{ + GdkPixbuf* pixbuf = (GdkPixbuf*)handle; + if (!GDK_IS_PIXBUF(pixbuf)) + { + if (w) *w = 0; + if (h) *h = 0; + if (bpp) *bpp = 0; + return 0; + } + if (w) *w = gdk_pixbuf_get_width(pixbuf); + if (h) *h = gdk_pixbuf_get_height(pixbuf); + if (bpp) *bpp = iupImageNormBpp(gdk_pixbuf_get_bits_per_sample(pixbuf)*gdk_pixbuf_get_n_channels(pixbuf)); + return 1; +} + +int iupdrvImageGetRawInfo(void* handle, int *w, int *h, int *bpp, iupColor* colors, int *colors_count) +{ + /* GdkPixbuf are only 24 bpp or 32 bpp */ + (void)colors; + (void)colors_count; + return iupdrvImageGetInfo(handle, w, h, bpp); +} + +void iupdrvImageDestroy(void* handle, int type) +{ + if (type == IUPIMAGE_CURSOR) + gdk_cursor_unref((GdkCursor*)handle); + else + g_object_unref(handle); +} diff --git a/iup/src/gtk/iupgtk_key.c b/iup/src/gtk/iupgtk_key.c new file mode 100755 index 0000000..5aec919 --- /dev/null +++ b/iup/src/gtk/iupgtk_key.c @@ -0,0 +1,422 @@ +/** \file + * \brief GTK Driver keyboard mapping + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> + +#include <stdlib.h> +#include <stdio.h> + +#include "iup.h" +#include "iupcbs.h" +#include "iupkey.h" + +#include "iup_object.h" +#include "iup_key.h" + +#include "iupgtk_drv.h" + + +typedef struct _Igtk2iupkey +{ + guint gtkcode; + int iupcode; + int s_iupcode; + int c_iupcode; + int m_iupcode; + int y_iupcode; +} Igtk2iupkey; + +static Igtk2iupkey gtkkey_map[] = { + +{ GDK_Escape, K_ESC, K_sESC, K_cESC, K_mESC ,K_yESC }, +{ GDK_Pause, K_PAUSE, K_sPAUSE, K_cPAUSE, K_mPAUSE ,K_yPAUSE }, +{ GDK_Print, K_Print, K_sPrint, K_cPrint, K_mPrint ,K_yPrint }, +{ GDK_Menu, K_Menu, K_sMenu, K_cMenu, K_mMenu ,K_yMenu }, + +{ GDK_Home, K_HOME, K_sHOME, K_cHOME, K_mHOME ,K_yHOME }, +{ GDK_Up, K_UP, K_sUP, K_cUP, K_mUP ,K_yUP }, +{ GDK_Prior, K_PGUP, K_sPGUP, K_cPGUP, K_mPGUP ,K_yPGUP }, +{ GDK_Left, K_LEFT, K_sLEFT, K_cLEFT, K_mLEFT ,K_yLEFT }, +{ GDK_Begin, K_MIDDLE,K_sMIDDLE, K_cMIDDLE,K_mMIDDLE,K_yMIDDLE}, +{ GDK_Right, K_RIGHT, K_sRIGHT, K_cRIGHT, K_mRIGHT ,K_yRIGHT }, +{ GDK_End, K_END, K_sEND, K_cEND, K_mEND ,K_yEND }, +{ GDK_Down, K_DOWN, K_sDOWN, K_cDOWN, K_mDOWN ,K_yDOWN }, +{ GDK_Next, K_PGDN, K_sPGDN, K_cPGDN, K_mPGDN ,K_yPGDN }, +{ GDK_Insert, K_INS, K_sINS, K_cINS, K_mINS ,K_yINS }, +{ GDK_Delete, K_DEL, K_sDEL, K_cDEL, K_mDEL ,K_yDEL }, +{ GDK_space, K_SP, K_sSP, K_cSP, K_mSP ,K_ySP }, +{ GDK_Tab, K_TAB, K_sTAB, K_cTAB, K_mTAB ,K_yTAB }, +{ GDK_Return, K_CR, K_sCR, K_cCR, K_mCR ,K_yCR }, +{ GDK_BackSpace, K_BS, K_sBS, K_cBS, K_mBS ,K_yBS }, + +{ GDK_1, K_1, K_exclam, K_c1, K_m1, K_y1 }, +{ GDK_2, K_2, K_at, K_c2, K_m2, K_y2 }, +{ GDK_3, K_3, K_numbersign, K_c3, K_m3, K_y3 }, +{ GDK_4, K_4, K_dollar, K_c4, K_m4, K_y4 }, +{ GDK_5, K_5, K_percent, K_c5, K_m5, K_y5 }, +{ GDK_6, K_6, K_circum, K_c6, K_m6, K_y6 }, +{ GDK_7, K_7, K_ampersand, K_c7, K_m7, K_y7 }, +{ GDK_8, K_8, K_asterisk, K_c8, K_m8, K_y8 }, +{ GDK_9, K_9, K_parentleft, K_c9, K_m9, K_y9 }, +{ GDK_0, K_0, K_parentright, K_c0, K_m0, K_y0 }, + +/* Shift will be flaged so s_iupcode will contain the right code */ +{ GDK_exclam, K_1, K_exclam, K_c1, K_m1, K_y1 }, +{ GDK_at, K_2, K_at, K_c2, K_m2, K_y2 }, +{ GDK_numbersign, K_3, K_numbersign, K_c3, K_m3, K_y3 }, +{ GDK_dollar, K_4, K_dollar, K_c4, K_m4, K_y4 }, +{ GDK_percent, K_5, K_percent, K_c5, K_m5, K_y5 }, +{ GDK_dead_diaeresis, K_6, K_circum, K_c6, K_m6, K_y6 }, +{ GDK_ampersand, K_7, K_ampersand, K_c7, K_m7, K_y7 }, +{ GDK_asterisk, K_8, K_asterisk, K_c8, K_m8, K_y8 }, +{ GDK_parenleft, K_9, K_parentleft, K_c9, K_m9, K_y9 }, +{ GDK_parenright, K_0, K_parentright, K_c0, K_m0, K_y0 }, + +{ GDK_a, K_a, K_A, K_cA, K_mA, K_yA }, +{ GDK_b, K_b, K_B, K_cB, K_mB, K_yB }, +{ GDK_c, K_c, K_C, K_cC, K_mC, K_yC }, +{ GDK_d, K_d, K_D, K_cD, K_mD, K_yD }, +{ GDK_e, K_e, K_E, K_cE, K_mE, K_yE }, +{ GDK_f, K_f, K_F, K_cF, K_mF, K_yF }, +{ GDK_g, K_g, K_G, K_cG, K_mG, K_yG }, +{ GDK_h, K_h, K_H, K_cH, K_mH, K_yH }, +{ GDK_i, K_i, K_I, K_cI, K_mI, K_yI }, +{ GDK_j, K_j, K_J, K_cJ, K_mJ, K_yJ }, +{ GDK_k, K_k, K_K, K_cK, K_mK, K_yK }, +{ GDK_l, K_l, K_L, K_cL, K_mL, K_yL }, +{ GDK_m, K_m, K_M, K_cM, K_mM, K_yM }, +{ GDK_n, K_n, K_N, K_cN, K_mN, K_yN }, +{ GDK_o, K_o, K_O, K_cO, K_mO, K_yO }, +{ GDK_p, K_p, K_P, K_cP, K_mP, K_yP }, +{ GDK_q, K_q, K_Q, K_cQ, K_mQ, K_yQ }, +{ GDK_r, K_r, K_R, K_cR, K_mR, K_yR }, +{ GDK_s, K_s, K_S, K_cS, K_mS, K_yS }, +{ GDK_t, K_t, K_T, K_cT, K_mT, K_yT }, +{ GDK_u, K_u, K_U, K_cU, K_mU, K_yU }, +{ GDK_v, K_v, K_V, K_cV, K_mV, K_yV }, +{ GDK_w, K_w, K_W, K_cW, K_mW, K_yW }, +{ GDK_x, K_x, K_X, K_cX, K_mX, K_yX }, +{ GDK_y, K_y, K_Y, K_cY, K_mY, K_yY }, +{ GDK_z, K_z, K_Z, K_cZ, K_mZ, K_yZ }, + +/* Shift will be flaged so s_iupcode will contain the right code */ +{ GDK_A, K_a, K_A, K_cA, K_mA, K_yA }, +{ GDK_B, K_b, K_B, K_cB, K_mB, K_yB }, +{ GDK_C, K_c, K_C, K_cC, K_mC, K_yC }, +{ GDK_D, K_d, K_D, K_cD, K_mD, K_yD }, +{ GDK_E, K_e, K_E, K_cE, K_mE, K_yE }, +{ GDK_F, K_f, K_F, K_cF, K_mF, K_yF }, +{ GDK_G, K_g, K_G, K_cG, K_mG, K_yG }, +{ GDK_H, K_h, K_H, K_cH, K_mH, K_yH }, +{ GDK_I, K_i, K_I, K_cI, K_mI, K_yI }, +{ GDK_J, K_j, K_J, K_cJ, K_mJ, K_yJ }, +{ GDK_K, K_k, K_K, K_cK, K_mK, K_yK }, +{ GDK_L, K_l, K_L, K_cL, K_mL, K_yL }, +{ GDK_M, K_m, K_M, K_cM, K_mM, K_yM }, +{ GDK_N, K_n, K_N, K_cN, K_mN, K_yN }, +{ GDK_O, K_o, K_O, K_cO, K_mO, K_yO }, +{ GDK_P, K_p, K_P, K_cP, K_mP, K_yP }, +{ GDK_Q, K_q, K_Q, K_cQ, K_mQ, K_yQ }, +{ GDK_R, K_r, K_R, K_cR, K_mR, K_yR }, +{ GDK_S, K_s, K_S, K_cS, K_mS, K_yS }, +{ GDK_T, K_t, K_T, K_cT, K_mT, K_yT }, +{ GDK_U, K_u, K_U, K_cU, K_mU, K_yU }, +{ GDK_V, K_v, K_V, K_cV, K_mV, K_yV }, +{ GDK_W, K_w, K_W, K_cW, K_mW, K_yW }, +{ GDK_X, K_x, K_X, K_cX, K_mX, K_yX }, +{ GDK_Y, K_y, K_Y, K_cY, K_mY, K_yY }, +{ GDK_Z, K_z, K_Z, K_cZ, K_mZ, K_yZ }, + +{ GDK_F1, K_F1, K_sF1, K_cF1, K_mF1, K_yF1 }, +{ GDK_F2, K_F2, K_sF2, K_cF2, K_mF2, K_yF2 }, +{ GDK_F3, K_F3, K_sF3, K_cF3, K_mF3, K_yF3 }, +{ GDK_F4, K_F4, K_sF4, K_cF4, K_mF4, K_yF4 }, +{ GDK_F5, K_F5, K_sF5, K_cF5, K_mF5, K_yF5 }, +{ GDK_F6, K_F6, K_sF6, K_cF6, K_mF6, K_yF6 }, +{ GDK_F7, K_F7, K_sF7, K_cF7, K_mF7, K_yF7 }, +{ GDK_F8, K_F8, K_sF8, K_cF8, K_mF8, K_yF8 }, +{ GDK_F9, K_F9, K_sF9, K_cF9, K_mF9, K_yF9 }, +{ GDK_F10, K_F10, K_sF10, K_cF10, K_mF10, K_yF10 }, +{ GDK_F11, K_F11, K_sF11, K_cF11, K_mF11, K_yF11 }, +{ GDK_F12, K_F12, K_sF12, K_cF12, K_mF12, K_yF12 }, + +{ GDK_semicolon, K_semicolon, K_colon, K_cSemicolon, K_mSemicolon, K_ySemicolon }, +{ GDK_equal, K_equal, K_plus, K_cEqual, K_mEqual, K_yEqual }, +{ GDK_comma, K_comma, K_less, K_cComma, K_mComma, K_yComma }, +{ GDK_minus, K_minus, K_underscore, K_cMinus, K_mMinus, K_yMinus }, +{ GDK_period, K_period, K_greater, K_cPeriod, K_mPeriod, K_yPeriod }, +{ GDK_slash, K_slash, K_question, K_cSlash, K_mSlash, K_ySlash }, +{ GDK_grave, K_grave, K_tilde, 0, 0, 0 }, +{ GDK_bracketleft, K_bracketleft, K_braceleft, K_cBracketleft, K_mBracketleft, K_yBracketleft }, +{ GDK_backslash, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash }, +{ GDK_bracketright,K_bracketright, K_braceright, K_cBracketright,K_mBracketright,K_yBracketright }, +{ GDK_apostrophe, K_apostrophe, K_quotedbl, 0, 0, 0 }, + +/* Shift will be flaged so s_iupcode will contain the right code */ +{ GDK_colon, K_semicolon, K_colon, K_cSemicolon, K_mSemicolon, K_ySemicolon }, +{ GDK_plus, K_equal, K_plus, K_cEqual, K_mEqual, K_yEqual }, +{ GDK_less, K_comma, K_less, K_cComma, K_mComma, K_yComma }, +{ GDK_underscore, K_minus, K_underscore, K_cMinus, K_mMinus, K_yMinus }, +{ GDK_greater, K_period, K_greater, K_cPeriod, K_mPeriod, K_yPeriod }, +{ GDK_question, K_slash, K_question, K_cSlash, K_mSlash, K_ySlash }, +{ GDK_braceleft, K_bracketleft, K_braceleft, K_cBracketleft, K_mBracketleft, K_yBracketleft }, +{ GDK_bar, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash }, +{ GDK_braceright, K_bracketright, K_braceright, K_cBracketright,K_mBracketright,K_yBracketright }, +{ GDK_quotedbl, K_apostrophe, K_quotedbl, 0, 0, 0 }, + +{ GDK_KP_0, K_0, K_0, K_c0, K_m0, K_y0 }, +{ GDK_KP_1, K_1, K_1, K_c1, K_m1, K_y1 }, +{ GDK_KP_2, K_2, K_2, K_c2, K_m2, K_y2 }, +{ GDK_KP_3, K_3, K_3, K_c3, K_m3, K_y3 }, +{ GDK_KP_4, K_4, K_4, K_c4, K_m4, K_y4 }, +{ GDK_KP_5, K_5, K_5, K_c5, K_m5, K_y5 }, +{ GDK_KP_6, K_6, K_6, K_c6, K_m6, K_y6 }, +{ GDK_KP_7, K_7, K_7, K_c7, K_m7, K_y7 }, +{ GDK_KP_8, K_8, K_8, K_c8, K_m8, K_y8 }, +{ GDK_KP_9, K_9, K_9, K_c9, K_m9, K_y9 }, +{ GDK_KP_Multiply, K_asterisk, K_sAsterisk, K_cAsterisk, K_mAsterisk, K_yAsterisk }, +{ GDK_KP_Add, K_plus, K_sPlus, K_cPlus, K_mPlus, K_yPlus }, +{ GDK_KP_Subtract, K_minus, K_sMinus, K_cMinus, K_mMinus, K_yMinus }, +{ GDK_KP_Decimal, K_period, K_sPeriod, K_cPeriod, K_mPeriod, K_yPeriod }, +{ GDK_KP_Divide, K_slash, K_sSlash, K_cSlash, K_mSlash, K_ySlash }, +{ GDK_KP_Separator, K_comma, K_sComma, K_cComma, K_mComma, K_yComma }, + +{ GDK_ccedilla, K_ccedilla, K_Ccedilla, K_cCcedilla, K_mCcedilla, K_yCcedilla }, +{ GDK_Ccedilla, K_ccedilla, K_Ccedilla, K_cCcedilla, K_mCcedilla, K_yCcedilla }, + +{ GDK_dead_tilde, K_tilde, K_circum, 0, 0, 0 }, +{ GDK_dead_acute, K_acute, K_grave, 0, 0, 0 }, +{ GDK_dead_grave, K_grave, K_tilde, 0, 0, 0 }, +{ GDK_dead_circumflex, K_tilde, K_circum, 0, 0, 0 }, + +{ GDK_KP_F1, K_F1, K_sF1, K_cF1, K_mF1, K_yF1 }, +{ GDK_KP_F2, K_F2, K_sF2, K_cF2, K_mF2, K_yF2 }, +{ GDK_KP_F3, K_F3, K_sF3, K_cF3, K_mF3, K_yF3 }, +{ GDK_KP_F4, K_F4, K_sF4, K_cF4, K_mF4, K_yF4 }, +{ GDK_KP_Space, K_SP, K_sSP, K_cSP, K_mSP ,K_ySP }, +{ GDK_KP_Tab, K_TAB, K_sTAB, K_cTAB, K_mTAB ,K_yTAB }, +{ GDK_KP_Equal, K_equal, 0, K_cEqual, K_mEqual, K_yEqual }, + +{ GDK_KP_Enter, K_CR, K_sCR, K_cCR, K_mCR, K_yCR }, +{ GDK_KP_Home, K_HOME, K_sHOME, K_cHOME, K_mHOME, K_yHOME }, +{ GDK_KP_Up, K_UP, K_sUP, K_cUP, K_mUP, K_yUP }, +{ GDK_KP_Page_Up, K_PGUP, K_sPGUP, K_cPGUP, K_mPGUP, K_yPGUP }, +{ GDK_KP_Left, K_LEFT, K_sLEFT, K_cLEFT, K_mLEFT, K_yLEFT }, +{ GDK_KP_Begin, K_MIDDLE,K_sMIDDLE, K_cMIDDLE,K_mMIDDLE,K_yMIDDLE}, +{ GDK_KP_Right, K_RIGHT, K_sRIGHT, K_cRIGHT, K_mRIGHT, K_yRIGHT }, +{ GDK_KP_End, K_END, K_sEND, K_cEND, K_mEND, K_yEND }, +{ GDK_KP_Down, K_DOWN, K_sDOWN, K_cDOWN, K_mDOWN, K_yDOWN }, +{ GDK_KP_Page_Down, K_PGDN, K_sPGDN, K_cPGDN, K_mPGDN, K_yPGDN }, +{ GDK_KP_Insert, K_INS, K_sINS, K_cINS, K_mINS, K_yINS }, +{ GDK_KP_Delete, K_DEL, K_sDEL, K_cDEL, K_mDEL, K_yDEL } + +}; + +void iupgtkKeyEncode(int key, guint *keyval, guint *state) +{ + int i, iupcode = key & 0xFF; /* 0-255 interval */ + int count = sizeof(gtkkey_map)/sizeof(gtkkey_map[0]); + for (i = 0; i < count; i++) + { + Igtk2iupkey* key_map = &(gtkkey_map[i]); + if (key_map->iupcode == iupcode) + { + *keyval = key_map->gtkcode; + *state = 0; + + if (iupcode != key) + { + if (key_map->c_iupcode == key) + *state = GDK_CONTROL_MASK; + else if (key_map->m_iupcode == key) + *state = GDK_MOD1_MASK; + else if (key_map->y_iupcode == key) + *state = GDK_MOD4_MASK; + else if (key_map->s_iupcode == key) + *state = GDK_SHIFT_MASK; + } + return; + } + else if (key_map->s_iupcode == key) /* There are Shift keys bellow 256 */ + { + *keyval = key_map->gtkcode; + *state = GDK_SHIFT_MASK; + + if ((*keyval >= GDK_a) && + (*keyval <= GDK_z)) + { + /* remap to upper case */ + *keyval -= GDK_a-GDK_A; + } + return; + } + } +} + +static int gtkKeyMap2Iup(int state, int i) +{ + int code = 0; + if (state & GDK_CONTROL_MASK) /* Ctrl */ + code = gtkkey_map[i].c_iupcode; + else if (state & GDK_MOD1_MASK || + state & GDK_MOD5_MASK) /* Alt */ + code = gtkkey_map[i].m_iupcode; + else if (state & GDK_MOD4_MASK) /* Apple/Win */ + code = gtkkey_map[i].y_iupcode; + else if (state & GDK_LOCK_MASK) /* CapsLock */ + { + if ((state & GDK_SHIFT_MASK) || !iupKeyCanCaps(gtkkey_map[i].iupcode)) + return gtkkey_map[i].iupcode; + else + code = gtkkey_map[i].s_iupcode; + } + else if (state & GDK_SHIFT_MASK) /* Shift */ + code = gtkkey_map[i].s_iupcode; + else + return gtkkey_map[i].iupcode; + + if (!code) + code = gtkkey_map[i].iupcode; + + return code; +} + +static int gtkKeyDecode(GdkEventKey *evt) +{ + int i; + int count = sizeof(gtkkey_map)/sizeof(gtkkey_map[0]); + guint keyval = evt->keyval; + + if ((evt->state & GDK_MOD2_MASK) && /* NumLock */ + (keyval >= GDK_KP_Home) && + (keyval <= GDK_KP_Delete)) + { + /* remap to numeric keys */ + guint remap_numkey[] = {GDK_KP_7, GDK_KP_4, GDK_KP_8, GDK_KP_6, GDK_KP_2, GDK_KP_9, GDK_KP_3, GDK_KP_1, GDK_KP_5, GDK_KP_0, GDK_KP_Decimal}; + keyval = remap_numkey[keyval-GDK_KP_Home]; + } + + for (i = 0; i < count; i++) + { + if (gtkkey_map[i].gtkcode == keyval) + return gtkKeyMap2Iup(evt->state, i); + } + + return 0; +} + +gboolean iupgtkKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) +{ + int result; + int code = gtkKeyDecode(evt); + if (code == 0) + return FALSE; + + /* Avoid duplicate calls if a child of the dialog contains the focus. + GTK will call the callback for the child and for the dialog */ + if (ih->iclass->nativetype == IUP_TYPEDIALOG && ih != IupGetFocus()) + return FALSE; + + result = iupKeyCallKeyCb(ih, code); + if (result == IUP_CLOSE) + { + IupExitLoop(); + return FALSE; + } + if (result == IUP_IGNORE) + return TRUE; + + /* in the previous callback the dialog could be destroyed */ + if (iupObjectCheck(ih)) + { + /* this is called only for canvas */ + if (ih->iclass->nativetype == IUP_TYPECANVAS) + { + result = iupKeyCallKeyPressCb(ih, code, 1); + if (result == IUP_CLOSE) + { + IupExitLoop(); + return FALSE; + } + if (result == IUP_IGNORE) + return TRUE; + } + + if (!iupKeyProcessNavigation(ih, code, evt->state & GDK_SHIFT_MASK)) + return TRUE; + + /* compensate the show-help limitation. + * It is not called on F1, only on Shift+F1 and Ctrl+F1. */ + if (code == K_F1) + { + Icallback cb = IupGetCallback(ih, "HELP_CB"); + if (cb) + { + if (cb(ih) == IUP_CLOSE) + IupExitLoop(); + } + } + } + + (void)widget; + return FALSE; +} + +gboolean iupgtkKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) +{ + /* this is called only for canvas */ + int result; + int code = gtkKeyDecode(evt); + if (code == 0) + return FALSE; + + result = iupKeyCallKeyPressCb(ih, code, 0); + if (result == IUP_CLOSE) + { + IupExitLoop(); + return FALSE; + } + if (result == IUP_IGNORE) + return TRUE; + + (void)widget; + return FALSE; +} + +void iupgtkButtonKeySetStatus(guint state, unsigned int but, char* status, int doubleclick) +{ + if (state & GDK_SHIFT_MASK) + iupKEYSETSHIFT(status); + + if (state & GDK_CONTROL_MASK) + iupKEYSETCONTROL(status); + + if ((state & GDK_BUTTON1_MASK) || but==1) + iupKEYSETBUTTON1(status); + + if ((state & GDK_BUTTON2_MASK) || but==2) + iupKEYSETBUTTON2(status); + + if ((state & GDK_BUTTON3_MASK) || but==3) + iupKEYSETBUTTON3(status); + + if ((state & GDK_BUTTON4_MASK) || but==4) + iupKEYSETBUTTON4(status); + + if ((state & GDK_BUTTON5_MASK) || but==5) + iupKEYSETBUTTON5(status); + + if (state & GDK_MOD1_MASK || state & GDK_MOD5_MASK) /* Alt */ + iupKEYSETALT(status); + + if (state & GDK_MOD4_MASK) /* Apple/Win */ + iupKEYSETSYS(status); + + if (doubleclick) + iupKEYSETDOUBLE(status); +} + diff --git a/iup/src/gtk/iupgtk_label.c b/iup/src/gtk/iupgtk_label.c new file mode 100755 index 0000000..49d5c6d --- /dev/null +++ b/iup/src/gtk/iupgtk_label.c @@ -0,0 +1,318 @@ +/** \file + * \brief Label Control + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_image.h" +#include "iup_label.h" +#include "iup_drv.h" +#include "iup_image.h" +#include "iup_focus.h" + +#include "iupgtk_drv.h" + + +static int gtkLabelSetTitleAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_LABEL_TEXT) + { + GtkLabel* label = (GtkLabel*)ih->handle; + if (iupgtkSetMnemonicTitle(ih, label, value)) + { + Ihandle* next = iupFocusNextInteractive(ih); + if (next) + { + if (next->handle) + gtk_label_set_mnemonic_widget(label, next->handle); + else + iupAttribSetStr(next, "_IUPGTK_LABELMNEMONIC", (char*)label); /* used by iupgtkUpdateMnemonic */ + } + } + return 1; + } + + return 0; +} + +static int gtkLabelSetWordWrapAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_LABEL_TEXT) + { + GtkLabel* label = (GtkLabel*)ih->handle; + if (iupStrBoolean(value)) + gtk_label_set_line_wrap(label, TRUE); + else + gtk_label_set_line_wrap(label, FALSE); + return 1; + } + return 0; +} + +static int gtkLabelSetEllipsisAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_LABEL_TEXT) + { +#if GTK_CHECK_VERSION(2, 6, 0) + GtkLabel* label = (GtkLabel*)ih->handle; + if (iupStrBoolean(value)) + gtk_label_set_ellipsize(label, PANGO_ELLIPSIZE_END); + else + gtk_label_set_ellipsize(label, PANGO_ELLIPSIZE_NONE); +#endif + return 1; + } + return 0; +} + +static int gtkLabelSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT) + { + GtkMisc* misc = (GtkMisc*)ih->handle; + PangoAlignment alignment; + float xalign, yalign; + char value1[30]="", value2[30]=""; + + iupStrToStrStr(value, value1, value2, ':'); + + if (iupStrEqualNoCase(value1, "ARIGHT")) + { + xalign = 1.0f; + alignment = PANGO_ALIGN_RIGHT; + } + else if (iupStrEqualNoCase(value1, "ACENTER")) + { + xalign = 0.5f; + alignment = PANGO_ALIGN_CENTER; + } + else /* "ALEFT" */ + { + xalign = 0; + alignment = PANGO_ALIGN_LEFT; + } + + if (iupStrEqualNoCase(value2, "ABOTTOM")) + yalign = 1.0f; + else if (iupStrEqualNoCase(value2, "ATOP")) + yalign = 0; + else /* ACENTER (default) */ + yalign = 0.5f; + + gtk_misc_set_alignment(misc, xalign, yalign); + + if (ih->data->type == IUP_LABEL_TEXT) + pango_layout_set_alignment(gtk_label_get_layout((GtkLabel*)ih->handle), alignment); + + return 1; + } + else + return 0; +} + +static int gtkLabelSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + + if (ih->handle && ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT) + { + GtkMisc* misc = (GtkMisc*)ih->handle; + gtk_misc_set_padding(misc, ih->data->horiz_padding, ih->data->vert_padding); + } + return 0; +} + +static char* gtkLabelGetPangoLayoutAttrib(Ihandle* ih) +{ + if (ih->data->type == IUP_LABEL_TEXT) + return (char*)gtk_label_get_layout((GtkLabel*)ih->handle); + else + return NULL; +} + +static void gtkLabelSetPixbuf(Ihandle* ih, const char* name, int make_inactive) +{ + GtkImage* image_label = (GtkImage*)ih->handle; + + if (name) + { + GdkPixbuf* pixbuf = iupImageGetImage(name, ih, make_inactive); + GdkPixbuf* old_pixbuf = gtk_image_get_pixbuf(image_label); + if (pixbuf != old_pixbuf) + gtk_image_set_from_pixbuf(image_label, pixbuf); + return; + } + + /* if not defined */ +#if GTK_CHECK_VERSION(2, 8, 0) + gtk_image_clear(image_label); +#endif +} + +static int gtkLabelSetImageAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_LABEL_IMAGE) + { + if (iupdrvIsActive(ih)) + gtkLabelSetPixbuf(ih, value, 0); + else + { + if (!iupAttribGet(ih, "IMINACTIVE")) + { + /* if not active and IMINACTIVE is not defined + then automaticaly create one based on IMAGE */ + gtkLabelSetPixbuf(ih, value, 1); /* make_inactive */ + } + } + return 1; + } + else + return 0; +} + +static int gtkLabelSetImInactiveAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_LABEL_IMAGE) + { + if (!iupdrvIsActive(ih)) + { + if (value) + gtkLabelSetPixbuf(ih, value, 0); + else + { + /* if not defined then automaticaly create one based on IMAGE */ + char* name = iupAttribGet(ih, "IMAGE"); + gtkLabelSetPixbuf(ih, name, 1); /* make_inactive */ + } + } + return 1; + } + else + return 0; +} + +static int gtkLabelSetActiveAttrib(Ihandle* ih, const char* value) +{ + /* update the inactive image if necessary */ + if (ih->data->type == IUP_LABEL_IMAGE) + { + if (!iupStrBoolean(value)) + { + char* name = iupAttribGet(ih, "IMINACTIVE"); + if (name) + gtkLabelSetPixbuf(ih, name, 0); + else + { + /* if not defined then automaticaly create one based on IMAGE */ + name = iupAttribGet(ih, "IMAGE"); + gtkLabelSetPixbuf(ih, name, 1); /* make_inactive */ + } + } + else + { + /* must restore the normal image */ + char* name = iupAttribGet(ih, "IMAGE"); + gtkLabelSetPixbuf(ih, name, 0); + } + } + + return iupBaseSetActiveAttrib(ih, value); +} + +static int gtkLabelMapMethod(Ihandle* ih) +{ + char* value; + GtkWidget *label; + + value = iupAttribGet(ih, "SEPARATOR"); + if (value) + { + if (iupStrEqualNoCase(value, "HORIZONTAL")) + { + ih->data->type = IUP_LABEL_SEP_HORIZ; + label = gtk_hseparator_new(); + } + else /* "VERTICAL" */ + { + ih->data->type = IUP_LABEL_SEP_VERT; + label = gtk_vseparator_new(); + } + } + else + { + value = iupAttribGet(ih, "IMAGE"); + if (value) + { + ih->data->type = IUP_LABEL_IMAGE; + label = gtk_image_new(); + } + else + { + ih->data->type = IUP_LABEL_TEXT; + label = gtk_label_new(NULL); + } + } + + if (!label) + return IUP_ERROR; + + ih->handle = label; + + /* add to the parent, all GTK controls must call this. */ + iupgtkBaseAddToParent(ih); + + gtk_widget_realize(label); + + return IUP_NOERROR; +} + +void iupdrvLabelInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkLabelMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Common GTK only (when text is in a secondary element) */ + iupClassRegisterAttribute(ic, "PANGOLAYOUT", gtkLabelGetPangoLayoutAttrib, NULL, NULL, NULL, IUPAF_NO_INHERIT); + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, gtkLabelSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "TITLE", NULL, gtkLabelSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupLabel only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, gtkLabelSetAlignmentAttrib, "ALEFT:ACENTER", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkLabelSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PADDING", iupLabelGetPaddingAttrib, gtkLabelSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + + /* IupLabel GTK and Motif only */ + iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, gtkLabelSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupLabel Windows and GTK only */ + iupClassRegisterAttribute(ic, "WORDWRAP", NULL, gtkLabelSetWordWrapAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "ELLIPSIS", NULL, gtkLabelSetEllipsisAttrib, NULL, NULL, IUPAF_DEFAULT); + + /* IupLabel GTK only */ + iupClassRegisterAttribute(ic, "MARKUP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT); +} diff --git a/iup/src/gtk/iupgtk_list.c b/iup/src/gtk/iupgtk_list.c new file mode 100755 index 0000000..80f6cce --- /dev/null +++ b/iup/src/gtk/iupgtk_list.c @@ -0,0 +1,1439 @@ +/** \file + * \brief List Control + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_mask.h" +#include "iup_key.h" +#include "iup_list.h" + +#include "iupgtk_drv.h" + + +static void gtkListSelectionChanged(GtkTreeSelection* selection, Ihandle* ih); +static void gtkListComboBoxChanged(GtkComboBox* widget, Ihandle* ih); + + +void iupdrvListAddItemSpace(Ihandle* ih, int *h) +{ + (void)ih; + *h += 3; +} + +void iupdrvListAddBorders(Ihandle* ih, int *x, int *y) +{ + int border_size = 2*5; + (*x) += border_size; + (*y) += border_size; + + if (ih->data->is_dropdown) + { +#ifdef HILDON + (*x) += 9; /* extra space for the dropdown button */ +#else + (*x) += 5; /* extra space for the dropdown button */ +#endif + + if (ih->data->has_editbox) + (*x) += 5; /* another extra space for the dropdown button */ + else + { + (*y) += 4; /* extra padding space */ + (*x) += 4; /* extra padding space */ + } + } + else + { + if (ih->data->has_editbox) + (*y) += 2*3; /* internal border between editbox and list */ + } +} + +static int gtkListConvertXYToPos(Ihandle* ih, int x, int y) +{ + if (!ih->data->is_dropdown) + { + GtkTreePath* path; + if (gtk_tree_view_get_dest_row_at_pos((GtkTreeView*)ih->handle, x, y, &path, NULL)) + { + int* indices = gtk_tree_path_get_indices(path); + int pos = indices[0]+1; /* IUP starts at 1 */ + gtk_tree_path_free (path); + return pos; + } + } + + return -1; +} + +static GtkTreeModel* gtkListGetModel(Ihandle* ih) +{ + if (ih->data->is_dropdown) + return gtk_combo_box_get_model((GtkComboBox*)ih->handle); + else + return gtk_tree_view_get_model((GtkTreeView*)ih->handle); +} + +int iupdrvListGetCount(Ihandle* ih) +{ + GtkTreeModel *model = gtkListGetModel(ih); + return gtk_tree_model_iter_n_children(model, NULL); +} + +void iupdrvListAppendItem(Ihandle* ih, const char* value) +{ + GtkTreeModel *model = gtkListGetModel(ih); + GtkTreeIter iter; + gtk_list_store_append(GTK_LIST_STORE(model), &iter); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, iupgtkStrConvertToUTF8(value), -1); +} + +void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value) +{ + GtkTreeModel *model = gtkListGetModel(ih); + GtkTreeIter iter; + gtk_list_store_insert(GTK_LIST_STORE(model), &iter, pos); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, iupgtkStrConvertToUTF8(value), -1); +} + +void iupdrvListRemoveItem(Ihandle* ih, int pos) +{ + GtkTreeModel *model = gtkListGetModel(ih); + GtkTreeIter iter; + if (gtk_tree_model_iter_nth_child(model, &iter, NULL, pos)) + { + if (ih->data->is_dropdown && !ih->data->has_editbox) + { + /* must check if removing the current item */ + int curpos = gtk_combo_box_get_active((GtkComboBox*)ih->handle); + if (pos == curpos) + { + if (curpos > 0) curpos--; + else curpos++; + + gtk_combo_box_set_active((GtkComboBox*)ih->handle, curpos); + } + } + + gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + } +} + +void iupdrvListRemoveAllItems(Ihandle* ih) +{ + GtkTreeModel *model = gtkListGetModel(ih); + gtk_list_store_clear(GTK_LIST_STORE(model)); +} + + +/*********************************************************************************/ + + +static int gtkListSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + iupdrvSetStandardFontAttrib(ih, value); + + if (ih->handle) + { + if (ih->data->is_dropdown) + { + GtkCellRenderer* renderer = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER"); + if (renderer) + { + g_object_set(G_OBJECT(renderer), "font-desc", (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih), NULL); + iupgtkFontUpdateObjectPangoLayout(ih, G_OBJECT(renderer)); + } + } + + if (ih->data->has_editbox) + { + GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + gtk_widget_modify_font((GtkWidget*)entry, (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih)); + iupgtkFontUpdatePangoLayout(ih, gtk_entry_get_layout(entry)); + } + } + return 1; +} + +static char* gtkListGetIdValueAttrib(Ihandle* ih, const char* name_id) +{ + int pos = iupListGetPos(ih, name_id); + if (pos != -1) + { + GtkTreeIter iter; + GtkTreeModel* model = gtkListGetModel(ih); + if (gtk_tree_model_iter_nth_child(model, &iter, NULL, pos)) + { + gchar *text = NULL; + gtk_tree_model_get(model, &iter, 0, &text, -1); + if (text) + { + char* ret_str = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(text)); + g_free(text); + return ret_str; + } + } + } + return NULL; +} + +static int gtkListSetBgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + + GtkScrolledWindow* scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (scrolled_window && !ih->data->is_dropdown) + { + /* ignore given value, must use only from parent for the scrollbars */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + if (iupStrToRGB(parent_value, &r, &g, &b)) + { + GtkWidget* sb; + + if (!GTK_IS_SCROLLED_WINDOW(scrolled_window)) + scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUPGTK_SCROLLED_WINDOW"); + + iupgtkBaseSetBgColor((GtkWidget*)scrolled_window, r, g, b); + +#if GTK_CHECK_VERSION(2, 8, 0) + sb = gtk_scrolled_window_get_hscrollbar(scrolled_window); + if (sb) iupgtkBaseSetBgColor(sb, r, g, b); + + sb = gtk_scrolled_window_get_vscrollbar(scrolled_window); + if (sb) iupgtkBaseSetBgColor(sb, r, g, b); +#endif + } + } + + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + if (ih->data->has_editbox) + { + GtkWidget* entry = (GtkWidget*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + iupgtkBaseSetBgColor(entry, r, g, b); + } + + { + GtkCellRenderer* renderer = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER"); + if (renderer) + { + GdkColor color; + iupgdkColorSet(&color, r, g, b); + g_object_set(G_OBJECT(renderer), "cell-background-gdk", &color, NULL); + } + } + + return iupdrvBaseSetBgColorAttrib(ih, value); +} + +static int gtkListSetFgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + iupgtkBaseSetFgColor(ih->handle, r, g, b); + + if (ih->data->has_editbox) + { + GtkWidget* entry = (GtkWidget*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + iupgtkBaseSetFgColor(entry, r, g, b); + } + + { + GtkCellRenderer* renderer = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER"); + if (renderer) + { + GdkColor color; + iupgdkColorSet(&color, r, g, b); + g_object_set(G_OBJECT(renderer), "foreground-gdk", &color, NULL); + } + } + + return 1; +} + +static char* gtkListGetValueAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + return iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_entry_get_text(entry))); + } + else + { + if (ih->data->is_dropdown) + { + int pos = gtk_combo_box_get_active((GtkComboBox*)ih->handle); + char* str = iupStrGetMemory(50); + sprintf(str, "%d", pos+1); /* IUP starts at 1 */ + return str; + } + else + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + if (!ih->data->is_multiple) + { + GtkTreeIter iter; + GtkTreeModel* tree_model; + if (gtk_tree_selection_get_selected(selection, &tree_model, &iter)) + { + char* str; + GtkTreePath *path = gtk_tree_model_get_path(tree_model, &iter); + int* indices = gtk_tree_path_get_indices(path); + str = iupStrGetMemory(50); + sprintf(str, "%d", indices[0]+1); /* IUP starts at 1 */ + gtk_tree_path_free (path); + return str; + } + } + else + { + GList *il, *list = gtk_tree_selection_get_selected_rows(selection, NULL); + int count = iupdrvListGetCount(ih); + char* str = iupStrGetMemory(count+1); + memset(str, '-', count); + str[count]=0; + for (il=list; il; il=il->next) + { + GtkTreePath* path = (GtkTreePath*)il->data; + int* indices = gtk_tree_path_get_indices(path); + str[indices[0]] = '+'; + gtk_tree_path_free(path); + } + g_list_free(list); + return str; + } + } + } + + return NULL; +} + +static int gtkListSetValueAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->has_editbox) + { + GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + if (!value) value = ""; + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + gtk_entry_set_text(entry, iupgtkStrConvertToUTF8(value)); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + } + else + { + if (ih->data->is_dropdown) + { + int pos; + GtkTreeModel *model = gtkListGetModel(ih); + g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkListComboBoxChanged), ih); + if (iupStrToInt(value, &pos)==1 && + (pos>0 && pos<gtk_tree_model_iter_n_children(model, NULL))) + { + gtk_combo_box_set_active((GtkComboBox*)ih->handle, pos-1); /* IUP starts at 1 */ + iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos); + } + else + { + gtk_combo_box_set_active((GtkComboBox*)ih->handle, -1); /* none */ + iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); + } + g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkListComboBoxChanged), ih); + } + else + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + if (!ih->data->is_multiple) + { + int pos; + g_signal_handlers_block_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih); + if (iupStrToInt(value, &pos)==1) + { + GtkTreePath* path = gtk_tree_path_new_from_indices(pos-1, -1); /* IUP starts at 1 */ + gtk_tree_selection_select_path(selection, path); + gtk_tree_path_free(path); + iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos); + } + else + { + gtk_tree_selection_unselect_all(selection); + iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); + } + g_signal_handlers_unblock_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih); + } + else + { + /* User has changed a multiple selection on a simple list. */ + int i, len, count; + + g_signal_handlers_block_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih); + + /* Clear all selections */ + gtk_tree_selection_unselect_all(selection); + + if (!value) + { + iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); + return 0; + } + + len = strlen(value); + count = iupdrvListGetCount(ih); + if (len < count) + count = len; + + /* update selection list */ + for (i = 0; i<count; i++) + { + if (value[i]=='+') + { + GtkTreePath* path = gtk_tree_path_new_from_indices(i, -1); + gtk_tree_selection_select_path(selection, path); + gtk_tree_path_free(path); + } + } + iupAttribStoreStr(ih, "_IUPLIST_OLDVALUE", value); + g_signal_handlers_unblock_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih); + } + } + } + + return 0; +} + +static int gtkListSetShowDropdownAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->is_dropdown) + { + if (iupStrBoolean(value)) + gtk_combo_box_popup((GtkComboBox*)ih->handle); + else + gtk_combo_box_popdown((GtkComboBox*)ih->handle); + } + return 0; +} + +static int gtkListSetTopItemAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->is_dropdown) + { + int pos = 1; + if (iupStrToInt(value, &pos)) + { + GtkTreePath* path = gtk_tree_path_new_from_indices(pos-1, -1); /* IUP starts at 1 */ + gtk_tree_view_scroll_to_cell((GtkTreeView*)ih->handle, path, NULL, FALSE, 0, 0); + gtk_tree_path_free(path); + } + } + return 0; +} + +static int gtkListSetSpacingAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->is_dropdown) + return 0; + + if (!iupStrToInt(value, &ih->data->spacing)) + ih->data->spacing = 0; + + if (ih->handle) + { + GtkCellRenderer* renderer = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER"); + if (renderer) + g_object_set(G_OBJECT(renderer), "xpad", ih->data->spacing, + "ypad", ih->data->spacing, + NULL); + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ +} + +static int gtkListSetPaddingAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->has_editbox) + return 0; + + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle) + { +#if GTK_CHECK_VERSION(2, 10, 0) + GtkEntry* entry; + GtkBorder border; + border.bottom = border.top = ih->data->vert_padding; + border.left = border.right = ih->data->horiz_padding; + entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + gtk_entry_set_inner_border(entry, &border); +#endif + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ +} + +static int gtkListSetSelectionAttrib(Ihandle* ih, const char* value) +{ + int start=1, end=1; + GtkEntry* entry; + if (!ih->data->has_editbox) + return 0; + if (!value) + return 0; + + entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + if (!value || iupStrEqualNoCase(value, "NONE")) + { + gtk_editable_select_region(GTK_EDITABLE(entry), 0, 0); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1); + return 0; + } + + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<1 || end<1) + return 0; + + start--; /* IUP starts at 1 */ + end--; + + gtk_editable_select_region(GTK_EDITABLE(entry), start, end); + + return 0; +} + +static char* gtkListGetSelectionAttrib(Ihandle* ih) +{ + char *str; + int start, end; + GtkEntry* entry; + if (!ih->data->has_editbox) + return NULL; + + entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + if (gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end)) + { + start++; /* IUP starts at 1 */ + end++; + str = iupStrGetMemory(100); + sprintf(str, "%d:%d", (int)start, (int)end); + return str; + } + + return NULL; +} + +static int gtkListSetSelectionPosAttrib(Ihandle* ih, const char* value) +{ + int start=0, end=0; + GtkEntry* entry; + if (!ih->data->has_editbox) + return 0; + if (!value) + return 0; + + entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + if (!value || iupStrEqualNoCase(value, "NONE")) + { + gtk_editable_select_region(GTK_EDITABLE(entry), 0, 0); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1); + return 0; + } + + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<0 || end<0) + return 0; + + gtk_editable_select_region(GTK_EDITABLE(entry), start, end); + + return 0; +} + +static char* gtkListGetSelectionPosAttrib(Ihandle* ih) +{ + int start, end; + char *str; + GtkEntry* entry; + if (!ih->data->has_editbox) + return NULL; + + entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + if (gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end)) + { + str = iupStrGetMemory(100); + sprintf(str, "%d:%d", (int)start, (int)end); + return str; + } + + return NULL; +} + +static int gtkListSetSelectedTextAttrib(Ihandle* ih, const char* value) +{ + int start, end; + GtkEntry* entry; + if (!ih->data->has_editbox) + return 0; + if (!value) + return 0; + + entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + if (gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end)) + { + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + gtk_editable_delete_selection(GTK_EDITABLE(entry)); + gtk_editable_insert_text(GTK_EDITABLE(entry), iupgtkStrConvertToUTF8(value), -1, &start); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + } + + return 0; +} + +static char* gtkListGetSelectedTextAttrib(Ihandle* ih) +{ + int start, end; + GtkEntry* entry; + if (!ih->data->has_editbox) + return NULL; + + entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + if (gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), &start, &end)) + { + char* selectedtext = gtk_editable_get_chars(GTK_EDITABLE(entry), start, end); + char* str = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(selectedtext)); + g_free(selectedtext); + return str; + } + + return NULL; +} + +static int gtkListSetCaretAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + GtkEntry* entry; + if (!ih->data->has_editbox) + return 0; + if (!value) + return 0; + + sscanf(value,"%i",&pos); + pos--; /* IUP starts at 1 */ + if (pos < 0) pos = 0; + + entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + gtk_editable_set_position(GTK_EDITABLE(entry), pos); + + return 0; +} + +static char* gtkListGetCaretAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + char* str = iupStrGetMemory(50); + GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + int pos = gtk_editable_get_position(GTK_EDITABLE(entry)); + pos++; /* IUP starts at 1 */ + sprintf(str, "%d", (int)pos); + return str; + } + else + return NULL; +} + +static int gtkListSetCaretPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + GtkEntry* entry; + if (!ih->data->has_editbox) + return 0; + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + gtk_editable_set_position(GTK_EDITABLE(entry), pos); + + return 0; +} + +static char* gtkListGetCaretPosAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + char* str = iupStrGetMemory(50); + GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + int pos = gtk_editable_get_position(GTK_EDITABLE(entry)); + sprintf(str, "%d", (int)pos); + return str; + } + else + return NULL; +} + +static int gtkListSetScrollToAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + GtkEntry* entry; + if (!ih->data->has_editbox) + return 0; + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 1) pos = 1; + pos--; /* return to GTK referece */ + + entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + gtk_editable_set_position(GTK_EDITABLE(entry), pos); + + return 0; +} + +static int gtkListSetScrollToPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + GtkEntry* entry; + if (!ih->data->has_editbox) + return 0; + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + gtk_editable_set_position(GTK_EDITABLE(entry), pos); + + return 0; +} + +static int gtkListSetInsertAttrib(Ihandle* ih, const char* value) +{ + gint pos; + GtkEntry* entry; + if (!ih->data->has_editbox) + return 0; + if (!value) + return 0; + + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); /* disable callbacks */ + entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + pos = gtk_editable_get_position(GTK_EDITABLE(entry)); + gtk_editable_insert_text(GTK_EDITABLE(entry), iupgtkStrConvertToUTF8(value), -1, &pos); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + + return 0; +} + +static int gtkListSetAppendAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->has_editbox) + { + GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + gint pos = strlen(gtk_entry_get_text(entry))+1; + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); /* disable callbacks */ + gtk_editable_insert_text(GTK_EDITABLE(entry), iupgtkStrConvertToUTF8(value), -1, &pos); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + } + return 0; +} + +static int gtkListSetNCAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->has_editbox) + return 0; + + if (!iupStrToInt(value, &ih->data->nc)) + ih->data->nc = INT_MAX; + + if (ih->handle) + { + GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + gtk_entry_set_max_length(entry, ih->data->nc); + } + + return 0; +} + +static int gtkListSetClipboardAttrib(Ihandle *ih, const char *value) +{ + GtkEntry* entry; + if (!ih->data->has_editbox) + return 0; + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + if (iupStrEqualNoCase(value, "COPY")) + gtk_editable_copy_clipboard(GTK_EDITABLE(entry)); + else if (iupStrEqualNoCase(value, "CUT")) + gtk_editable_cut_clipboard(GTK_EDITABLE(entry)); + else if (iupStrEqualNoCase(value, "PASTE")) + gtk_editable_paste_clipboard(GTK_EDITABLE(entry)); + else if (iupStrEqualNoCase(value, "CLEAR")) + gtk_editable_delete_selection(GTK_EDITABLE(entry)); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + return 0; +} + +static int gtkListSetReadOnlyAttrib(Ihandle* ih, const char* value) +{ + GtkEntry* entry; + if (!ih->data->has_editbox) + return 0; + entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + gtk_editable_set_editable(GTK_EDITABLE(entry), !iupStrBoolean(value)); + return 0; +} + +static char* gtkListGetReadOnlyAttrib(Ihandle* ih) +{ + GtkEntry* entry; + if (!ih->data->has_editbox) + return NULL; + entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + if (!gtk_editable_get_editable(GTK_EDITABLE(entry))) + return "YES"; + else + return "NO"; +} + + +/*********************************************************************************/ + + +static void gtkListEditMoveCursor(GtkWidget* entry, GtkMovementStep step, gint count, gboolean extend_selection, Ihandle* ih) +{ + int pos; + + IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB"); + if (!cb) return; + + pos = gtk_editable_get_position(GTK_EDITABLE(entry)); + + if (pos != ih->data->last_caret_pos) + { + ih->data->last_caret_pos = pos; + + cb(ih, 1, pos+1, pos); + } + + (void)step; + (void)count; + (void)extend_selection; +} + +static gboolean gtkListEditKeyPressEvent(GtkWidget* entry, GdkEventKey *evt, Ihandle *ih) +{ + if (iupgtkKeyPressEvent(entry, evt, ih) == TRUE) + return TRUE; + + if ((evt->keyval == GDK_Up || evt->keyval == GDK_KP_Up) || + (evt->keyval == GDK_Prior || evt->keyval == GDK_KP_Page_Up) || + (evt->keyval == GDK_Down || evt->keyval == GDK_KP_Down) || + (evt->keyval == GDK_Next || evt->keyval == GDK_KP_Page_Down)) + { + int pos = -1; + GtkTreeIter iter; + GtkTreeModel* model = NULL; + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + if (gtk_tree_selection_get_selected(selection, &model, &iter)) + { + GtkTreePath *path = gtk_tree_model_get_path(model, &iter); + int* indices = gtk_tree_path_get_indices(path); + pos = indices[0]; + gtk_tree_path_free(path); + } + + if (pos == -1) + pos = 0; + else if (evt->keyval == GDK_Up || evt->keyval == GDK_KP_Up) + { + pos--; + if (pos < 0) pos = 0; + } + else if (evt->keyval == GDK_Prior || evt->keyval == GDK_KP_Page_Up) + { + pos -= 5; + if (pos < 0) pos = 0; + } + else if (evt->keyval == GDK_Down || evt->keyval == GDK_KP_Down) + { + int count = gtk_tree_model_iter_n_children(model, NULL); + pos++; + if (pos > count-1) pos = count-1; + } + else if (evt->keyval == GDK_Next || evt->keyval == GDK_KP_Page_Down) + { + int count = gtk_tree_model_iter_n_children(model, NULL); + pos += 5; + if (pos > count-1) pos = count-1; + } + + if (pos != -1) + { + GtkTreePath* path = gtk_tree_path_new_from_indices(pos, -1); + g_signal_handlers_block_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih); + gtk_tree_selection_select_path(selection, path); + g_signal_handlers_unblock_by_func(G_OBJECT(selection), G_CALLBACK(gtkListSelectionChanged), ih); + gtk_tree_path_free(path); + iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos); + + if (!model) model = gtkListGetModel(ih); + + if (gtk_tree_model_iter_nth_child(model, &iter, NULL, pos)) + { + gchar *text = NULL; + gtk_tree_model_get(model, &iter, 0, &text, -1); + if (text) + { + gtk_entry_set_text((GtkEntry*)entry, text); + g_free(text); + } + } + + } + } + + return FALSE; +} + +static gboolean gtkListEditKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) +{ + gtkListEditMoveCursor(widget, 0, 0, 0, ih); + (void)evt; + return FALSE; +} + +static gboolean gtkListEditButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih) +{ + gtkListEditMoveCursor(widget, 0, 0, 0, ih); + (void)evt; + return FALSE; +} + +static int gtkListCallEditCb(Ihandle* ih, GtkEditable *editable, const char* insert_value, int len, int start, int end) +{ + char *new_value, *value; + int ret = -1, key = 0; + + IFnis cb = (IFnis)IupGetCallback(ih, "EDIT_CB"); + if (!cb && !ih->data->mask) + return -1; /* continue */ + + value = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_entry_get_text(GTK_ENTRY(editable)))); + + if (!insert_value) + { + new_value = iupStrDup(value); + if (end<0) end = strlen(value)+1; + iupStrRemove(new_value, start, end, 1); + } + else + { + if (!value) + new_value = iupStrDup(insert_value); + else + { + if (len < end-start) + { + new_value = iupStrDup(value); + new_value = iupStrInsert(new_value, insert_value, start, end); + } + else + new_value = iupStrInsert(value, insert_value, start, end); + } + } + + if (insert_value && insert_value[0]!=0 && insert_value[1]==0) + key = insert_value[0]; + + if (!new_value) + return -1; /* continue */ + + if (ih->data->nc && (int)strlen(new_value) > ih->data->nc) + { + if (new_value != value) free(new_value); + return 0; /* abort */ + } + + if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0) + { + if (new_value != value) free(new_value); + return 0; /* abort */ + } + + if (cb) + { + int cb_ret = cb(ih, key, (char*)new_value); + if (cb_ret==IUP_IGNORE) + ret = 0; /* abort */ + else if (cb_ret==IUP_CLOSE) + { + IupExitLoop(); + ret = 0; /* abort */ + } + else if (cb_ret!=0 && key!=0 && + cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE) + ret = cb_ret; /* abort and replace */ + } + + if (new_value != value) free(new_value); + return ret; /* continue */ +} + +static void gtkListEditDeleteText(GtkEditable *editable, int start, int end, Ihandle* ih) +{ + if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB")) + return; + + if (gtkListCallEditCb(ih, editable, NULL, 0, start, end)==0) + g_signal_stop_emission_by_name(editable, "delete_text"); +} + +static void gtkListEditInsertText(GtkEditable *editable, char *insert_value, int len, int *pos, Ihandle* ih) +{ + int ret; + + if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB")) + return; + + ret = gtkListCallEditCb(ih, editable, iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(insert_value)), len, *pos, *pos); + if (ret == 0) + g_signal_stop_emission_by_name(editable, "insert_text"); + else if (ret != -1) + { + insert_value[0] = (char)ret; /* replace key */ + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + gtk_editable_insert_text(editable, insert_value, 1, pos); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + + g_signal_stop_emission_by_name(editable, "insert_text"); + } +} + +static void gtkListEditChanged(void* dummy, Ihandle* ih) +{ + if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB")) + return; + + iupBaseCallValueChangedCb(ih); + (void)dummy; +} + +static void gtkListComboBoxPopupShownChanged(GtkComboBox* widget, GParamSpec *pspec, Ihandle* ih) +{ + IFni cb = (IFni)IupGetCallback(ih, "DROPDOWN_CB"); + if (cb) + { + gboolean popup_shown; + g_object_get(widget, "popup-shown", &popup_shown, NULL); + cb(ih, popup_shown); + } + (void)pspec; +} + +static void gtkListComboBoxChanged(GtkComboBox* widget, Ihandle* ih) +{ + IFnsii cb = (IFnsii)IupGetCallback(ih, "ACTION"); + if (cb) + { + int pos = gtk_combo_box_get_active((GtkComboBox*)ih->handle); + pos++; /* IUP starts at 1 */ + iupListSingleCallActionCallback(ih, cb, pos); + } + + if (!ih->data->has_editbox) + iupBaseCallValueChangedCb(ih); + + (void)widget; +} + +static gboolean gtkListSimpleKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) +{ + if (iupgtkKeyPressEvent(widget, evt, ih) == TRUE) + return TRUE; + + if (evt->keyval == GDK_Return || evt->keyval == GDK_KP_Enter) + return TRUE; /* used to avoid the call to DBLCLICK_CB in the default processing */ + return FALSE; +} + +static void gtkListRowActivated(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, Ihandle* ih) +{ + IFnis cb = (IFnis) IupGetCallback(ih, "DBLCLICK_CB"); + if (cb) + { + int* indices = gtk_tree_path_get_indices(path); + iupListSingleCallDblClickCallback(ih, cb, indices[0]+1); /* IUP starts at 1 */ + } + (void)column; + (void)tree_view; +} + +static void gtkListSelectionChanged(GtkTreeSelection* selection, Ihandle* ih) +{ + if (ih->data->has_editbox) + { + /* must manually update its contents */ + GtkTreeIter iter; + GtkTreeModel* tree_model; + if (gtk_tree_selection_get_selected(selection, &tree_model, &iter)) + { + GtkTreePath *path = gtk_tree_model_get_path(tree_model, &iter); + char* value = NULL; + gtk_tree_model_get(tree_model, &iter, 0, &value, -1); + if (value) + { + GtkEntry* entry = (GtkEntry*)iupAttribGet(ih, "_IUPGTK_ENTRY"); + gtk_entry_set_text(entry, value); + g_free(value); + } + gtk_tree_path_free(path); + } + } + + if (!ih->data->is_multiple) + { + IFnsii cb = (IFnsii)IupGetCallback(ih, "ACTION"); + if (cb) + { + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iter; + GtkTreeModel* tree_model; + if (gtk_tree_selection_get_selected(selection, &tree_model, &iter)) + { + GtkTreePath *path = gtk_tree_model_get_path(tree_model, &iter); + int* indices = gtk_tree_path_get_indices(path); + iupListSingleCallActionCallback(ih, cb, indices[0]+1); /* IUP starts at 1 */ + gtk_tree_path_free (path); + } + } + } + else + { + IFns multi_cb = (IFns)IupGetCallback(ih, "MULTISELECT_CB"); + IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION"); + if (multi_cb || cb) + { + GList *il, *list = gtk_tree_selection_get_selected_rows(selection, NULL); + int i, sel_count = g_list_length(list); + int* pos = malloc(sizeof(int)*sel_count); + for (il=list, i=0; il; il=il->next, i++) + { + GtkTreePath* path = (GtkTreePath*)il->data; + int* indices = gtk_tree_path_get_indices(path); + pos[i] = indices[0]; + gtk_tree_path_free(path); + } + g_list_free(list); + + iupListMultipleCallActionCallback(ih, cb, multi_cb, pos, sel_count); + free(pos); + } + } + + if (!ih->data->has_editbox) + iupBaseCallValueChangedCb(ih); +} + + +/*********************************************************************************/ + + +static int gtkListMapMethod(Ihandle* ih) +{ + GtkScrolledWindow* scrolled_window = NULL; + GtkListStore *store; + + store = gtk_list_store_new(1, G_TYPE_STRING); + + if (ih->data->is_dropdown) + { + GtkCellRenderer *renderer = NULL; + + if (ih->data->has_editbox) + ih->handle = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(store), 0); + else + ih->handle = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store)); + g_object_unref(store); + + if (!ih->handle) + return IUP_ERROR; + + g_object_set(G_OBJECT(ih->handle), "has-frame", TRUE, NULL); + + if (ih->data->has_editbox) + { + GtkWidget *entry; +#if GTK_CHECK_VERSION(2, 12, 0) + GList* list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(ih->handle)); + renderer = list->data; + g_list_free(list); +#endif + + entry = gtk_bin_get_child(GTK_BIN(ih->handle)); + iupAttribSetStr(ih, "_IUPGTK_ENTRY", (char*)entry); + + g_signal_connect(G_OBJECT(entry), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(entry), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(entry), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(entry), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(entry), "show-help", G_CALLBACK(iupgtkShowHelp), ih); + g_signal_connect(G_OBJECT(entry), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih); + + g_signal_connect(G_OBJECT(entry), "delete-text", G_CALLBACK(gtkListEditDeleteText), ih); + g_signal_connect(G_OBJECT(entry), "insert-text", G_CALLBACK(gtkListEditInsertText), ih); + /* g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(gtkListEditChanged), ih); */ + g_signal_connect_after(G_OBJECT(entry), "move-cursor", G_CALLBACK(gtkListEditMoveCursor), ih); /* only report some caret movements */ + g_signal_connect_after(G_OBJECT(entry), "key-release-event", G_CALLBACK(gtkListEditKeyReleaseEvent), ih); + g_signal_connect(G_OBJECT(entry), "button-press-event", G_CALLBACK(gtkListEditButtonEvent), ih); /* if connected "after" then it is ignored */ + g_signal_connect(G_OBJECT(entry), "button-release-event",G_CALLBACK(gtkListEditButtonEvent), ih); + + if (!iupAttribGetBoolean(ih, "CANFOCUS")) + GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS; + } + else + { + /* had to add an event box just to get get/killfocus,enter/leave events */ + GtkWidget *box = gtk_event_box_new(); + gtk_container_add((GtkContainer*)box, ih->handle); + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)box); + + renderer = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(ih->handle), renderer, TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(ih->handle), renderer, "text", 0, NULL); + + g_signal_connect(G_OBJECT(box), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(box), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(box), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(box), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih); + + if (!iupAttribGetBoolean(ih, "CANFOCUS")) + GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS; + else + GTK_WIDGET_FLAGS(box) |= GTK_CAN_FOCUS; + } + + g_signal_connect(ih->handle, "changed", G_CALLBACK(gtkListComboBoxChanged), ih); + g_signal_connect(ih->handle, "notify::popup-shown", G_CALLBACK(gtkListComboBoxPopupShownChanged), ih); + + if (renderer) + { + renderer->xpad = 0; + renderer->ypad = 0; + iupAttribSetStr(ih, "_IUPGTK_RENDERER", (char*)renderer); + } + } + else + { + GtkCellRenderer *renderer; + GtkTreeSelection* selection; + GtkTreeViewColumn *column; + GtkPolicyType scrollbar_policy; + + ih->handle = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + g_object_unref(store); + + if (!ih->handle) + return IUP_ERROR; + + scrolled_window = (GtkScrolledWindow*)gtk_scrolled_window_new(NULL, NULL); + + if (ih->data->has_editbox) + { + GtkBox* vbox = (GtkBox*)gtk_vbox_new(FALSE, 0); + + GtkWidget *entry = gtk_entry_new(); + gtk_widget_show(entry); + gtk_box_pack_start(vbox, entry, FALSE, FALSE, 0); + iupAttribSetStr(ih, "_IUPGTK_ENTRY", (char*)entry); + + gtk_widget_show((GtkWidget*)vbox); + gtk_box_pack_end(vbox, (GtkWidget*)scrolled_window, TRUE, TRUE, 0); + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)vbox); + iupAttribSetStr(ih, "_IUPGTK_SCROLLED_WINDOW", (char*)scrolled_window); + + GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS; /* focus goes only to the edit box */ + if (!iupAttribGetBoolean(ih, "CANFOCUS")) + GTK_WIDGET_FLAGS(entry) &= ~GTK_CAN_FOCUS; + + g_signal_connect(G_OBJECT(entry), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(entry), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(entry), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(entry), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(entry), "show-help", G_CALLBACK(iupgtkShowHelp), ih); + + g_signal_connect(G_OBJECT(entry), "delete-text", G_CALLBACK(gtkListEditDeleteText), ih); + g_signal_connect(G_OBJECT(entry), "insert-text", G_CALLBACK(gtkListEditInsertText), ih); + g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(gtkListEditChanged), ih); + g_signal_connect_after(G_OBJECT(entry), "move-cursor", G_CALLBACK(gtkListEditMoveCursor), ih); /* only report some caret movements */ + g_signal_connect(G_OBJECT(entry), "key-press-event", G_CALLBACK(gtkListEditKeyPressEvent), ih); + g_signal_connect_after(G_OBJECT(entry), "key-release-event", G_CALLBACK(gtkListEditKeyReleaseEvent), ih); + g_signal_connect(G_OBJECT(entry), "button-press-event", G_CALLBACK(gtkListEditButtonEvent), ih); /* if connected "after" then it is ignored */ + g_signal_connect(G_OBJECT(entry), "button-release-event",G_CALLBACK(gtkListEditButtonEvent), ih); + } + else + { + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)scrolled_window); + + if (!iupAttribGetBoolean(ih, "CANFOCUS")) + GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS; + + g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkListSimpleKeyPressEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih); + } + + column = gtk_tree_view_column_new(); + + renderer = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(column), renderer, TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(column), renderer, "text", 0, NULL); + + iupAttribSetStr(ih, "_IUPGTK_RENDERER", (char*)renderer); + g_object_set(G_OBJECT(renderer), "xpad", 0, NULL); + g_object_set(G_OBJECT(renderer), "ypad", 0, NULL); + + gtk_tree_view_append_column(GTK_TREE_VIEW(ih->handle), column); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(ih->handle), FALSE); + gtk_tree_view_set_enable_search(GTK_TREE_VIEW(ih->handle), FALSE); /* TODO: check "start-interactive-search" signal */ + + gtk_container_add((GtkContainer*)scrolled_window, ih->handle); + gtk_widget_show((GtkWidget*)scrolled_window); + gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_IN); + + if (ih->data->sb) + { + if (iupAttribGetBoolean(ih, "AUTOHIDE")) + scrollbar_policy = GTK_POLICY_AUTOMATIC; + else + scrollbar_policy = GTK_POLICY_ALWAYS; + } + else + scrollbar_policy = GTK_POLICY_NEVER; + + gtk_scrolled_window_set_policy(scrolled_window, scrollbar_policy, scrollbar_policy); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + if (!ih->data->has_editbox && ih->data->is_multiple) + { + gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); +#if GTK_CHECK_VERSION(2, 10, 0) + gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(ih->handle), TRUE); +#endif + } + else + gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); + + g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(gtkListSelectionChanged), ih); + g_signal_connect(G_OBJECT(ih->handle), "row-activated", G_CALLBACK(gtkListRowActivated), ih); + g_signal_connect(G_OBJECT(ih->handle), "motion-notify-event",G_CALLBACK(iupgtkMotionNotifyEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(iupgtkButtonEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(iupgtkButtonEvent), ih); + } + + if (iupAttribGetBoolean(ih, "SORT")) + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), 0, GTK_SORT_ASCENDING); + + /* add to the parent, all GTK controls must call this. */ + iupgtkBaseAddToParent(ih); + + if (scrolled_window) + gtk_widget_realize((GtkWidget*)scrolled_window); + gtk_widget_realize(ih->handle); + + /* configure for DRAG&DROP */ + if (IupGetCallback(ih, "DROPFILES_CB")) + iupAttribSetStr(ih, "DRAGDROP", "YES"); + + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)gtkListConvertXYToPos); + + iupListSetInitialItems(ih); + + return IUP_NOERROR; +} + +void iupdrvListInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkListMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Overwrite Common */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, gtkListSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkListSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkListSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT); + + /* IupList only */ + iupClassRegisterAttributeId(ic, "IDVALUE", gtkListGetIdValueAttrib, iupListSetIdValueAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE", gtkListGetValueAttrib, gtkListSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWDROPDOWN", NULL, gtkListSetShowDropdownAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TOPITEM", NULL, gtkListSetTopItemAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPACING", iupListGetSpacingAttrib, gtkListSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + + iupClassRegisterAttribute(ic, "PADDING", iupListGetPaddingAttrib, gtkListSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "SELECTEDTEXT", gtkListGetSelectedTextAttrib, gtkListSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTION", gtkListGetSelectionAttrib, gtkListSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTIONPOS", gtkListGetSelectionPosAttrib, gtkListSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARET", gtkListGetCaretAttrib, gtkListSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARETPOS", gtkListGetCaretPosAttrib, gtkListSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INSERT", NULL, gtkListSetInsertAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "APPEND", NULL, gtkListSetAppendAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "READONLY", gtkListGetReadOnlyAttrib, gtkListSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "NC", iupListGetNCAttrib, gtkListSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, gtkListSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTO", NULL, gtkListSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, gtkListSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); +} diff --git a/iup/src/gtk/iupgtk_loop.c b/iup/src/gtk/iupgtk_loop.c new file mode 100755 index 0000000..e349a45 --- /dev/null +++ b/iup/src/gtk/iupgtk_loop.c @@ -0,0 +1,93 @@ +/** \file + * \brief GTK Message Loop + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <string.h> + +#include <gtk/gtk.h> + +#include "iup.h" +#include "iupcbs.h" + + +/* local variables */ +static IFidle gtk_idle_cb = NULL; +static guint gtk_idle_id; + +static gboolean gtkIdleFunc(gpointer data) +{ + (void)data; + if (gtk_idle_cb) + { + int ret = gtk_idle_cb(); + if (ret == IUP_CLOSE) + { + gtk_idle_cb = NULL; + IupExitLoop(); + return FALSE; /* removes the idle */ + } + if (ret == IUP_IGNORE) + { + gtk_idle_cb = NULL; + return FALSE; /* removes the idle */ + } + + return TRUE; /* keeps the idle */ + } + + return FALSE; /* removes the idle */ +} + +void iupdrvSetIdleFunction(Icallback f) +{ + if (gtk_idle_cb) + g_source_remove(gtk_idle_id); + + gtk_idle_cb = (IFidle)f; + + if (gtk_idle_cb) + gtk_idle_id = g_idle_add(gtkIdleFunc, NULL); +} + +void IupExitLoop(void) +{ + if (gtk_main_iteration_do(FALSE)==FALSE) + gtk_main_quit(); +} + +int IupMainLoopLevel(void) +{ + return gtk_main_level(); +} + +int IupMainLoop(void) +{ + gtk_main(); + return IUP_NOERROR; +} + +int IupLoopStep(void) +{ + if (gtk_main_iteration_do(FALSE)) + return IUP_CLOSE; + return IUP_DEFAULT; +} + +void IupFlush(void) +{ + IFidle old_gtk_idle_cb = NULL; + if (gtk_idle_cb) + { + old_gtk_idle_cb = gtk_idle_cb; + iupdrvSetIdleFunction(NULL); + } + + while (gtk_events_pending()) + gtk_main_iteration(); + + if (old_gtk_idle_cb) + iupdrvSetIdleFunction((Icallback)old_gtk_idle_cb); +} diff --git a/iup/src/gtk/iupgtk_menu.c b/iup/src/gtk/iupgtk_menu.c new file mode 100755 index 0000000..c12fbea --- /dev/null +++ b/iup/src/gtk/iupgtk_menu.c @@ -0,0 +1,525 @@ +/** \file + * \brief Menu Resources + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> + +#ifdef HILDON +#include <hildon/hildon-window.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_label.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_image.h" +#include "iup_menu.h" + +#include "iupgtk_drv.h" + + +typedef struct _ImenuPos +{ + int x, y; +} ImenuPos; + +static void gtkMenuPositionFunc(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, ImenuPos *menupos) +{ + *x = menupos->x; + *y = menupos->y; + *push_in = FALSE; + (void)menu; +} + +int iupdrvMenuPopup(Ihandle* ih, int x, int y) +{ + ImenuPos menupos; + menupos.x = x; + menupos.y = y; + gtk_menu_popup((GtkMenu*)ih->handle, NULL, NULL, (GtkMenuPositionFunc)gtkMenuPositionFunc, + (gpointer)&menupos, 0, gtk_get_current_event_time()); + gtk_main(); + return IUP_NOERROR; +} + +int iupdrvMenuGetMenuBarSize(Ihandle* ih) +{ + int ch; + iupdrvFontGetCharSize(ih, NULL, &ch); +#ifdef WIN32 + return 3 + ch + 3; +#else + return 4 + ch + 4; +#endif +} + +static void gtkItemUpdateImage(Ihandle* ih, const char* value, const char* image, const char* impress) +{ + GdkPixbuf* pixbuf; + + if (!impress || !iupStrBoolean(value)) + pixbuf = iupImageGetImage(image, ih, 0); + else + pixbuf = iupImageGetImage(impress, ih, 0); + + if (pixbuf) + { + GtkWidget* image_label = gtk_image_menu_item_get_image((GtkImageMenuItem*)ih->handle); + if (!image_label) + { + image_label = gtk_image_new(); + gtk_image_menu_item_set_image((GtkImageMenuItem*)ih->handle, image_label); + } + + if (pixbuf != gtk_image_get_pixbuf((GtkImage*)image_label)) + gtk_image_set_from_pixbuf((GtkImage*)image_label, pixbuf); + } + else + gtk_image_menu_item_set_image((GtkImageMenuItem*)ih->handle, NULL); +} + + +/*******************************************************************************************/ + + +static void gtkMenuMap(GtkWidget *widget, Ihandle* ih) +{ + Icallback cb = IupGetCallback(ih, "OPEN_CB"); + if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "OPEN_CB"); /* check also in the Submenu */ + if (cb) cb(ih); + + (void)widget; +} + +static void gtkMenuUnMap(GtkWidget *widget, Ihandle* ih) +{ + Icallback cb = IupGetCallback(ih, "MENUCLOSE_CB"); + if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "MENUCLOSE_CB"); /* check also in the Submenu */ + if (cb) cb(ih); + + (void)widget; +} + +static void gtkPopupMenuUnMap(GtkWidget *widget, Ihandle* ih) +{ + gtkMenuUnMap(widget, ih); + + /* quit the popup loop */ + gtk_main_quit(); +} + +static void gtkItemSelect(GtkWidget *widget, Ihandle* ih) +{ + Icallback cb = IupGetCallback(ih, "HIGHLIGHT_CB"); + if (cb) + cb(ih); + + cb = IupGetCallback(ih, "HELP_CB"); + if (cb) + gtk_menu_set_active((GtkMenu*)ih->parent->handle, IupGetChildPos(ih->parent, ih)); + + (void)widget; +} + +static void gtkItemActivate(GtkWidget *widget, Ihandle* ih) +{ + Icallback cb; + + if (GTK_IS_CHECK_MENU_ITEM(ih->handle) && !iupAttribGetBoolean(ih, "AUTOTOGGLE") && !iupAttribGetBoolean(ih->parent, "RADIO")) + { + /* GTK by default will do autotoggle */ + g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih); + gtk_check_menu_item_set_active((GtkCheckMenuItem*)ih->handle, !gtk_check_menu_item_get_active((GtkCheckMenuItem*)ih->handle)); + g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih); + } + + if (GTK_IS_IMAGE_MENU_ITEM(ih->handle)) + { + if (iupAttribGetBoolean(ih, "AUTOTOGGLE")) + { + if (iupAttribGetBoolean(ih, "VALUE")) + iupAttribSetStr(ih, "VALUE", "OFF"); + else + iupAttribSetStr(ih, "VALUE", "ON"); + + gtkItemUpdateImage(ih, iupAttribGet(ih, "VALUE"), iupAttribGet(ih, "IMAGE"), iupAttribGet(ih, "IMPRESS")); + } + } + + cb = IupGetCallback(ih, "ACTION"); + if (cb && cb(ih)==IUP_CLOSE) + IupExitLoop(); + + (void)widget; +} + +static gboolean gtkMenuKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) +{ + if (evt->keyval == GDK_F1) + { + Ihandle* child; + GtkWidget* active = gtk_menu_get_active((GtkMenu*)widget); + for (child=ih->firstchild; child; child=child->brother) + { + if (child->handle == active) + iupgtkShowHelp(NULL, NULL, child); + } + } + + (void)widget; + (void)evt; + return FALSE; +} + + +/*******************************************************************************************/ + + +static int gtkMenuMapMethod(Ihandle* ih) +{ + if (iupMenuIsMenuBar(ih)) + { + /* top level menu used for MENU attribute in IupDialog (a menu bar) */ +#ifdef HILDON + Ihandle *pih; + ih->handle = gtk_menu_new(); + if (!ih->handle) + return IUP_ERROR; + + pih = iupChildTreeGetNativeParent(ih); + hildon_window_set_menu(HILDON_WINDOW(pih->handle), GTK_MENU(ih->handle)); +#else + ih->handle = gtk_menu_bar_new(); + if (!ih->handle) + return IUP_ERROR; + + iupgtkBaseAddToParent(ih); +#endif + } + else + { + ih->handle = gtk_menu_new(); + if (!ih->handle) + return IUP_ERROR; + + if (ih->parent) + { + /* parent is a submenu */ + gtk_menu_item_set_submenu((GtkMenuItem*)ih->parent->handle, ih->handle); + + g_signal_connect(G_OBJECT(ih->handle), "map", G_CALLBACK(gtkMenuMap), ih); + g_signal_connect(G_OBJECT(ih->handle), "unmap", G_CALLBACK(gtkMenuUnMap), ih); + } + else + { + /* top level menu used for IupPopup */ + iupAttribSetStr(ih, "_IUPGTK_POPUP_MENU", "1"); + + g_signal_connect(G_OBJECT(ih->handle), "map", G_CALLBACK(gtkMenuMap), ih); + g_signal_connect(G_OBJECT(ih->handle), "unmap", G_CALLBACK(gtkPopupMenuUnMap), ih); + } + } + + gtk_widget_add_events(ih->handle, GDK_KEY_PRESS_MASK); + g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkMenuKeyPressEvent), ih); + + ih->serial = iupMenuGetChildId(ih); + gtk_widget_show(ih->handle); + + return IUP_NOERROR; +} + +void iupdrvMenuInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkMenuMapMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Used by iupdrvMenuGetMenuBarSize */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, NULL, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_DEFAULT); /* use inheritance to retrieve standard fonts */ + + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, NULL, NULL, IUPAF_DEFAULT); +} + + +/*******************************************************************************************/ + +static int gtkItemSetTitleImageAttrib(Ihandle* ih, const char* value) +{ + if (GTK_IS_IMAGE_MENU_ITEM(ih->handle)) + { + gtkItemUpdateImage(ih, NULL, value, NULL); + return 1; + } + else + return 0; +} + +static int gtkItemSetImageAttrib(Ihandle* ih, const char* value) +{ + if (GTK_IS_IMAGE_MENU_ITEM(ih->handle)) + { + gtkItemUpdateImage(ih, iupAttribGet(ih, "VALUE"), value, iupAttribGet(ih, "IMPRESS")); + return 1; + } + else + return 0; +} + +static int gtkItemSetImpressAttrib(Ihandle* ih, const char* value) +{ + if (GTK_IS_IMAGE_MENU_ITEM(ih->handle)) + { + gtkItemUpdateImage(ih, iupAttribGet(ih, "VALUE"), iupAttribGet(ih, "IMAGE"), value); + return 1; + } + else + return 0; +} + +static int gtkItemSetTitleAttrib(Ihandle* ih, const char* value) +{ + char *str; + GtkWidget* label; + + if (!value) + { + str = " "; + value = str; + } + else + str = iupMenuProcessTitle(ih, value); + + label = gtk_bin_get_child((GtkBin*)ih->handle); + + iupgtkSetMnemonicTitle(ih, (GtkLabel*)label, str); + + if (str != value) free(str); + return 1; +} + +static int gtkItemSetValueAttrib(Ihandle* ih, const char* value) +{ + if (GTK_IS_CHECK_MENU_ITEM(ih->handle)) + { + if (iupAttribGetBoolean(ih->parent, "RADIO")) + value = "ON"; + + g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih); + gtk_check_menu_item_set_active((GtkCheckMenuItem*)ih->handle, iupStrBoolean(value)); + g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih); + return 0; + } + else if (GTK_IS_IMAGE_MENU_ITEM(ih->handle)) + { + gtkItemUpdateImage(ih, value, iupAttribGet(ih, "IMAGE"), iupAttribGet(ih, "IMPRESS")); + return 1; + } + else + return 0; +} + +static char* gtkItemGetValueAttrib(Ihandle* ih) +{ + if (GTK_IS_CHECK_MENU_ITEM(ih->handle)) + { + if (gtk_check_menu_item_get_active((GtkCheckMenuItem*)ih->handle)) + return "ON"; + else + return "OFF"; + } + else + return NULL; +} + +static int gtkItemMapMethod(Ihandle* ih) +{ + int pos; + + if (!ih->parent) + return IUP_ERROR; + +#ifndef HILDON + if (iupMenuIsMenuBar(ih->parent)) + ih->handle = gtk_menu_item_new_with_label(""); + else +#endif + { + if (iupAttribGet(ih, "IMAGE")||iupAttribGet(ih, "TITLEIMAGE")) + ih->handle = gtk_image_menu_item_new_with_label(""); + else if (iupAttribGetBoolean(ih->parent, "RADIO")) + { + GtkRadioMenuItem* last_tg = (GtkRadioMenuItem*)iupAttribGet(ih->parent, "_IUPGTK_LASTRADIOITEM"); + if (last_tg) + ih->handle = gtk_radio_menu_item_new_with_label_from_widget(last_tg, ""); + else + ih->handle = gtk_radio_menu_item_new_with_label(NULL, ""); + iupAttribSetStr(ih->parent, "_IUPGTK_LASTRADIOITEM", (char*)ih->handle); + } + else + { + char* hidemark = iupAttribGetStr(ih, "HIDEMARK"); + if (!hidemark && gtk_check_version(2, 14, 0) == NULL) + { + /* force HIDEMARK if VALUE is defined before Map, after GTK 2.14 */ + if (!iupAttribGet(ih, "VALUE")) + hidemark = "YES"; + } + + if (iupStrBoolean(hidemark)) + ih->handle = gtk_menu_item_new_with_label(""); + else + ih->handle = gtk_check_menu_item_new_with_label(""); + } + } + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupMenuGetChildId(ih); + + g_signal_connect(G_OBJECT(ih->handle), "select", G_CALLBACK(gtkItemSelect), ih); + g_signal_connect(G_OBJECT(ih->handle), "activate", G_CALLBACK(gtkItemActivate), ih); + + pos = IupGetChildPos(ih->parent, ih); + gtk_menu_shell_insert((GtkMenuShell*)ih->parent->handle, ih->handle, pos); + gtk_widget_show(ih->handle); + + iupUpdateStandardFontAttrib(ih); + + return IUP_NOERROR; +} + +void iupdrvItemInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkItemMapMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Common */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, iupdrvSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* use inheritance to retrieve standard fonts */ + + /* Visual */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* IupItem only */ + iupClassRegisterAttribute(ic, "VALUE", gtkItemGetValueAttrib, gtkItemSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TITLE", NULL, gtkItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TITLEIMAGE", NULL, gtkItemSetTitleImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkItemSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMPRESS", NULL, gtkItemSetImpressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupItem GTK and Motif only */ + iupClassRegisterAttribute(ic, "HIDEMARK", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED); +} + + +/*******************************************************************************************/ + + +static int gtkSubmenuSetImageAttrib(Ihandle* ih, const char* value) +{ + if (GTK_IS_IMAGE_MENU_ITEM(ih->handle)) + { + gtkItemUpdateImage(ih, NULL, value, NULL); + return 1; + } + else + return 0; +} + +static int motSubmenuMapMethod(Ihandle* ih) +{ + int pos; + + if (!ih->parent) + return IUP_ERROR; + +#ifndef HILDON + if (iupMenuIsMenuBar(ih->parent)) + ih->handle = gtk_menu_item_new_with_label(""); + else +#endif + ih->handle = gtk_image_menu_item_new_with_label(""); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupMenuGetChildId(ih); + + pos = IupGetChildPos(ih->parent, ih); + gtk_menu_shell_insert((GtkMenuShell*)ih->parent->handle, ih->handle, pos); + gtk_widget_show(ih->handle); + + g_signal_connect(G_OBJECT(ih->handle), "select", G_CALLBACK(gtkItemSelect), ih); + + iupUpdateStandardFontAttrib(ih); + + return IUP_NOERROR; +} + +void iupdrvSubmenuInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motSubmenuMapMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Common */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, iupdrvSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* use inheritance to retrieve standard fonts */ + + /* Visual */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* IupSubmenu only */ + iupClassRegisterAttribute(ic, "TITLE", NULL, gtkItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkSubmenuSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +} + + +/*******************************************************************************************/ + + +static int gtkSeparatorMapMethod(Ihandle* ih) +{ + int pos; + + if (!ih->parent) + return IUP_ERROR; + + ih->handle = gtk_separator_menu_item_new(); + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupMenuGetChildId(ih); + + pos = IupGetChildPos(ih->parent, ih); + gtk_menu_shell_insert((GtkMenuShell*)ih->parent->handle, ih->handle, pos); + gtk_widget_show(ih->handle); + + return IUP_NOERROR; +} + +void iupdrvSeparatorInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkSeparatorMapMethod; + ic->UnMap = iupdrvBaseUnMapMethod; +} diff --git a/iup/src/gtk/iupgtk_messagedlg.c b/iup/src/gtk/iupgtk_messagedlg.c new file mode 100755 index 0000000..a036af6 --- /dev/null +++ b/iup/src/gtk/iupgtk_messagedlg.c @@ -0,0 +1,128 @@ +/** \file + * \brief GTK IupMessageDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_dialog.h" + +#include "iupgtk_drv.h" + +/* Sometimes GTK decides to invert the buttons position because of the GNOME Guidelines. + To avoid that we define different Ids for the buttons. */ +#define IUP_RESPONSE_1 -100 +#define IUP_RESPONSE_2 -200 +#define IUP_RESPONSE_HELP -300 + +#ifndef GTK_MESSAGE_OTHER +#define GTK_MESSAGE_OTHER GTK_MESSAGE_INFO +#endif + +static int gtkMessageDlgPopup(Ihandle* ih, int x, int y) +{ + InativeHandle* parent = iupDialogGetNativeParent(ih); + GtkMessageType type = GTK_MESSAGE_OTHER; + GtkWidget* dialog; + char *icon, *buttons, *title; + int response, num_but = 2; + + iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */ + iupAttribSetInt(ih, "_IUPDLG_Y", y); + + icon = iupAttribGetStr(ih, "DIALOGTYPE"); + if (iupStrEqualNoCase(icon, "ERROR")) + type = GTK_MESSAGE_ERROR; + else if (iupStrEqualNoCase(icon, "WARNING")) + type = GTK_MESSAGE_WARNING; + else if (iupStrEqualNoCase(icon, "INFORMATION")) + type = GTK_MESSAGE_INFO; + else if (iupStrEqualNoCase(icon, "QUESTION")) + type = GTK_MESSAGE_QUESTION; + + dialog = gtk_message_dialog_new((GtkWindow*)parent, + 0, + type, + GTK_BUTTONS_NONE, + iupgtkStrConvertToUTF8(iupAttribGet(ih, "VALUE"))); + if (!dialog) + return IUP_ERROR; + + title = iupAttribGet(ih, "TITLE"); + if (title) + gtk_window_set_title(GTK_WINDOW(dialog), iupgtkStrConvertToUTF8(title)); + + buttons = iupAttribGetStr(ih, "BUTTONS"); + if (iupStrEqualNoCase(buttons, "OKCANCEL")) + { + gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_OK, + IUP_RESPONSE_1); + gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_CANCEL, + IUP_RESPONSE_2); + } + else if (iupStrEqualNoCase(buttons, "YESNO")) + { + gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_YES, + IUP_RESPONSE_1); + gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_NO, + IUP_RESPONSE_2); + } + else /* OK */ + { + gtk_dialog_add_button(GTK_DIALOG(dialog), + GTK_STOCK_OK, + IUP_RESPONSE_1); + num_but = 1; + } + + if (IupGetCallback(ih, "HELP_CB")) + gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_HELP, IUP_RESPONSE_HELP); + + if (num_but == 2 && iupAttribGetInt(ih, "BUTTONDEFAULT") == 2) + gtk_dialog_set_default_response(GTK_DIALOG(dialog), IUP_RESPONSE_2); + else + gtk_dialog_set_default_response(GTK_DIALOG(dialog), IUP_RESPONSE_1); + + /* initialize the widget */ + gtk_widget_realize(dialog); + + ih->handle = dialog; + iupDialogUpdatePosition(ih); + ih->handle = NULL; + + do + { + response = gtk_dialog_run(GTK_DIALOG(dialog)); + + if (response == IUP_RESPONSE_HELP) + { + Icallback cb = IupGetCallback(ih, "HELP_CB"); + if (cb && cb(ih) == IUP_CLOSE) + response = (num_but == 2)? IUP_RESPONSE_2: IUP_RESPONSE_1; + } + } while (response == IUP_RESPONSE_HELP); + + if (response == IUP_RESPONSE_1) + IupSetAttribute(ih, "BUTTONRESPONSE", "1"); + else + IupSetAttribute(ih, "BUTTONRESPONSE", "2"); + + gtk_widget_destroy(dialog); + + return IUP_NOERROR; +} + +void iupdrvMessageDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = gtkMessageDlgPopup; +} diff --git a/iup/src/gtk/iupgtk_open.c b/iup/src/gtk/iupgtk_open.c new file mode 100755 index 0000000..66e46e8 --- /dev/null +++ b/iup/src/gtk/iupgtk_open.c @@ -0,0 +1,172 @@ +/** \file + * \brief GTK Driver Core + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <gtk/gtk.h> + +#include "iup.h" + +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvinfo.h" +#include "iup_object.h" +#include "iup_globalattrib.h" + +#include "iupgtk_drv.h" + + +#ifdef WIN32 /******************************** WIN32 ************************************/ +#include <gdk/gdkwin32.h> + +char* iupgtkGetNativeWindowHandle(Ihandle* ih) +{ + GdkWindow* window = ih->handle->window; + if (window) + return (char*)GDK_WINDOW_HWND(window); + else + return NULL; +} + +void* iupgtkGetNativeGraphicsContext(GtkWidget* widget) +{ + return GetDC(GDK_WINDOW_HWND(widget->window)); +} + +void iupgtkReleaseNativeGraphicsContext(GtkWidget* widget, void* gc) +{ + ReleaseDC(GDK_WINDOW_HWND(widget->window), (HDC)gc); +} + +void* iupdrvGetDisplay(void) +{ + return NULL; +} + +void iupgtkPushVisualAndColormap(void* visual, void* colormap) +{ + (void)visual; + (void)colormap; +} + +static void gtkSetDrvGlobalAttrib(void) +{ +} + +#else /******************************** X11 ************************************/ +#include <gdk/gdkx.h> + +char* iupgtkGetNativeWindowHandle(Ihandle* ih) +{ + GdkWindow* window = ih->handle->window; + if (window) + return (char*)GDK_WINDOW_XID(window); + else + return NULL; +} + +void* iupgtkGetNativeGraphicsContext(GtkWidget* widget) +{ + GdkDisplay* display = gdk_display_get_default(); + return (void*)XCreateGC(GDK_DISPLAY_XDISPLAY(display), GDK_WINDOW_XID(widget->window), 0, NULL); +} + +void iupgtkReleaseNativeGraphicsContext(GtkWidget* widget, void* gc) +{ + GdkDisplay* display = gdk_display_get_default(); + XFreeGC(GDK_DISPLAY_XDISPLAY(display), (GC)gc); + (void)widget; +} + +void* iupdrvGetDisplay(void) +{ + GdkDisplay* display = gdk_display_get_default(); + return GDK_DISPLAY_XDISPLAY(display); +} + +void iupgtkPushVisualAndColormap(void* visual, void* colormap) +{ + GdkColormap* gdk_colormap; + GdkVisual *gdk_visual = gdkx_visual_get(XVisualIDFromVisual((Visual*)visual)); + if (colormap) + gdk_colormap = gdk_x11_colormap_foreign_new(gdk_visual, (Colormap)colormap); + else + gdk_colormap = gdk_colormap_new(gdk_visual, FALSE); + + gtk_widget_push_colormap(gdk_colormap); + + /* gtk_widget_push_visual is now deprecated */ +} + +static void gtkSetDrvGlobalAttrib(void) +{ + GdkDisplay* display = gdk_display_get_default(); + Display* xdisplay = GDK_DISPLAY_XDISPLAY(display); + IupSetGlobal("XDISPLAY", (char*)xdisplay); + IupSetGlobal("XSCREEN", (char*)XDefaultScreen(xdisplay)); + IupSetGlobal("XSERVERVENDOR", ServerVendor(xdisplay)); + IupSetfAttribute(NULL, "XVENDORRELEASE", "%d", VendorRelease(xdisplay)); +} + +#endif + +static void gtkSetGlobalColorAttrib(const char* name, GdkColor *color) +{ + iupGlobalSetDefaultColorAttrib(name, (int)iupCOLOR16TO8(color->red), + (int)iupCOLOR16TO8(color->green), + (int)iupCOLOR16TO8(color->blue)); +} + +void iupgtkUpdateGlobalColors(GtkStyle* style) +{ + GdkColor color = style->bg[GTK_STATE_NORMAL]; + gtkSetGlobalColorAttrib("DLGBGCOLOR", &color); + + color = style->fg[GTK_STATE_NORMAL]; + gtkSetGlobalColorAttrib("DLGFGCOLOR", &color); + + color = style->base[GTK_STATE_NORMAL]; + gtkSetGlobalColorAttrib("TXTBGCOLOR", &color); + + color = style->text[GTK_STATE_NORMAL]; + gtkSetGlobalColorAttrib("TXTFGCOLOR", &color); +} + +int iupdrvOpen(int *argc, char ***argv) +{ + GtkStyle* style; + + if (!gtk_init_check(argc, argv)) + return IUP_ERROR; + + IupSetGlobal("DRIVER", "GTK"); + + IupStoreGlobal("SYSTEMLANGUAGE", pango_language_to_string(gtk_get_default_language())); + + /* driver system version */ + IupSetfAttribute(NULL, "GTKVERSION", "%d.%d.%d", gtk_major_version, + gtk_minor_version, + gtk_micro_version); + IupSetfAttribute(NULL, "GTKDEVVERSION", "%d.%d.%d", GTK_MAJOR_VERSION, + GTK_MINOR_VERSION, + GTK_MICRO_VERSION); + + gtkSetDrvGlobalAttrib(); + + style = gtk_style_new(); + iupgtkUpdateGlobalColors(style); + IupSetGlobal("_IUP_RESET_GLOBALCOLORS", "YES"); /* will update the global colors when the first dialog is mapped */ + g_object_unref(style); + + return IUP_NOERROR; +} + +void iupdrvClose(void) +{ + iupgtkReleaseConvertUTF8(); +} diff --git a/iup/src/gtk/iupgtk_progressbar.c b/iup/src/gtk/iupgtk_progressbar.c new file mode 100755 index 0000000..7bc6cbb --- /dev/null +++ b/iup/src/gtk/iupgtk_progressbar.c @@ -0,0 +1,131 @@ +/** \file +* \brief Progress bar Control +* +* See Copyright Notice in "iup.h" +*/ + +#undef GTK_DISABLE_DEPRECATED +#include <gtk/gtk.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_progressbar.h" +#include "iup_drv.h" + +#include "iupgtk_drv.h" + + +static int gtkProgressBarSetMarqueeAttrib(Ihandle* ih, const char* value) +{ + GtkProgress* progress = (GtkProgress*)ih->handle; + + if (iupStrBoolean(value)) + { + ih->data->marquee = 1; + gtk_progress_set_activity_mode(progress, TRUE); + } + else + { + gtk_progress_set_activity_mode(progress, FALSE); + ih->data->marquee = 0; + } + + return 1; +} + +static int gtkProgressBarSetValueAttrib(Ihandle* ih, const char* value) +{ + GtkProgressBar* pbar = (GtkProgressBar*)ih->handle; + + if (!value) + ih->data->value = 0; + else + ih->data->value = atof(value); + iProgressBarCropValue(ih); + + if (ih->data->marquee) + gtk_progress_bar_pulse(pbar); + else + gtk_progress_bar_set_fraction(pbar, (ih->data->value - ih->data->vmin) / (ih->data->vmax - ih->data->vmin)); + + return 0; +} + +static int gtkProgressBarSetDashedAttrib(Ihandle* ih, const char* value) +{ + GtkProgressBar* pbar = (GtkProgressBar*)ih->handle; + + /* gtk_progress_bar_set_bar_style is deprecated */ + if (iupStrBoolean(value)) + { + ih->data->dashed = 1; + gtk_progress_bar_set_bar_style(pbar, GTK_PROGRESS_DISCRETE); + } + else /* Default */ + { + ih->data->dashed = 0; + gtk_progress_bar_set_bar_style(pbar, GTK_PROGRESS_CONTINUOUS); + } + + return 0; +} + +static int gtkProgressBarMapMethod(Ihandle* ih) +{ + ih->handle = gtk_progress_bar_new(); + if (!ih->handle) + return IUP_ERROR; + + /* add to the parent, all GTK controls must call this. */ + iupgtkBaseAddToParent(ih); + + gtk_widget_realize(ih->handle); + + if (iupStrEqualNoCase(iupAttribGetStr(ih, "ORIENTATION"), "VERTICAL")) + { + gtk_progress_bar_set_orientation((GtkProgressBar*)ih->handle, GTK_PROGRESS_BOTTOM_TO_TOP); + + if (ih->currentheight < ih->currentwidth) + { + int tmp = ih->currentheight; + ih->currentheight = ih->currentwidth; + ih->currentwidth = tmp; + } + } + else + gtk_progress_bar_set_orientation((GtkProgressBar*)ih->handle, GTK_PROGRESS_LEFT_TO_RIGHT); + + return IUP_NOERROR; +} + +void iupdrvProgressBarInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkProgressBarMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, NULL, NULL, IUPAF_DEFAULT); + + /* IupProgressBar only */ + iupClassRegisterAttribute(ic, "VALUE", iProgressBarGetValueAttrib, gtkProgressBarSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DASHED", iProgressBarGetDashedAttrib, gtkProgressBarSetDashedAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ORIENTATION", NULL, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MARQUEE", NULL, gtkProgressBarSetMarqueeAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DASHED", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); +} diff --git a/iup/src/gtk/iupgtk_tabs.c b/iup/src/gtk/iupgtk_tabs.c new file mode 100755 index 0000000..8029826 --- /dev/null +++ b/iup/src/gtk/iupgtk_tabs.c @@ -0,0 +1,444 @@ +/** \file +* \brief Tabs Control +* +* See Copyright Notice in "iup.h" +*/ + +#include <gtk/gtk.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_dialog.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_image.h" +#include "iup_tabs.h" + +#include "iupgtk_drv.h" + + +int iupdrvTabsExtraDecor(Ihandle* ih) +{ + (void)ih; + return 0; +} + +int iupdrvTabsGetLineCountAttrib(Ihandle* ih) +{ + (void)ih; + return 1; +} + +void iupdrvTabsSetCurrentTab(Ihandle* ih, int pos) +{ + iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", "1"); + gtk_notebook_set_current_page((GtkNotebook*)ih->handle, pos); + iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", NULL); +} + +int iupdrvTabsGetCurrentTab(Ihandle* ih) +{ + return gtk_notebook_get_current_page((GtkNotebook*)ih->handle); +} + +static void gtkTabsUpdatePageFont(Ihandle* ih) +{ + Ihandle* child; + PangoFontDescription* fontdesc = (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih); + + for (child = ih->firstchild; child; child = child->brother) + { + GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL"); + if (tab_label) + { + gtk_widget_modify_font(tab_label, fontdesc); + iupgtkFontUpdatePangoLayout(ih, gtk_label_get_layout((GtkLabel*)tab_label)); + } + } +} + +static void gtkTabsUpdatePageBgColor(Ihandle* ih, unsigned char r, unsigned char g, unsigned char b) +{ + Ihandle* child; + + for (child = ih->firstchild; child; child = child->brother) + { + GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER"); + if (tab_page) + { + GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL"); + if (tab_label) + iupgtkBaseSetBgColor(tab_label, r, g, b); + iupgtkBaseSetBgColor(tab_page, r, g, b); + } + } +} + +static void gtkTabsUpdatePageFgColor(Ihandle* ih, unsigned char r, unsigned char g, unsigned char b) +{ + Ihandle* child; + + for (child = ih->firstchild; child; child = child->brother) + { + GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL"); + if (tab_label) + iupgtkBaseSetFgColor(tab_label, r, g, b); + } +} + +static void gtkTabsUpdatePagePadding(Ihandle* ih) +{ + Ihandle* child; + + for (child = ih->firstchild; child; child = child->brother) + { + GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL"); + if (tab_label) + gtk_misc_set_padding((GtkMisc*)tab_label, ih->data->horiz_padding, ih->data->vert_padding); + } +} + +/* ------------------------------------------------------------------------- */ +/* gtkTabs - Sets and Gets accessors */ +/* ------------------------------------------------------------------------- */ + + +static int gtkTabsSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + + if (ih->handle) + gtkTabsUpdatePagePadding(ih); + return 0; +} + +static void gtkTabsUpdateTabType(Ihandle* ih) +{ + GtkNotebook* tab_page = (GtkNotebook*)ih->handle; + int iup2gtk[4] = {GTK_POS_TOP, GTK_POS_BOTTOM, GTK_POS_LEFT, GTK_POS_RIGHT}; + gtk_notebook_set_tab_pos(tab_page, iup2gtk[ih->data->type]); +} + +static int gtkTabsSetTabTypeAttrib(Ihandle* ih, const char* value) +{ + if(iupStrEqualNoCase(value, "BOTTOM")) + ih->data->type = ITABS_BOTTOM; + else if(iupStrEqualNoCase(value, "LEFT")) + ih->data->type = ITABS_LEFT; + else if(iupStrEqualNoCase(value, "RIGHT")) + ih->data->type = ITABS_RIGHT; + else /* "TOP" */ + ih->data->type = ITABS_TOP; + + if (ih->handle) + gtkTabsUpdateTabType(ih); + + return 0; +} + +static int gtkTabsSetTabOrientationAttrib(Ihandle* ih, const char* value) +{ + if (ih->handle) /* allow to set only before mapping */ + return 0; + + if(iupStrEqualNoCase(value, "VERTICAL")) + ih->data->orientation = ITABS_VERTICAL; + else /* HORIZONTAL */ + ih->data->orientation = ITABS_HORIZONTAL; + + return 0; +} + +static int gtkTabsSetTabTitleAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int pos; + if (value && iupStrToInt(name_id, &pos)==1) + { + Ihandle* child = IupGetChild(ih, pos); + GtkWidget* tab_label = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABLABEL"); + if (tab_label) + { + GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER"); + gtk_label_set_text((GtkLabel*)tab_label, iupgtkStrConvertToUTF8(value)); + gtk_notebook_set_menu_label_text((GtkNotebook*)ih->handle, tab_page, gtk_label_get_text((GtkLabel*)tab_label)); + } + } + return 1; +} + +static int gtkTabsSetTabImageAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int pos; + if (value && iupStrToInt(name_id, &pos)==1) + { + Ihandle* child = IupGetChild(ih, pos); + GtkWidget* tab_image = (GtkWidget*)iupAttribGet(child, "_IUPGTK_TABIMAGE"); + if (tab_image) + { + GdkPixbuf* pixbuf = iupImageGetImage(value, ih, 0); + if (pixbuf) + gtk_image_set_from_pixbuf((GtkImage*)tab_image, pixbuf); + } + } + return 1; +} + +static int gtkTabsSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + iupdrvSetStandardFontAttrib(ih, value); + if (ih->handle) + gtkTabsUpdatePageFont(ih); + return 1; +} + +static int gtkTabsSetFgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + iupgtkBaseSetFgColor(ih->handle, r, g, b); + gtkTabsUpdatePageFgColor(ih, r, g, b); + + return 1; +} + +static int gtkTabsSetBgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + iupgtkBaseSetBgColor(ih->handle, r, g, b); + gtkTabsUpdatePageBgColor(ih, r, g, b); + + return 1; +} + + +/* ------------------------------------------------------------------------- */ +/* gtkTabs - Callbacks */ +/* ------------------------------------------------------------------------- */ + +void gtkTabSwitchPage(GtkNotebook* notebook, GtkNotebookPage *page, int pos, Ihandle* ih) +{ + IFnnn cb; + Ihandle* child = IupGetChild(ih, pos); + Ihandle* prev_child = IupGetChild(ih, iupdrvTabsGetCurrentTab(ih)); + IupSetAttribute(child, "VISIBLE", "YES"); + IupSetAttribute(prev_child, "VISIBLE", "NO"); + + if (iupAttribGet(ih, "_IUPGTK_IGNORE_CHANGE")) + return; + + cb = (IFnnn)IupGetCallback(ih, "TABCHANGE_CB"); + if (cb) + cb(ih, child, prev_child); + + (void)notebook; + (void)page; +} + +/* ------------------------------------------------------------------------- */ +/* gtkTabs - Methods and Init Class */ +/* ------------------------------------------------------------------------- */ + +static void gtkTabsChildAddedMethod(Ihandle* ih, Ihandle* child) +{ + if (IupGetName(child) == NULL) + iupAttribSetHandleName(child); + + if (ih->handle) + { + GtkWidget* tab_page; + GtkWidget *tab_label = NULL, *tab_image = NULL; + char *tabtitle, *tabimage; + int pos; + unsigned char r, g, b; + + pos = IupGetChildPos(ih, child); + + tab_page = gtk_fixed_new(); + gtk_widget_show(tab_page); + + tabtitle = iupAttribGet(child, "TABTITLE"); + if (!tabtitle) tabtitle = iupTabsAttribGetStrId(ih, "TABTITLE", pos); + tabimage = iupAttribGet(child, "TABIMAGE"); + if (!tabimage) tabimage = iupTabsAttribGetStrId(ih, "TABIMAGE", pos); + if (!tabtitle && !tabimage) + tabtitle = " "; + + if (tabtitle) + { + tab_label = gtk_label_new(iupgtkStrConvertToUTF8(tabtitle)); + +#if GTK_CHECK_VERSION(2, 6, 0) + if (ih->data->orientation == ITABS_VERTICAL) + gtk_label_set_angle((GtkLabel*)tab_label, 90); +#endif + } + + if (tabimage) + { + GdkPixbuf* pixbuf = iupImageGetImage(tabimage, ih, 0); + + tab_image = gtk_image_new(); + + if (pixbuf) + gtk_image_set_from_pixbuf((GtkImage*)tab_image, pixbuf); + } + + iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", "1"); + + if (tabimage && tabtitle) + { + GtkWidget* box; + if (ih->data->orientation == ITABS_VERTICAL) + box = gtk_vbox_new(FALSE, 2); + else + box = gtk_hbox_new(FALSE, 2); + gtk_widget_show(box); + + gtk_container_add((GtkContainer*)box, tab_image); + gtk_container_add((GtkContainer*)box, tab_label); + + gtk_notebook_insert_page((GtkNotebook*)ih->handle, tab_page, box, pos); + gtk_notebook_set_menu_label_text((GtkNotebook*)ih->handle, tab_page, gtk_label_get_text((GtkLabel*)tab_label)); + } + else if (tabimage) + gtk_notebook_insert_page((GtkNotebook*)ih->handle, tab_page, tab_image, pos); + else + gtk_notebook_insert_page((GtkNotebook*)ih->handle, tab_page, tab_label, pos); + + gtk_widget_realize(tab_page); + + iupAttribSetStr(child, "_IUPGTK_TABIMAGE", (char*)tab_image); /* store it even if its NULL */ + iupAttribSetStr(child, "_IUPGTK_TABLABEL", (char*)tab_label); + iupAttribSetStr(child, "_IUPTAB_CONTAINER", (char*)tab_page); + iupStrToRGB(IupGetAttribute(ih, "BGCOLOR"), &r, &g, &b); + iupgtkBaseSetBgColor(tab_page, r, g, b); + + if (tabtitle) + { + PangoFontDescription* fontdesc = (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih); + gtk_widget_modify_font(tab_label, fontdesc); + iupgtkFontUpdatePangoLayout(ih, gtk_label_get_layout((GtkLabel*)tab_label)); + + iupgtkBaseSetBgColor(tab_label, r, g, b); + + iupStrToRGB(IupGetAttribute(ih, "FGCOLOR"), &r, &g, &b); + iupgtkBaseSetFgColor(tab_label, r, g, b); + + gtk_widget_show(tab_label); + gtk_widget_realize(tab_label); + } + + if (tabimage) + { + gtk_widget_show(tab_image); + gtk_widget_realize(tab_image); + } + + iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", NULL); + + if (pos == iupdrvTabsGetCurrentTab(ih)) + IupSetAttribute(child, "VISIBLE", "YES"); + else + IupSetAttribute(child, "VISIBLE", "NO"); + } +} + +static void gtkTabsChildRemovedMethod(Ihandle* ih, Ihandle* child) +{ + if (ih->handle) + { + GtkWidget* tab_page = (GtkWidget*)iupAttribGet(child, "_IUPTAB_CONTAINER"); + if (tab_page) + { + int pos = gtk_notebook_page_num((GtkNotebook*)ih->handle, tab_page); + + iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", "1"); + gtk_notebook_remove_page((GtkNotebook*)ih->handle, pos); + iupAttribSetStr(ih, "_IUPGTK_IGNORE_CHANGE", NULL); + + iupAttribSetStr(child, "_IUPGTK_TABIMAGE", NULL); + iupAttribSetStr(child, "_IUPGTK_TABLABEL", NULL); + iupAttribSetStr(child, "_IUPTAB_CONTAINER", NULL); + } + } +} + +static int gtkTabsMapMethod(Ihandle* ih) +{ + ih->handle = gtk_notebook_new(); + if (!ih->handle) + return IUP_ERROR; + + gtk_notebook_set_scrollable((GtkNotebook*)ih->handle, TRUE); + gtk_notebook_popup_enable((GtkNotebook*)ih->handle); + + gtkTabsUpdateTabType(ih); + + /* add to the parent, all GTK controls must call this. */ + iupgtkBaseAddToParent(ih); + + gtk_widget_add_events(ih->handle, GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK); + + g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih); + + g_signal_connect(G_OBJECT(ih->handle), "switch-page", G_CALLBACK(gtkTabSwitchPage), ih); + + gtk_widget_realize(ih->handle); + + /* Create pages and tabs */ + if (ih->firstchild) + { + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + gtkTabsChildAddedMethod(ih, child); + } + + return IUP_NOERROR; +} + +void iupdrvTabsInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkTabsMapMethod; + ic->ChildAdded = gtkTabsChildAddedMethod; + ic->ChildRemoved = gtkTabsChildRemovedMethod; + + /* Driver Dependent Attribute functions */ + + /* Common */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, gtkTabsSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkTabsSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkTabsSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + + /* IupTabs only */ + iupClassRegisterAttribute(ic, "TABTYPE", iupTabsGetTabTypeAttrib, gtkTabsSetTabTypeAttrib, IUPAF_SAMEASSYSTEM, "TOP", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TABORIENTATION", iupTabsGetTabOrientationAttrib, gtkTabsSetTabOrientationAttrib, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TABTITLE", NULL, gtkTabsSetTabTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TABIMAGE", NULL, gtkTabsSetTabImageAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, gtkTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); +} diff --git a/iup/src/gtk/iupgtk_text.c b/iup/src/gtk/iupgtk_text.c new file mode 100755 index 0000000..4c2906a --- /dev/null +++ b/iup/src/gtk/iupgtk_text.c @@ -0,0 +1,1716 @@ +/** \file + * \brief Text Control + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_image.h" +#include "iup_mask.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_image.h" +#include "iup_key.h" +#include "iup_array.h" +#include "iup_text.h" + +#include "iupgtk_drv.h" + +#ifndef PANGO_WEIGHT_SEMIBOLD +#define PANGO_WEIGHT_SEMIBOLD 600 +#endif + +void iupdrvTextAddSpin(int *w, int h) +{ + int spin_size = 16; + *w += spin_size; + (void)h; +} + +void iupdrvTextAddBorders(int *x, int *y) +{ + int border_size = 2*5; + (*x) += border_size; + (*y) += border_size; +} + +static void gtkTextParseParagraphFormat(Ihandle* formattag, GtkTextTag* tag) +{ + int val; + char* format; + + format = iupAttribGet(formattag, "INDENT"); + if (format && iupStrToInt(format, &val)) + g_object_set(G_OBJECT(tag), "indent", val, NULL); + + format = iupAttribGet(formattag, "ALIGNMENT"); + if (format) + { + if (iupStrEqualNoCase(format, "JUSTIFY")) + val = GTK_JUSTIFY_FILL; + else if (iupStrEqualNoCase(format, "RIGHT")) + val = GTK_JUSTIFY_RIGHT; + else if (iupStrEqualNoCase(format, "CENTER")) + val = GTK_JUSTIFY_CENTER; + else /* "LEFT" */ + val = GTK_JUSTIFY_LEFT; + + g_object_set(G_OBJECT(tag), "justification", val, NULL); + } + + format = iupAttribGet(formattag, "TABSARRAY"); + { + PangoTabArray *tabs; + int pos, i = 0; + PangoTabAlign align; + char* str; + + tabs = pango_tab_array_new(32, FALSE); + + while (format) + { + str = iupStrCopyUntil((char**)&format, ' '); + if (!str) break; + pos = atoi(str); + free(str); + + str = iupStrCopyUntil((char**)&format, ' '); + if (!str) break; + +/* if (iupStrEqualNoCase(str, "DECIMAL")) unsupported for now + align = PANGO_TAB_NUMERIC; + else if (iupStrEqualNoCase(str, "RIGHT")) + align = PANGO_TAB_RIGHT; + else if (iupStrEqualNoCase(str, "CENTER")) + align = PANGO_TAB_CENTER; + else */ /* "LEFT" */ + align = PANGO_TAB_LEFT; + free(str); + + pango_tab_array_set_tab(tabs, i, align, IUPGTK_PIXELS2PANGOUNITS(pos)); + i++; + if (i == 32) break; + } + + g_object_set(G_OBJECT(tag), "tabs", tabs, NULL); + pango_tab_array_free(tabs); + } + + format = iupAttribGet(formattag, "SPACEBEFORE"); + if (format && iupStrToInt(format, &val)) + g_object_set(G_OBJECT(tag), "pixels-above-lines", val, NULL); + + format = iupAttribGet(formattag, "SPACEAFTER"); + if (format && iupStrToInt(format, &val)) + g_object_set(G_OBJECT(tag), "pixels-below-lines", val, NULL); + + format = iupAttribGet(formattag, "LINESPACING"); + if (format && iupStrToInt(format, &val)) + g_object_set(G_OBJECT(tag), "pixels-inside-wrap", val, NULL); +} + +static void gtkTextParseCharacterFormat(Ihandle* formattag, GtkTextTag* tag) +{ + int val; + char* format; + + format = iupAttribGet(formattag, "LANGUAGE"); + if (format) + g_object_set(G_OBJECT(tag), "language", format, NULL); + + format = iupAttribGet(formattag, "STRETCH"); + if (format) + { + if (iupStrEqualNoCase(format, "EXTRA_CONDENSED")) + val = PANGO_STRETCH_EXTRA_CONDENSED; + else if (iupStrEqualNoCase(format, "CONDENSED")) + val = PANGO_STRETCH_CONDENSED; + else if (iupStrEqualNoCase(format, "SEMI_CONDENSED")) + val = PANGO_STRETCH_SEMI_CONDENSED; + else if (iupStrEqualNoCase(format, "SEMI_EXPANDED")) + val = PANGO_STRETCH_SEMI_EXPANDED; + else if (iupStrEqualNoCase(format, "EXPANDED")) + val = PANGO_STRETCH_EXPANDED; + else if (iupStrEqualNoCase(format, "EXTRA_EXPANDED")) + val = PANGO_STRETCH_EXTRA_EXPANDED; + else /* "NORMAL" */ + val = PANGO_STRETCH_NORMAL; + + g_object_set(G_OBJECT(tag), "stretch", val, NULL); + } + + format = iupAttribGet(formattag, "RISE"); + if (format) + { + val = 0; + + if (iupStrEqualNoCase(format, "SUPERSCRIPT")) + { + g_object_set(G_OBJECT(tag), "scale", PANGO_SCALE_X_SMALL, NULL); + val = 10; /* 10 pixels up */ + } + else if (iupStrEqualNoCase(format, "SUBSCRIPT")) + { + g_object_set(G_OBJECT(tag), "scale", PANGO_SCALE_X_SMALL, NULL); + val = -10; /* 10 pixels down */ + } + else + iupStrToInt(format, &val); + + val = IUPGTK_PIXELS2PANGOUNITS(val); + g_object_set(G_OBJECT(tag), "rise", val, NULL); + } + + format = iupAttribGet(formattag, "SMALLCAPS"); + if (format) + { + if (iupStrBoolean(format)) + val = PANGO_VARIANT_SMALL_CAPS; + else + val = PANGO_VARIANT_NORMAL; + g_object_set(G_OBJECT(tag), "variant", val, NULL); + } + + format = iupAttribGet(formattag, "ITALIC"); + if (format) + { + if (iupStrBoolean(format)) + val = PANGO_STYLE_ITALIC; + else + val = PANGO_STYLE_NORMAL; + g_object_set(G_OBJECT(tag), "style", val, NULL); + } + + format = iupAttribGet(formattag, "STRIKEOUT"); + if (format) + { + val = iupStrBoolean(format); + g_object_set(G_OBJECT(tag), "strikethrough", val, NULL); + } + + format = iupAttribGet(formattag, "PROTECTED"); + if (format) + { + val = iupStrBoolean(format); + g_object_set(G_OBJECT(tag), "editable", val, NULL); + } + + format = iupAttribGet(formattag, "FONTSIZE"); + if (format && iupStrToInt(format, &val)) + { + if (val < 0) /* in pixels */ + { + val = IUPGTK_PIXELS2PANGOUNITS(-val); + g_object_set(G_OBJECT(tag), "size", val, NULL); + } + else /* in points */ + g_object_set(G_OBJECT(tag), "size-points", (double)val, NULL); + } + + format = iupAttribGet(formattag, "FONTSCALE"); + if (format) + { + float fval = 0; + if (iupStrEqualNoCase(format, "XX-SMALL")) + fval = (float)PANGO_SCALE_XX_SMALL; + else if (iupStrEqualNoCase(format, "X-SMALL")) + fval = (float)PANGO_SCALE_X_SMALL; + else if (iupStrEqualNoCase(format, "SMALL")) + fval = (float)PANGO_SCALE_SMALL; + else if (iupStrEqualNoCase(format, "MEDIUM")) + fval = (float)PANGO_SCALE_MEDIUM; + else if (iupStrEqualNoCase(format, "LARGE")) + fval = (float)PANGO_SCALE_LARGE; + else if (iupStrEqualNoCase(format, "X-LARGE")) + fval = (float)PANGO_SCALE_X_LARGE; + else if (iupStrEqualNoCase(format, "XX-LARGE")) + fval = (float)PANGO_SCALE_XX_LARGE; + else + iupStrToFloat(format, &fval); + + if (fval > 0) + g_object_set(G_OBJECT(tag), "scale", (double)fval, NULL); + } + + format = iupAttribGet(formattag, "FONTFACE"); + if (format) + g_object_set(G_OBJECT(tag), "family", format, NULL); + + format = iupAttribGet(formattag, "FGCOLOR"); + if (format) + { + unsigned char r, g, b; + if (iupStrToRGB(format, &r, &g, &b)) + { + GdkColor color; + iupgdkColorSet(&color, r, g, b); + g_object_set(G_OBJECT(tag), "foreground-gdk", &color, NULL); + } + } + + format = iupAttribGet(formattag, "BGCOLOR"); + if (format) + { + unsigned char r, g, b; + if (iupStrToRGB(format, &r, &g, &b)) + { + GdkColor color; + iupgdkColorSet(&color, r, g, b); + g_object_set(G_OBJECT(tag), "background-gdk", &color, NULL); + } + } + + format = iupAttribGet(formattag, "UNDERLINE"); + if (format) + { + if (iupStrEqualNoCase(format, "SINGLE")) + val = PANGO_UNDERLINE_SINGLE; + else if (iupStrEqualNoCase(format, "DOUBLE")) + val = PANGO_UNDERLINE_DOUBLE; + else /* "NONE" */ + val = PANGO_UNDERLINE_NONE; + + g_object_set(G_OBJECT(tag), "underline", val, NULL); + } + + format = iupAttribGet(formattag, "WEIGHT"); + if (format) + { + if (iupStrEqualNoCase(format, "EXTRALIGHT")) + val = PANGO_WEIGHT_ULTRALIGHT; + else if (iupStrEqualNoCase(format, "LIGHT")) + val = PANGO_WEIGHT_LIGHT; + else if (iupStrEqualNoCase(format, "SEMIBOLD")) + val = PANGO_WEIGHT_SEMIBOLD; + else if (iupStrEqualNoCase(format, "BOLD")) + val = PANGO_WEIGHT_BOLD; + else if (iupStrEqualNoCase(format, "EXTRABOLD")) + val = PANGO_WEIGHT_ULTRABOLD; + else if (iupStrEqualNoCase(format, "HEAVY")) + val = PANGO_WEIGHT_HEAVY; + else /* "NORMAL" */ + val = PANGO_WEIGHT_NORMAL; + + g_object_set(G_OBJECT(tag), "weight", val, NULL); + } +} + +static void gtkTextMoveIterToLinCol(GtkTextBuffer *buffer, GtkTextIter *iter, int lin, int col) +{ + int line_count, line_length; + + lin--; /* IUP starts at 1 */ + col--; + + line_count = gtk_text_buffer_get_line_count(buffer); + if (lin < 0) lin = 0; + if (lin >= line_count) + lin = line_count-1; + + gtk_text_buffer_get_iter_at_line(buffer, iter, lin); + line_length = gtk_text_iter_get_chars_in_line(iter); + + if (col < 0) col = 0; + if (col > line_length) + col = line_length; /* after the last character */ + + gtk_text_iter_set_line_offset(iter, col); +} + +static void gtkTextGetLinColFromPosition(const GtkTextIter *iter, int *lin, int *col) +{ + *lin = gtk_text_iter_get_line(iter); + *col = gtk_text_iter_get_line_offset(iter); + + (*lin)++; /* IUP starts at 1 */ + (*col)++; +} + +static int gtkTextGetCharSize(Ihandle* ih) +{ + int charwidth; + PangoFontMetrics* metrics; + PangoContext* context; + PangoFontDescription* fontdesc = (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih); + if (!fontdesc) + return 0; + + context = gdk_pango_context_get(); + metrics = pango_context_get_metrics(context, fontdesc, pango_context_get_language(context)); + charwidth = pango_font_metrics_get_approximate_char_width(metrics); + pango_font_metrics_unref(metrics); + return charwidth; +} + +void iupdrvTextConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos) +{ + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtkTextMoveIterToLinCol(buffer, &iter, lin, col); + *pos = gtk_text_iter_get_offset(&iter); +} + +void iupdrvTextConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col) +{ + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_iter_at_offset(buffer, &iter, pos); + gtkTextGetLinColFromPosition(&iter, lin, col); +} + +static int gtkTextConvertXYToPos(Ihandle* ih, int x, int y) +{ + if (ih->data->is_multiline) + { + GtkTextIter iter; + gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(ih->handle), GTK_TEXT_WINDOW_WIDGET, x, y, &x, &y); + gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(ih->handle), &iter, x, y); + return gtk_text_iter_get_offset(&iter); + } + else + { + int trailing, off_x, off_y, pos; + + /* transform to Layout coordinates */ + gtk_entry_get_layout_offsets(GTK_ENTRY(ih->handle), &off_x, &off_y); + x = IUPGTK_PIXELS2PANGOUNITS(x - off_x); + y = IUPGTK_PIXELS2PANGOUNITS(y - off_y); + + pango_layout_xy_to_index(gtk_entry_get_layout(GTK_ENTRY(ih->handle)), x, y, &pos, &trailing); + return pos; + } +} + +static void gtkTextScrollToVisible(Ihandle* ih) +{ + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + GtkTextMark* mark = gtk_text_buffer_get_insert(buffer); + gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(ih->handle), mark); +} + + +/*******************************************************************************************/ + + +static int gtkTextSetSelectionAttrib(Ihandle* ih, const char* value) +{ + if (!value) + return 0; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + if (ih->data->is_multiline) + { + GtkTextIter start_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_start_iter(buffer, &start_iter); + gtk_text_buffer_select_range(buffer, &start_iter, &start_iter); + } + else + gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, 0); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + if (ih->data->is_multiline) + { + GtkTextIter start_iter; + GtkTextIter end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_start_iter(buffer, &start_iter); + gtk_text_buffer_get_end_iter(buffer, &end_iter); + gtk_text_buffer_select_range(buffer, &start_iter, &end_iter); + } + else + gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, -1); + return 0; + } + + if (ih->data->is_multiline) + { + int lin_start=1, col_start=1, lin_end=1, col_end=1; + GtkTextIter start_iter, end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + + if (sscanf(value, "%d,%d:%d,%d", &lin_start, &col_start, &lin_end, &col_end)!=4) return 0; + if (lin_start<1 || col_start<1 || lin_end<1 || col_end<1) return 0; + + gtkTextMoveIterToLinCol(buffer, &start_iter, lin_start, col_start); + gtkTextMoveIterToLinCol(buffer, &end_iter, lin_end, col_end); + + gtk_text_buffer_select_range(buffer, &start_iter, &end_iter); + } + else + { + int start=1, end=1; + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<1 || end<1) + return 0; + + start--; /* IUP starts at 1 */ + end--; + + gtk_editable_select_region(GTK_EDITABLE(ih->handle), start, end); + } + + return 0; +} + +static char* gtkTextGetSelectionAttrib(Ihandle* ih) +{ + char *str; + + if (ih->data->is_multiline) + { + int start_col, start_lin, end_col, end_lin; + + GtkTextIter start_iter, end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter)) + { + gtkTextGetLinColFromPosition(&start_iter, &start_lin, &start_col); + gtkTextGetLinColFromPosition(&end_iter, &end_lin, &end_col); + + str = iupStrGetMemory(100); + sprintf(str,"%d,%d:%d,%d", start_lin, start_col, end_lin, end_col); + return str; + } + } + else + { + int start, end; + if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end)) + { + start++; /* IUP starts at 1 */ + end++; + str = iupStrGetMemory(100); + sprintf(str, "%d:%d", (int)start, (int)end); + return str; + } + } + + return NULL; +} + +static int gtkTextSetSelectionPosAttrib(Ihandle* ih, const char* value) +{ + int start=0, end=0; + + if (!value) + return 0; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + if (ih->data->is_multiline) + { + GtkTextIter start_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_start_iter(buffer, &start_iter); + gtk_text_buffer_select_range(buffer, &start_iter, &start_iter); + } + else + gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, 0); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + if (ih->data->is_multiline) + { + GtkTextIter start_iter; + GtkTextIter end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_start_iter(buffer, &start_iter); + gtk_text_buffer_get_end_iter(buffer, &end_iter); + gtk_text_buffer_select_range(buffer, &start_iter, &end_iter); + } + else + gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, -1); + return 0; + } + + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<0 || end<0) + return 0; + + if (ih->data->is_multiline) + { + GtkTextIter start_iter, end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + + gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, start); + gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, end); + + gtk_text_buffer_select_range(buffer, &start_iter, &end_iter); + } + else + gtk_editable_select_region(GTK_EDITABLE(ih->handle), start, end); + + return 0; +} + +static char* gtkTextGetSelectionPosAttrib(Ihandle* ih) +{ + int start, end; + char *str; + + if (ih->data->is_multiline) + { + GtkTextIter start_iter, end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter)) + { + start = gtk_text_iter_get_offset(&start_iter); + end = gtk_text_iter_get_offset(&end_iter); + + str = iupStrGetMemory(100); + sprintf(str, "%d:%d", (int)start, (int)end); + return str; + } + } + else + { + if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end)) + { + str = iupStrGetMemory(100); + sprintf(str, "%d:%d", (int)start, (int)end); + return str; + } + } + + return NULL; +} + +static int gtkTextSetSelectedTextAttrib(Ihandle* ih, const char* value) +{ + if (!value) + return 0; + + if (ih->data->is_multiline) + { + GtkTextIter start_iter, end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter)) + { + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + gtk_text_buffer_delete(buffer, &start_iter, &end_iter); + gtk_text_buffer_insert(buffer, &start_iter, iupgtkStrConvertToUTF8(value), -1); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + } + } + else + { + int start, end; + if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end)) + { + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + gtk_editable_delete_selection(GTK_EDITABLE(ih->handle)); + gtk_editable_insert_text(GTK_EDITABLE(ih->handle), iupgtkStrConvertToUTF8(value), -1, &start); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + } + } + + return 0; +} + +static char* gtkTextGetSelectedTextAttrib(Ihandle* ih) +{ + if (ih->data->is_multiline) + { + GtkTextIter start_iter, end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter)) + return iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, TRUE))); + } + else + { + int start, end; + if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end)) + { + char* selectedtext = gtk_editable_get_chars(GTK_EDITABLE(ih->handle), start, end); + char* str = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(selectedtext)); + g_free(selectedtext); + return str; + } + } + + return NULL; +} + +static int gtkTextSetCaretAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + + if (!value) + return 0; + + if (ih->data->is_multiline) + { + int lin = 1, col = 1; + GtkTextIter iter; + + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + + iupStrToIntInt(value, &lin, &col, ','); + + gtkTextMoveIterToLinCol(buffer, &iter, lin, col); + + gtk_text_buffer_place_cursor(buffer, &iter); + gtkTextScrollToVisible(ih); + } + else + { + sscanf(value,"%i",&pos); + pos--; /* IUP starts at 1 */ + if (pos < 0) pos = 0; + + gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos); + } + + return 0; +} + +static char* gtkTextGetCaretAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(50); + + if (ih->data->is_multiline) + { + int col, lin; + GtkTextIter iter; + + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_iter_at_mark(buffer, &iter, gtk_text_buffer_get_insert(buffer)); + gtkTextGetLinColFromPosition(&iter, &lin, &col); + + sprintf(str, "%d,%d", lin, col); + } + else + { + int pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle)); + pos++; /* IUP starts at 1 */ + sprintf(str, "%d", (int)pos); + } + + return str; +} + +static int gtkTextSetCaretPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + if (ih->data->is_multiline) + { + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_iter_at_offset(buffer, &iter, pos); + gtk_text_buffer_place_cursor(buffer, &iter); + gtkTextScrollToVisible(ih); + } + else + gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos); + + return 0; +} + +static char* gtkTextGetCaretPosAttrib(Ihandle* ih) +{ + int pos; + char* str = iupStrGetMemory(50); + + if (ih->data->is_multiline) + { + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_iter_at_mark(buffer, &iter, gtk_text_buffer_get_insert(buffer)); + pos = gtk_text_iter_get_offset(&iter); + } + else + pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle)); + + sprintf(str, "%d", (int)pos); + return str; +} + +static int gtkTextSetScrollToAttrib(Ihandle* ih, const char* value) +{ + if (!value) + return 0; + + if (ih->data->is_multiline) + { + int lin = 1, col = 1; + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + + iupStrToIntInt(value, &lin, &col, ','); + if (lin < 1) lin = 1; + if (col < 1) col = 1; + + gtkTextMoveIterToLinCol(buffer, &iter, lin, col); + gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ih->handle), &iter, 0, FALSE, 0, 0); + } + else + { + int pos = 1; + sscanf(value,"%i",&pos); + if (pos < 1) pos = 1; + pos--; /* return to GTK referece */ + gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos); + } + + return 0; +} + +static int gtkTextSetScrollToPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + if (ih->data->is_multiline) + { + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_iter_at_offset(buffer, &iter, pos); + gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ih->handle), &iter, 0, FALSE, 0, 0); + } + else + gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos); + + return 0; +} + +static int gtkTextSetValueAttrib(Ihandle* ih, const char* value) +{ + if (!value) value = ""; + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + if (ih->data->is_multiline) + { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_set_text(buffer, iupgtkStrConvertToUTF8(value), -1); + } + else + gtk_entry_set_text(GTK_ENTRY(ih->handle), iupgtkStrConvertToUTF8(value)); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + return 0; +} + +static char* gtkTextGetValueAttrib(Ihandle* ih) +{ + char* value; + + if (ih->data->is_multiline) + { + GtkTextIter start_iter; + GtkTextIter end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_start_iter(buffer, &start_iter); + gtk_text_buffer_get_end_iter(buffer, &end_iter); + value = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, TRUE))); + } + else + value = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_entry_get_text(GTK_ENTRY(ih->handle)))); + + if (!value) value = ""; + + return value; +} + +static int gtkTextSetInsertAttrib(Ihandle* ih, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + if (!value) + return 0; + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + if (ih->data->is_multiline) + { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_insert_at_cursor(buffer, iupgtkStrConvertToUTF8(value), -1); + } + else + { + gint pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle)); + gtk_editable_insert_text(GTK_EDITABLE(ih->handle), iupgtkStrConvertToUTF8(value), -1, &pos); + } + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + + return 0; +} + +static int gtkTextSetAppendAttrib(Ihandle* ih, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + if (ih->data->is_multiline) + { + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_end_iter(buffer, &iter); + if (ih->data->append_newline) + gtk_text_buffer_insert(buffer, &iter, "\n", 1); + gtk_text_buffer_insert(buffer, &iter, iupgtkStrConvertToUTF8(value), -1); + } + else + { + gint pos = strlen(gtk_entry_get_text(GTK_ENTRY(ih->handle)))+1; + gtk_editable_insert_text(GTK_EDITABLE(ih->handle), iupgtkStrConvertToUTF8(value), -1, &pos); + } + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + return 0; +} + +static int gtkTextSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + float xalign; + GtkJustification justification; + + if (iupStrEqualNoCase(value, "ARIGHT")) + { + xalign = 1.0f; + justification = GTK_JUSTIFY_RIGHT; + } + else if (iupStrEqualNoCase(value, "ACENTER")) + { + xalign = 0.5f; + justification = GTK_JUSTIFY_CENTER; + } + else /* "ALEFT" */ + { + xalign = 0; + justification = GTK_JUSTIFY_LEFT; + } + + if (ih->data->is_multiline) + gtk_text_view_set_justification(GTK_TEXT_VIEW(ih->handle), justification); + else + gtk_entry_set_alignment(GTK_ENTRY(ih->handle), xalign); + + return 1; +} + +static int gtkTextSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle) + { + if (ih->data->is_multiline) + { + gtk_text_view_set_left_margin(GTK_TEXT_VIEW(ih->handle), ih->data->horiz_padding); + gtk_text_view_set_right_margin(GTK_TEXT_VIEW(ih->handle), ih->data->horiz_padding); + ih->data->vert_padding = 0; + } + else + { +#if GTK_CHECK_VERSION(2, 10, 0) + GtkBorder border; + border.bottom = border.top = ih->data->vert_padding; + border.left = border.right = ih->data->horiz_padding; + gtk_entry_set_inner_border(GTK_ENTRY(ih->handle), &border); +#endif + } + } + return 0; +} + +static int gtkTextSetNCAttrib(Ihandle* ih, const char* value) +{ + if (!iupStrToInt(value, &ih->data->nc)) + ih->data->nc = INT_MAX; + + if (!ih->data->is_multiline && ih->handle) + gtk_entry_set_max_length(GTK_ENTRY(ih->handle), ih->data->nc); + + return 0; +} + +static int gtkTextSetClipboardAttrib(Ihandle *ih, const char *value) +{ + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + if (iupStrEqualNoCase(value, "COPY")) + { + if (ih->data->is_multiline) + { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + GtkClipboard *clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)); + gtk_text_buffer_copy_clipboard(buffer, clipboard); + } + else + gtk_editable_copy_clipboard(GTK_EDITABLE(ih->handle)); + } + else if (iupStrEqualNoCase(value, "CUT")) + { + if (ih->data->is_multiline) + { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + GtkClipboard *clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)); + gtk_text_buffer_cut_clipboard(buffer, clipboard, TRUE); + } + else + gtk_editable_cut_clipboard(GTK_EDITABLE(ih->handle)); + } + else if (iupStrEqualNoCase(value, "PASTE")) + { + if (ih->data->is_multiline) + { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + GtkClipboard *clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)); + gtk_text_buffer_paste_clipboard(buffer, clipboard, NULL, TRUE); + } + else + gtk_editable_paste_clipboard(GTK_EDITABLE(ih->handle)); + } + else if (iupStrEqualNoCase(value, "CLEAR")) + { + if (ih->data->is_multiline) + { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_delete_selection(buffer, FALSE, TRUE); + } + else + gtk_editable_delete_selection(GTK_EDITABLE(ih->handle)); + } + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + return 0; +} + +static int gtkTextSetReadOnlyAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->is_multiline) + gtk_text_view_set_editable(GTK_TEXT_VIEW(ih->handle), !iupStrBoolean(value)); + else + gtk_editable_set_editable(GTK_EDITABLE(ih->handle), !iupStrBoolean(value)); + return 0; +} + +static char* gtkTextGetReadOnlyAttrib(Ihandle* ih) +{ + int editable; + if (ih->data->is_multiline) + editable = gtk_text_view_get_editable(GTK_TEXT_VIEW(ih->handle)); + else + editable = gtk_editable_get_editable(GTK_EDITABLE(ih->handle)); + if (!editable) + return "YES"; + else + return "NO"; +} + +static char* gtkTextGetPangoLayoutAttrib(Ihandle* ih) +{ + if (ih->data->is_multiline) + return NULL; + else + return (char*)gtk_entry_get_layout(GTK_ENTRY(ih->handle)); +} + +static int gtkTextSetBgColorAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->is_multiline) + { + GtkScrolledWindow* scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + unsigned char r, g, b; + + /* ignore given value, must use only from parent for the scrollbars */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + if (iupStrToRGB(parent_value, &r, &g, &b)) + { + GtkWidget* sb; + + iupgtkBaseSetBgColor((GtkWidget*)scrolled_window, r, g, b); + +#if GTK_CHECK_VERSION(2, 8, 0) + sb = gtk_scrolled_window_get_hscrollbar(scrolled_window); + if (sb) iupgtkBaseSetBgColor(sb, r, g, b); + + sb = gtk_scrolled_window_get_vscrollbar(scrolled_window); + if (sb) iupgtkBaseSetBgColor(sb, r, g, b); +#endif + } + } + + return iupdrvBaseSetBgColorAttrib(ih, value); +} + +static int gtkTextSetTabSizeAttrib(Ihandle* ih, const char* value) +{ + PangoTabArray *tabs; + int tabsize, charwidth; + if (!ih->data->is_multiline) + return 0; + + iupStrToInt(value, &tabsize); + charwidth = gtkTextGetCharSize(ih); + tabsize *= charwidth; + tabs = pango_tab_array_new_with_positions(1, FALSE, PANGO_TAB_LEFT, tabsize); + gtk_text_view_set_tabs(GTK_TEXT_VIEW(ih->handle), tabs); + pango_tab_array_free(tabs); + return 1; +} + +static int gtkTextSetOverwriteAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->is_multiline) + return 0; + gtk_text_view_set_overwrite(GTK_TEXT_VIEW(ih->handle), iupStrBoolean(value)); + return 0; +} + +static char* gtkTextGetOverwriteAttrib(Ihandle* ih) +{ + if (!ih->data->is_multiline) + return "NO"; + if (gtk_text_view_get_overwrite(GTK_TEXT_VIEW(ih->handle))) + return "YES"; + else + return "NO"; +} + +void iupdrvTextAddFormatTag(Ihandle* ih, Ihandle* formattag) +{ + GtkTextBuffer *buffer; + GtkTextIter start_iter, end_iter; + GtkTextTag* tag; + char *selection; + + if (!ih->data->is_multiline) + return; + + selection = iupAttribGet(formattag, "SELECTION"); + if (selection) + { + /* simulate Windows behavior and change the current selection */ + gtkTextSetSelectionAttrib(ih, selection); + iupAttribSetStr(ih, "SELECTION", NULL); + } + else + { + char* selectionpos = iupAttribGet(formattag, "SELECTIONPOS"); + if (selectionpos) + { + /* simulate Windows behavior and change the current selection */ + gtkTextSetSelectionPosAttrib(ih, selectionpos); + iupAttribSetStr(ih, "SELECTIONPOS", NULL); + } + } + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + if (!gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter)) + { + GtkTextMark* mark = gtk_text_buffer_get_insert(buffer); + gtk_text_buffer_get_iter_at_mark(buffer, &start_iter, mark); + gtk_text_buffer_get_iter_at_mark(buffer, &end_iter, mark); + } + + tag = gtk_text_buffer_create_tag(buffer, NULL, NULL); + gtkTextParseParagraphFormat(formattag, tag); + gtkTextParseCharacterFormat(formattag, tag); + gtk_text_buffer_apply_tag(buffer, tag, &start_iter, &end_iter); + + /* reset the selection */ + gtkTextSetSelectionAttrib(ih, NULL); +} + +static int gtkTextSetRemoveFormattingAttrib(Ihandle* ih, const char* value) +{ + GtkTextBuffer *buffer; + GtkTextIter start_iter, end_iter; + + if (!ih->data->is_multiline) + return 0; + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter)) + gtk_text_buffer_remove_all_tags(buffer, &start_iter, &end_iter); + + (void)value; + return 0; +} + + +/************************************************************************************************/ + +static gboolean gtkTextSpinOutput(GtkSpinButton *spin, Ihandle* ih) +{ + if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO")) + { + iupAttribSetInt(ih, "_IUPGTK_SPIN_VALUE", (int)spin->adjustment->value); + return TRUE; /* disable output update */ + } + else + { + iupAttribSetStr(ih, "_IUPGTK_SPIN_OLDVALUE", gtk_entry_get_text(GTK_ENTRY(ih->handle))); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + return FALSE; + } +} + +static gint gtkTextSpinInput(GtkSpinButton *spin, gdouble *val, Ihandle* ih) +{ + (void)spin; + *val = (double)iupAttribGetInt(ih, "_IUPGTK_SPIN_VALUE"); + /* called only when SPINAUTO=NO */ + return TRUE; /* disable input update */ +} + +static void gtkTextSpinValueChanged(GtkSpinButton* spin, Ihandle* ih) +{ + IFni cb; + + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + + cb = (IFni)IupGetCallback(ih, "SPIN_CB"); + if (cb) + { + int pos, ret; + if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO")) + pos = iupAttribGetInt(ih, "_IUPGTK_SPIN_VALUE"); + else + pos = gtk_spin_button_get_value_as_int((GtkSpinButton*)ih->handle); + + ret = cb(ih, pos); + if (ret == IUP_IGNORE) + { + /* this is not working: g_signal_stop_emission_by_name(spin, "value_changed"); */ + } + } + + (void)spin; +} + +static int gtkTextSetSpinMinAttrib(Ihandle* ih, const char* value) +{ + if (GTK_IS_SPIN_BUTTON(ih->handle)) + { + int min; + if (iupStrToInt(value, &min)) + { + int max = iupAttribGetInt(ih, "SPINMAX"); + + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih); + + gtk_spin_button_set_range((GtkSpinButton*)ih->handle, (double)min, (double)max); + + g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + } + } + return 1; +} + +static int gtkTextSetSpinMaxAttrib(Ihandle* ih, const char* value) +{ + if (GTK_IS_SPIN_BUTTON(ih->handle)) + { + int max; + if (iupStrToInt(value, &max)) + { + int min = iupAttribGetInt(ih, "SPINMIN"); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih); + + gtk_spin_button_set_range((GtkSpinButton*)ih->handle, (double)min, (double)max); + + g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + } + } + return 1; +} + +static int gtkTextSetSpinIncAttrib(Ihandle* ih, const char* value) +{ + if (GTK_IS_SPIN_BUTTON(ih->handle)) + { + int inc; + if (iupStrToInt(value, &inc)) + gtk_spin_button_set_increments((GtkSpinButton*)ih->handle, (double)inc, (double)(inc*10)); + } + return 1; +} + +static int gtkTextSetSpinValueAttrib(Ihandle* ih, const char* value) +{ + if (GTK_IS_SPIN_BUTTON(ih->handle)) + { + int pos; + if (iupStrToInt(value, &pos)) + { + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih); + + gtk_spin_button_set_value((GtkSpinButton*)ih->handle, (double)pos); + + g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + + if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO")) + iupAttribSetInt(ih, "_IUPGTK_SPIN_VALUE", pos); + } + } + return 1; +} + +static char* gtkTextGetSpinValueAttrib(Ihandle* ih) +{ + if (GTK_IS_SPIN_BUTTON(ih->handle)) + { + int pos; + char *str = iupStrGetMemory(50); + + if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO")) + pos = iupAttribGetInt(ih, "_IUPGTK_SPIN_VALUE"); + else + pos = gtk_spin_button_get_value_as_int((GtkSpinButton*)ih->handle); + + sprintf(str, "%d", pos); + return str; + } + return NULL; +} + + +/**********************************************************************************************************/ + + +static void gtkTextMoveCursor(GtkWidget *w, GtkMovementStep step, gint count, gboolean extend_selection, Ihandle* ih) +{ + int col, lin, pos; + + IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB"); + if (!cb) return; + + if (ih->data->is_multiline) + { + GtkTextIter iter; + + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_iter_at_mark(buffer, &iter, gtk_text_buffer_get_insert(buffer)); + gtkTextGetLinColFromPosition(&iter, &lin, &col); + pos = gtk_text_iter_get_offset(&iter); + } + else + { + pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle)); + col = pos; + col++; /* IUP starts at 1 */ + lin = 1; + } + + if (pos != ih->data->last_caret_pos) + { + ih->data->last_caret_pos = pos; + + cb(ih, lin, col, pos); + } + + (void)w; + (void)step; + (void)count; + (void)extend_selection; +} + +static gboolean gtkTextKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) +{ + gtkTextMoveCursor(NULL, 0, 0, 0, ih); + (void)widget; + (void)evt; + return FALSE; +} + +static gboolean gtkTextButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih) +{ + gtkTextMoveCursor(NULL, 0, 0, 0, ih); + return iupgtkButtonEvent(widget, evt, ih); +} + +static int gtkTextCallActionCb(Ihandle* ih, const char* insert_value, int len, int start, int end) +{ + char *new_value, *value; + int ret = -1, key = 0; + + IFnis cb = (IFnis)IupGetCallback(ih, "ACTION"); + if (!cb && !ih->data->mask) + return -1; /* continue */ + + value = gtkTextGetValueAttrib(ih); /* new_value is the internal buffer */ + + if (!insert_value) + { + new_value = iupStrDup(value); + if (end<0) end = strlen(value)+1; + iupStrRemove(new_value, start, end, 1); + } + else + { + if (value[0]==0) + new_value = iupStrDup(insert_value); + else + { + if (len < end-start) + { + new_value = iupStrDup(value); + new_value = iupStrInsert(new_value, insert_value, start, end); + } + else + new_value = iupStrInsert(value, insert_value, start, end); + } + } + + if (insert_value && insert_value[0]!=0 && insert_value[1]==0) + key = insert_value[0]; + + if (!new_value) + return -1; /* continue */ + + if (ih->data->nc && (int)strlen(new_value) > ih->data->nc) + { + if (new_value != value) free(new_value); + return 0; /* abort */ + } + + if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0) + { + if (new_value != value) free(new_value); + return 0; /* abort */ + } + + if (cb) + { + int cb_ret = cb(ih, key, (char*)new_value); + if (cb_ret==IUP_IGNORE) + ret = 0; /* abort */ + else if (cb_ret==IUP_CLOSE) + { + IupExitLoop(); + ret = 0; /* abort */ + } + else if (cb_ret!=0 && key!=0 && + cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE) + ret = cb_ret; /* abort and replace */ + } + + if (new_value != value) free(new_value); + return ret; /* continue */ +} + +static void gtkTextEntryDeleteText(GtkEditable *editable, int start, int end, Ihandle* ih) +{ + if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB")) + return; + + if (gtkTextCallActionCb(ih, NULL, 0, start, end)==0) + g_signal_stop_emission_by_name (editable, "delete_text"); +} + +static void gtkTextEntryInsertText(GtkEditable *editable, char *insert_value, int len, int *pos, Ihandle* ih) +{ + int ret; + + if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB")) + return; + + ret = gtkTextCallActionCb(ih, iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(insert_value)), len, *pos, *pos); + if (ret == 0) + g_signal_stop_emission_by_name(editable, "insert_text"); + else if (ret != -1) + { + insert_value[0] = (char)ret; /* replace key */ + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + gtk_editable_insert_text(editable, insert_value, 1, pos); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + + g_signal_stop_emission_by_name(editable, "insert_text"); + } +} + +static void gtkTextBufferDeleteRange(GtkTextBuffer *textbuffer, GtkTextIter *start_iter, GtkTextIter *end_iter, Ihandle* ih) +{ + int start, end; + if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB")) + return; + + start = gtk_text_iter_get_offset(start_iter); + end = gtk_text_iter_get_offset(end_iter); + + if (gtkTextCallActionCb(ih, NULL, 0, start, end)==0) + g_signal_stop_emission_by_name (textbuffer, "delete_range"); +} + +static void gtkTextBufferInsertText(GtkTextBuffer *textbuffer, GtkTextIter *pos_iter, gchar *insert_value, gint len, Ihandle* ih) +{ + int ret, pos; + + if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB")) + return; + + pos = gtk_text_iter_get_offset(pos_iter); + + ret = gtkTextCallActionCb(ih, iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(insert_value)), len, pos, pos); + if (ret == 0) + g_signal_stop_emission_by_name(textbuffer, "insert_text"); + else if (ret != -1) + { + insert_value[0] = (char)ret; /* replace key */ + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + gtk_text_buffer_insert(textbuffer, pos_iter, insert_value, 1); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + + g_signal_stop_emission_by_name(textbuffer, "insert_text"); + } +} + +static void gtkTextChanged(void* dummy, Ihandle* ih) +{ + if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB")) + return; + + iupBaseCallValueChangedCb(ih); + (void)dummy; +} + +/**********************************************************************************************************/ + + +static int gtkTextMapMethod(Ihandle* ih) +{ + GtkScrolledWindow* scrolled_window = NULL; + + if (ih->data->is_multiline) + { + GtkPolicyType hscrollbar_policy, vscrollbar_policy; + int wordwrap = 0; + + ih->handle = gtk_text_view_new(); + if (!ih->handle) + return IUP_ERROR; + + scrolled_window = (GtkScrolledWindow*)gtk_scrolled_window_new(NULL, NULL); + if (!scrolled_window) + return IUP_ERROR; + + gtk_container_add((GtkContainer*)scrolled_window, ih->handle); + gtk_widget_show((GtkWidget*)scrolled_window); + + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)scrolled_window); + + /* formatting is always supported when MULTILINE=YES */ + ih->data->has_formatting = 1; + + if (iupAttribGetBoolean(ih, "WORDWRAP")) + { + wordwrap = 1; + ih->data->sb &= ~IUP_SB_HORIZ; /* must remove the horizontal scroolbar */ + } + + if (iupAttribGetBoolean(ih, "BORDER")) + gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_IN); + else + gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_NONE); + + if (ih->data->sb & IUP_SB_HORIZ) + { + if (iupAttribGetBoolean(ih, "AUTOHIDE")) + hscrollbar_policy = GTK_POLICY_AUTOMATIC; + else + hscrollbar_policy = GTK_POLICY_ALWAYS; + } + else + hscrollbar_policy = GTK_POLICY_NEVER; + + if (ih->data->sb & IUP_SB_VERT) + { + if (iupAttribGetBoolean(ih, "AUTOHIDE")) + vscrollbar_policy = GTK_POLICY_AUTOMATIC; + else + vscrollbar_policy = GTK_POLICY_ALWAYS; + } + else + vscrollbar_policy = GTK_POLICY_NEVER; + + gtk_scrolled_window_set_policy(scrolled_window, hscrollbar_policy, vscrollbar_policy); + + if (wordwrap) + gtk_text_view_set_wrap_mode((GtkTextView*)ih->handle, GTK_WRAP_WORD); + + gtk_widget_add_events(ih->handle, GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK); + } + else + { + if (iupAttribGetBoolean(ih, "SPIN")) + ih->handle = gtk_spin_button_new_with_range(0, 100, 1); + else + ih->handle = gtk_entry_new(); + + if (!ih->handle) + return IUP_ERROR; + + /* formatting is never supported when MULTILINE=NO */ + ih->data->has_formatting = 0; + + gtk_entry_set_has_frame((GtkEntry*)ih->handle, IupGetInt(ih, "BORDER")); + + if (iupAttribGetBoolean(ih, "PASSWORD")) + gtk_entry_set_visibility((GtkEntry*)ih->handle, FALSE); + + if (GTK_IS_SPIN_BUTTON(ih->handle)) + { + gtk_spin_button_set_numeric((GtkSpinButton*)ih->handle, FALSE); + gtk_spin_button_set_digits((GtkSpinButton*)ih->handle, 0); + + gtk_spin_button_set_wrap((GtkSpinButton*)ih->handle, iupAttribGetBoolean(ih, "SPINWRAP")); + + g_signal_connect(G_OBJECT(ih->handle), "value-changed", G_CALLBACK(gtkTextSpinValueChanged), ih); + g_signal_connect(G_OBJECT(ih->handle), "output", G_CALLBACK(gtkTextSpinOutput), ih); + + if (!iupAttribGetBoolean(ih, "SPINAUTO")) + { + g_signal_connect(G_OBJECT(ih->handle), "input", G_CALLBACK(gtkTextSpinInput), ih); + iupAttribSetStr(ih, "_IUPGTK_SPIN_NOAUTO", "1"); + } + } + } + + /* add to the parent, all GTK controls must call this. */ + iupgtkBaseAddToParent(ih); + + if (!iupAttribGetBoolean(ih, "CANFOCUS")) + GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS; + + g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih); + + g_signal_connect_after(G_OBJECT(ih->handle), "move-cursor", G_CALLBACK(gtkTextMoveCursor), ih); /* only report some caret movements */ + g_signal_connect_after(G_OBJECT(ih->handle), "key-release-event", G_CALLBACK(gtkTextKeyReleaseEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkTextButtonEvent), ih); /* if connected "after" then it is ignored */ + g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkTextButtonEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "motion-notify-event",G_CALLBACK(iupgtkMotionNotifyEvent), ih); + + if (ih->data->is_multiline) + { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + g_signal_connect(G_OBJECT(buffer), "delete-range", G_CALLBACK(gtkTextBufferDeleteRange), ih); + g_signal_connect(G_OBJECT(buffer), "insert-text", G_CALLBACK(gtkTextBufferInsertText), ih); + g_signal_connect(G_OBJECT(buffer), "changed", G_CALLBACK(gtkTextChanged), ih); + } + else + { + g_signal_connect(G_OBJECT(ih->handle), "delete-text", G_CALLBACK(gtkTextEntryDeleteText), ih); + g_signal_connect(G_OBJECT(ih->handle), "insert-text", G_CALLBACK(gtkTextEntryInsertText), ih); + g_signal_connect(G_OBJECT(ih->handle), "changed", G_CALLBACK(gtkTextChanged), ih); + } + + if (scrolled_window) + gtk_widget_realize((GtkWidget*)scrolled_window); + gtk_widget_realize(ih->handle); + + /* configure for DRAG&DROP */ + if (IupGetCallback(ih, "DROPFILES_CB")) + iupAttribSetStr(ih, "DRAGDROP", "YES"); + + /* update a mnemonic in a label if necessary */ + iupgtkUpdateMnemonic(ih); + + if (ih->data->formattags) + iupTextUpdateFormatTags(ih); + + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)gtkTextConvertXYToPos); + + return IUP_NOERROR; +} + +void iupdrvTextInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkTextMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Common GTK only (when text is in a secondary element) */ + iupClassRegisterAttribute(ic, "PANGOLAYOUT", gtkTextGetPangoLayoutAttrib, NULL, NULL, NULL, IUPAF_NO_INHERIT); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkTextSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT); + + /* IupText only */ + iupClassRegisterAttribute(ic, "PADDING", iupTextGetPaddingAttrib, gtkTextSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "VALUE", gtkTextGetValueAttrib, gtkTextSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTEDTEXT", gtkTextGetSelectedTextAttrib, gtkTextSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTION", gtkTextGetSelectionAttrib, gtkTextSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTIONPOS", gtkTextGetSelectionPosAttrib, gtkTextSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARET", gtkTextGetCaretAttrib, gtkTextSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARETPOS", gtkTextGetCaretPosAttrib, gtkTextSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INSERT", NULL, gtkTextSetInsertAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "APPEND", NULL, gtkTextSetAppendAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "READONLY", gtkTextGetReadOnlyAttrib, gtkTextSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "NC", iupTextGetNCAttrib, gtkTextSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, gtkTextSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTO", NULL, gtkTextSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, gtkTextSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINMIN", NULL, gtkTextSetSpinMinAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINMAX", NULL, gtkTextSetSpinMaxAttrib, IUPAF_SAMEASSYSTEM, "100", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPININC", NULL, gtkTextSetSpinIncAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINVALUE", gtkTextGetSpinValueAttrib, gtkTextSetSpinValueAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT); + + /* IupText Windows and GTK only */ + iupClassRegisterAttribute(ic, "ADDFORMATTAG", NULL, iupTextSetAddFormatTagAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ADDFORMATTAG_HANDLE", NULL, iupTextSetAddFormatTagHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, gtkTextSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ALEFT", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FORMATTING", iupTextGetFormattingAttrib, iupTextSetFormattingAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "OVERWRITE", gtkTextGetOverwriteAttrib, gtkTextSetOverwriteAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "REMOVEFORMATTING", NULL, gtkTextSetRemoveFormattingAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TABSIZE", NULL, gtkTextSetTabSizeAttrib, "8", NULL, IUPAF_DEFAULT); /* force new default value */ + iupClassRegisterAttribute(ic, "PASSWORD", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); +} diff --git a/iup/src/gtk/iupgtk_timer.c b/iup/src/gtk/iupgtk_timer.c new file mode 100755 index 0000000..ecbefa3 --- /dev/null +++ b/iup/src/gtk/iupgtk_timer.c @@ -0,0 +1,61 @@ +/** \file + * \brief Timer for the GTK Driver. + * + * See Copyright Notice in "iup.h" + */ + + +#include <stdio.h> +#include <stdlib.h> + +#include <gtk/gtk.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_assert.h" +#include "iup_timer.h" + + +static gboolean gtkTimerProc(gpointer data) +{ + Ihandle *ih = (Ihandle*)data; + Icallback cb; + + if (!iupObjectCheck(ih)) /* control could be destroyed before timer callback */ + return FALSE; + + cb = IupGetCallback(ih, "ACTION_CB"); + if (cb && cb(ih)==IUP_CLOSE) + IupExitLoop(); + + return TRUE; +} + +void iupdrvTimerRun(Ihandle *ih) +{ + unsigned int time_ms; + + if (ih->serial > 0) /* timer already started */ + return; + + time_ms = iupAttribGetInt(ih, "TIME"); + if (time_ms > 0) + ih->serial = g_timeout_add(time_ms, gtkTimerProc, (gpointer)ih); +} + +void iupdrvTimerStop(Ihandle* ih) +{ + if (ih->serial > 0) + { + g_source_remove(ih->serial); + ih->serial = -1; + } +} + +void iupdrvTimerInitClass(Iclass* ic) +{ + (void)ic; +} diff --git a/iup/src/gtk/iupgtk_tips.c b/iup/src/gtk/iupgtk_tips.c new file mode 100755 index 0000000..6289d70 --- /dev/null +++ b/iup/src/gtk/iupgtk_tips.c @@ -0,0 +1,100 @@ +/** \file + * \brief Windows Driver TIPS management + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> + +#include <gtk/gtk.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_str.h" +#include "iup_attrib.h" +#include "iup_image.h" + +#include "iupgtk_drv.h" + +#if GTK_CHECK_VERSION(2, 12, 0) +#else +static GtkTooltips* gtk_tips = NULL; /* old TIPS */ +#endif + +#if GTK_CHECK_VERSION(2, 12, 0) +static gboolean gtkQueryTooltip(GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, Ihandle* ih) +{ + char* value = iupAttribGet(ih, "TIPRECT"); + if (value && !keyboard_mode) + { + GdkRectangle rect; + int x1, x2, y1, y2; + sscanf(value, "%d %d %d %d", &x1, &y1, &x2, &y2); + rect.x = x1; + rect.y = y1; + rect.width = x2-x1+1; + rect.height = y2-y1+1; + gtk_tooltip_set_tip_area(tooltip, &rect); + } + else + gtk_tooltip_set_tip_area(tooltip, NULL); + + value = iupAttribGet(ih, "TIPICON"); + if (!value) + gtk_tooltip_set_icon(tooltip, NULL); + else + { + GdkPixbuf* icon = (GdkPixbuf*)iupImageGetIcon(value); + if (icon) + gtk_tooltip_set_icon(tooltip, icon); + } + + (void)y; + (void)x; + (void)widget; + return FALSE; +} +#endif + +int iupdrvBaseSetTipAttrib(Ihandle* ih, const char* value) +{ + GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) + widget = ih->handle; + +#if GTK_CHECK_VERSION(2, 12, 0) + if (iupAttribGetBoolean(ih, "TIPMARKUP")) + gtk_widget_set_tooltip_markup(widget, iupgtkStrConvertToUTF8(value)); + else + gtk_widget_set_tooltip_text(widget, iupgtkStrConvertToUTF8(value)); + + g_signal_connect(widget, "query-tooltip", G_CALLBACK(gtkQueryTooltip), ih); +#else + if (gtk_tips == NULL) + gtk_tips = gtk_tooltips_new(); + + gtk_tooltips_set_tip(gtk_tips, widget, iupgtkStrConvertToUTF8(value), NULL); +#endif + + return 1; +} + +int iupdrvBaseSetTipVisibleAttrib(Ihandle* ih, const char* value) +{ + GtkWidget* widget = (GtkWidget*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) + widget = ih->handle; + (void)value; + + /* must use IupGetAttribute to use inheritance */ + if (!IupGetAttribute(ih, "TIP")) + return 0; + +#if GTK_CHECK_VERSION(2, 12, 0) + gtk_widget_trigger_tooltip_query(widget); +#endif + + return 0; +} + diff --git a/iup/src/gtk/iupgtk_toggle.c b/iup/src/gtk/iupgtk_toggle.c new file mode 100755 index 0000000..8ff7df5 --- /dev/null +++ b/iup/src/gtk/iupgtk_toggle.c @@ -0,0 +1,519 @@ +/** \file + * \brief Toggle Control + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_image.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_image.h" +#include "iup_key.h" +#include "iup_toggle.h" + +#include "iupgtk_drv.h" + + +#if !GTK_CHECK_VERSION(2, 6, 0) +static void gtk_button_set_image(GtkButton *button, GtkWidget *image) +{ +} +static GtkWidget* gtk_button_get_image(GtkButton *button) +{ + return NULL; +} +#endif + +void iupdrvToggleAddCheckBox(int *x, int *y) +{ +#ifdef HILDON + (*x) += 30+4; + if ((*y) < 30) (*y) = 30; /* minimum height */ +#else + (*x) += 16+4; + if ((*y) < 16) (*y) = 16; /* minimum height */ +#endif + (*y) += 4; +} + +static int gtkToggleGetCheck(Ihandle* ih) +{ + if (gtk_toggle_button_get_inconsistent((GtkToggleButton*)ih->handle)) + return -1; + if (gtk_toggle_button_get_active((GtkToggleButton*)ih->handle)) + return 1; + else + return 0; +} + +static void gtkToggleSetPixbuf(Ihandle* ih, const char* name, int make_inactive) +{ + GtkButton* button = (GtkButton*)ih->handle; + GtkImage* image = (GtkImage*)gtk_button_get_image(button); + + if (name) + { + GdkPixbuf* pixbuf = iupImageGetImage(name, ih, make_inactive); + GdkPixbuf* old_pixbuf = gtk_image_get_pixbuf(image); + if (pixbuf != old_pixbuf) + gtk_image_set_from_pixbuf(image, pixbuf); + return; + } + + /* if not defined */ +#if GTK_CHECK_VERSION(2, 8, 0) + gtk_image_clear(image); +#endif +} + +static void gtkToggleUpdateImage(Ihandle* ih, int active, int check) +{ + char* name; + + if (!active) + { + name = iupAttribGet(ih, "IMINACTIVE"); + if (name) + gtkToggleSetPixbuf(ih, name, 0); + else + { + /* if not defined then automaticaly create one based on IMAGE */ + name = iupAttribGet(ih, "IMAGE"); + gtkToggleSetPixbuf(ih, name, 1); /* make_inactive */ + } + } + else + { + /* must restore the normal image */ + if (check) + { + name = iupAttribGet(ih, "IMPRESS"); + if (name) + gtkToggleSetPixbuf(ih, name, 0); + else + { + /* if not defined then automaticaly create one based on IMAGE */ + name = iupAttribGet(ih, "IMAGE"); + gtkToggleSetPixbuf(ih, name, 0); + } + } + else + { + name = iupAttribGet(ih, "IMAGE"); + if (name) + gtkToggleSetPixbuf(ih, name, 0); + } + } +} + + +/*************************************************************************/ + + +static int gtkToggleSetValueAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value,"NOTDEF")) + gtk_toggle_button_set_inconsistent((GtkToggleButton*)ih->handle, TRUE); + else + { + gtk_toggle_button_set_inconsistent((GtkToggleButton*)ih->handle, FALSE); + + /* This action causes the toggled signal to be emitted. */ + iupAttribSetStr(ih, "_IUPGTK_IGNORE_TOGGLE", "1"); + + if (iupStrBoolean(value)) + gtk_toggle_button_set_active((GtkToggleButton*)ih->handle, TRUE); + else + gtk_toggle_button_set_active((GtkToggleButton*)ih->handle, FALSE); + + if (ih->data->type == IUP_TOGGLE_IMAGE) + gtkToggleUpdateImage(ih, iupdrvIsActive(ih), gtkToggleGetCheck(ih)); + + iupAttribSetStr(ih, "_IUPGTK_IGNORE_TOGGLE", NULL); + } + + return 0; +} + +static char* gtkToggleGetValueAttrib(Ihandle* ih) +{ + int check = gtkToggleGetCheck(ih); + if (check == -1) + return "NOTDEF"; + else if (check == 1) + return "ON"; + else + return "OFF"; +} + +static int gtkToggleSetTitleAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_TEXT) + { + GtkButton* button = (GtkButton*)ih->handle; + GtkLabel* label = (GtkLabel*)gtk_button_get_image(button); + iupgtkSetMnemonicTitle(ih, label, value); + return 1; + } + + return 0; +} + +static int gtkToggleSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + GtkButton* button = (GtkButton*)ih->handle; + float xalign, yalign; + char value1[30]="", value2[30]=""; + + if (ih->data->type == IUP_TOGGLE_TEXT) + return 0; + + iupStrToStrStr(value, value1, value2, ':'); + + if (iupStrEqualNoCase(value1, "ARIGHT")) + xalign = 1.0f; + else if (iupStrEqualNoCase(value1, "ACENTER")) + xalign = 0.5f; + else /* "ALEFT" */ + xalign = 0; + + if (iupStrEqualNoCase(value2, "ABOTTOM")) + yalign = 1.0f; + else if (iupStrEqualNoCase(value2, "ATOP")) + yalign = 0; + else /* ACENTER (default) */ + yalign = 0.5f; + + gtk_button_set_alignment(button, xalign, yalign); + + return 1; +} + +static int gtkToggleSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle && ih->data->type == IUP_TOGGLE_IMAGE) + { + GtkButton* button = (GtkButton*)ih->handle; + GtkMisc* misc = (GtkMisc*)gtk_button_get_image(button); + gtk_misc_set_padding(misc, ih->data->horiz_padding, ih->data->vert_padding); + } + return 0; +} + +static int gtkToggleSetFgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + GtkWidget* label = (GtkWidget*)gtk_button_get_image((GtkButton*)ih->handle); + if (!label) return 0; + + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + iupgtkBaseSetFgColor(label, r, g, b); + + return 1; +} + +static int gtkToggleSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + iupdrvSetStandardFontAttrib(ih, value); + + if (ih->handle) + { + GtkWidget* label = gtk_button_get_image((GtkButton*)ih->handle); + if (!label) return 1; + + gtk_widget_modify_font(label, (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih)); + + if (ih->data->type == IUP_TOGGLE_TEXT) + iupgtkFontUpdatePangoLayout(ih, gtk_label_get_layout((GtkLabel*)label)); + } + return 1; +} + +static int gtkToggleSetImageAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + if (value != iupAttribGet(ih, "IMAGE")) + iupAttribSetStr(ih, "IMAGE", (char*)value); + gtkToggleUpdateImage(ih, iupdrvIsActive(ih), gtkToggleGetCheck(ih)); + return 1; + } + else + return 0; +} + +static int gtkToggleSetImInactiveAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + if (value != iupAttribGet(ih, "IMINACTIVE")) + iupAttribSetStr(ih, "IMINACTIVE", (char*)value); + gtkToggleUpdateImage(ih, iupdrvIsActive(ih), gtkToggleGetCheck(ih)); + return 1; + } + else + return 0; +} + +static int gtkToggleSetImPressAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + if (value != iupAttribGet(ih, "IMPRESS")) + iupAttribSetStr(ih, "IMPRESS", (char*)value); + gtkToggleUpdateImage(ih, iupdrvIsActive(ih), gtkToggleGetCheck(ih)); + return 1; + } + else + return 0; +} + +static int gtkToggleSetActiveAttrib(Ihandle* ih, const char* value) +{ + /* update the inactive image if necessary */ + if (ih->data->type == IUP_TOGGLE_IMAGE) + gtkToggleUpdateImage(ih, iupStrBoolean(value), gtkToggleGetCheck(ih)); + + return iupBaseSetActiveAttrib(ih, value); +} + +/****************************************************************************************************/ + +static void gtkToggleToggled(GtkToggleButton *widget, Ihandle* ih) +{ + IFni cb; + int check; + + if (iupAttribGet(ih, "_IUPGTK_IGNORE_TOGGLE")) + return; + + check = gtkToggleGetCheck(ih); + + if (ih->data->type == IUP_TOGGLE_IMAGE) + gtkToggleUpdateImage(ih, iupdrvIsActive(ih), check); + + cb = (IFni)IupGetCallback(ih, "ACTION"); + if (cb && cb(ih, check) == IUP_CLOSE) + IupExitLoop(); + + iupBaseCallValueChangedCb(ih); + + (void)widget; +} + +static int gtkToggleUpdate3StateCheck(Ihandle *ih, int keyb) +{ + int check = gtkToggleGetCheck(ih); + if (check == 1) /* GOTO check == -1 */ + { + gtk_toggle_button_set_inconsistent((GtkToggleButton*)ih->handle, TRUE); + gtkToggleToggled((GtkToggleButton*)ih->handle, ih); + return TRUE; /* ignore message to avoid change toggle state */ + } + else if (check == -1) /* GOTO check == 0 */ + { + gtk_toggle_button_set_inconsistent((GtkToggleButton*)ih->handle, FALSE); + if (keyb) + { + gtk_toggle_button_set_active((GtkToggleButton*)ih->handle, FALSE); + return TRUE; /* ignore message to avoid change toggle state */ + } + } + else /* (check == 0) GOTO check == 1 */ + { + gtk_toggle_button_set_inconsistent((GtkToggleButton*)ih->handle, FALSE); + if (keyb) + { + gtk_toggle_button_set_active((GtkToggleButton*)ih->handle, TRUE); + return TRUE; /* ignore message to avoid change toggle state */ + } + } + + return FALSE; +} + +static gboolean gtkToggleButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih) +{ + if (iupAttribGet(ih, "_IUPGTK_IGNORE_TOGGLE")) + return FALSE; + + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + char* name = iupAttribGet(ih, "IMPRESS"); + if (name) + { + if (evt->type == GDK_BUTTON_PRESS) + gtkToggleUpdateImage(ih, iupdrvIsActive(ih), 1); + else + gtkToggleUpdateImage(ih, iupdrvIsActive(ih), 0); + } + } + else + { + if (evt->type == GDK_BUTTON_RELEASE) + { + if (gtkToggleUpdate3StateCheck(ih, 0)) + return TRUE; /* ignore message to avoid change toggle state */ + } + } + + (void)widget; + return FALSE; +} + +static gboolean gtkToggleKeyEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) +{ + if (evt->type == GDK_KEY_PRESS) + { + if (evt->keyval == GDK_space || evt->keyval == GDK_Return) + return TRUE; /* ignore message to avoid change toggle state */ + } + else + { + if (evt->keyval == GDK_space || evt->keyval == GDK_Return) + { + if (gtkToggleUpdate3StateCheck(ih, 1)) + return TRUE; /* ignore message to avoid change toggle state */ + } + } + + (void)widget; + return FALSE; +} + +static int gtkToggleMapMethod(Ihandle* ih) +{ + Ihandle* radio = iupRadioFindToggleParent(ih); + char *value; + int is3state = 0; + + if (!ih->parent) + return IUP_ERROR; + + if (radio) + ih->data->radio = 1; + + value = iupAttribGet(ih, "IMAGE"); + if (value) + ih->data->type = IUP_TOGGLE_IMAGE; + else + ih->data->type = IUP_TOGGLE_TEXT; + + if (radio) + { + GtkRadioButton* last_tg = (GtkRadioButton*)iupAttribGet(radio, "_IUPGTK_LASTRADIOBUTTON"); + if (last_tg) + ih->handle = gtk_radio_button_new_from_widget(last_tg); + else + ih->handle = gtk_radio_button_new(NULL); + iupAttribSetStr(radio, "_IUPGTK_LASTRADIOBUTTON", (char*)ih->handle); + } + else + { + if (ih->data->type == IUP_TOGGLE_TEXT) + { + ih->handle = gtk_check_button_new(); + + if (iupAttribGetBoolean(ih, "3STATE")) + is3state = 1; + } + else + ih->handle = gtk_toggle_button_new(); + } + + if (!ih->handle) + return IUP_ERROR; + + if (ih->data->type == IUP_TOGGLE_TEXT) + { + gtk_button_set_image((GtkButton*)ih->handle, gtk_label_new(NULL)); + gtk_toggle_button_set_mode((GtkToggleButton*)ih->handle, TRUE); + } + else + { + gtk_button_set_image((GtkButton*)ih->handle, gtk_image_new()); + gtk_toggle_button_set_mode((GtkToggleButton*)ih->handle, FALSE); + } + + /* add to the parent, all GTK controls must call this. */ + iupgtkBaseAddToParent(ih); + + if (!iupAttribGetBoolean(ih, "CANFOCUS")) + GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS; + + g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + + g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih); + + g_signal_connect(G_OBJECT(ih->handle), "toggled", G_CALLBACK(gtkToggleToggled), ih); + + if (ih->data->type == IUP_TOGGLE_IMAGE || is3state) + { + g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkToggleButtonEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkToggleButtonEvent), ih); + } + + if (is3state) + { + g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkToggleKeyEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "key-release-event", G_CALLBACK(gtkToggleKeyEvent), ih); + } + + gtk_widget_realize(ih->handle); + + return IUP_NOERROR; +} + +void iupdrvToggleInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkToggleMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Overwrite Common */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, gtkToggleSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, gtkToggleSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkToggleSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); /* black */ + iupClassRegisterAttribute(ic, "TITLE", NULL, gtkToggleSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupToggle only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, gtkToggleSetAlignmentAttrib, "ACENTER:ACENTER", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkToggleSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, gtkToggleSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMPRESS", NULL, gtkToggleSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE", gtkToggleGetValueAttrib, gtkToggleSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "PADDING", iupToggleGetPaddingAttrib, gtkToggleSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "MARKUP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT); +} diff --git a/iup/src/gtk/iupgtk_tree.c b/iup/src/gtk/iupgtk_tree.c new file mode 100755 index 0000000..d408f27 --- /dev/null +++ b/iup/src/gtk/iupgtk_tree.c @@ -0,0 +1,2369 @@ +/** \file + * \brief Tree Control + * + * See Copyright Notice in iup.h + */ + +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_key.h" +#include "iup_image.h" +#include "iup_array.h" +#include "iup_tree.h" + +#include "iup_drvinfo.h" +#include "iupgtk_drv.h" + +enum +{ + IUPGTK_TREE_IMAGE, + IUPGTK_TREE_HAS_IMAGE, + IUPGTK_TREE_IMAGE_EXPANDED, + IUPGTK_TREE_HAS_IMAGE_EXPANDED, + IUPGTK_TREE_TITLE, + IUPGTK_TREE_KIND, + IUPGTK_TREE_COLOR, + IUPGTK_TREE_FONT, + IUPGTK_TREE_USERDATA +}; + +static GtkTreeIter gtkTreeInvalidIter = {0,0,0,0}; + +/*****************************************************************************/ +/* COPYING ITEMS (Branches and its children) */ +/*****************************************************************************/ +/* Insert the copied item in a new location. Returns the new item. */ +static void gtkTreeCopyItem(GtkTreeModel* model, GtkTreeIter* iterItem, GtkTreeIter* iterParent, int position, GtkTreeIter *iterNewItem, int full_copy) +{ + GtkTreeStore* store = GTK_TREE_STORE(model); + int kind; + char* title; + gboolean has_image, has_image_expanded; + PangoFontDescription* font; + void* userdata; + GdkColor *color; + GdkPixbuf* image, *image_expanded; + + gtk_tree_model_get(GTK_TREE_MODEL(store), iterItem, IUPGTK_TREE_IMAGE, &image, + IUPGTK_TREE_HAS_IMAGE, &has_image, + IUPGTK_TREE_IMAGE_EXPANDED, &image_expanded, + IUPGTK_TREE_HAS_IMAGE_EXPANDED, &has_image_expanded, + IUPGTK_TREE_TITLE, &title, + IUPGTK_TREE_KIND, &kind, + IUPGTK_TREE_COLOR, &color, + IUPGTK_TREE_FONT, &font, + IUPGTK_TREE_USERDATA, &userdata, + -1); + + if (position == 2) + gtk_tree_store_append(store, iterNewItem, iterParent); + else if (position == 1) /* copy as first child of expanded branch */ + gtk_tree_store_insert(store, iterNewItem, iterParent, 0); /* iterParent is parent of the new item (firstchild of it) */ + else /* copy as next brother of item or collapsed branch */ + gtk_tree_store_insert_after(store, iterNewItem, NULL, iterParent); /* iterParent is sibling of the new item */ + + if (full_copy) /* during a full copy the userdata reference is not copied */ + userdata = NULL; + + gtk_tree_store_set(store, iterNewItem, IUPGTK_TREE_IMAGE, image, + IUPGTK_TREE_HAS_IMAGE, has_image, + IUPGTK_TREE_IMAGE_EXPANDED, image_expanded, + IUPGTK_TREE_HAS_IMAGE_EXPANDED, has_image_expanded, + IUPGTK_TREE_TITLE, title, + IUPGTK_TREE_KIND, kind, + IUPGTK_TREE_COLOR, color, + IUPGTK_TREE_FONT, font, + IUPGTK_TREE_USERDATA, userdata, + -1); +} + +static void gtkTreeCopyChildren(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItemSrc, GtkTreeIter *iterItemDst, int full_copy) +{ + GtkTreeIter iterChildSrc; + int hasItem = gtk_tree_model_iter_children(model, &iterChildSrc, iterItemSrc); /* get the firstchild */ + while(hasItem) + { + GtkTreeIter iterNewItem; + gtkTreeCopyItem(model, &iterChildSrc, iterItemDst, 2, &iterNewItem, full_copy); /* append always */ + + /* Recursively transfer all the items */ + gtkTreeCopyChildren(ih, model, &iterChildSrc, &iterNewItem, full_copy); + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterChildSrc); + } +} + +/* Copies all items in a branch to a new location. Returns the new branch node. */ +static void gtkTreeCopyNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItemSrc, GtkTreeIter *iterItemDst, GtkTreeIter* iterNewItem, int full_copy) +{ + int kind, position = 0; /* insert after iterItemDst */ + gtk_tree_model_get(model, iterItemDst, IUPGTK_TREE_KIND, &kind, -1); + + if (kind == ITREE_BRANCH) + { + GtkTreePath* path = gtk_tree_model_get_path(model, iterItemDst); + if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) + position = 1; /* insert as first child of iterItemDst */ + gtk_tree_path_free(path); + } + + gtkTreeCopyItem(model, iterItemSrc, iterItemDst, position, iterNewItem, full_copy); + + gtkTreeCopyChildren(ih, model, iterItemSrc, iterNewItem, full_copy); +} + +/*****************************************************************************/ +/* FINDING ITEMS */ +/*****************************************************************************/ + +static void gtkTreeInvertAllNodeMarking(Ihandle* ih, GtkTreeModel* model, GtkTreeSelection* selection, GtkTreeIter* iterItem) +{ + GtkTreeIter iterChild; + int hasItem = TRUE; + + while(hasItem) + { + if(gtk_tree_selection_iter_is_selected(selection, iterItem)) + gtk_tree_selection_unselect_iter(selection, iterItem); + else + gtk_tree_selection_select_iter(selection, iterItem); + + /* Check whether we have child items */ + if(gtk_tree_model_iter_has_child(model, iterItem)) + { + gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ + gtkTreeInvertAllNodeMarking(ih, model, selection, &iterChild); + } + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, iterItem); + } +} + +static GtkTreeIter gtkTreeFindVisibleNodeId(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, GtkTreeIter iterNode) +{ + GtkTreeIter iterChild; + GtkTreePath* path; + int hasItem = TRUE; + + while(hasItem) + { + /* ID control to traverse items */ + ih->data->id_control++; /* not the real id since it counts only the visible ones */ + + /* StateID founded! */ + if(iterItem.user_data == iterNode.user_data) + return iterItem; + + path = gtk_tree_model_get_path(model, &iterItem); + + /* Check whether we have child items and it is expanded (visible) */ + if (gtk_tree_model_iter_has_child(model, &iterItem) && gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) + { + gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ + iterChild = gtkTreeFindVisibleNodeId(ih, model, iterChild, iterNode); + + /* StateID founded! */ + if(iterChild.user_data) + { + gtk_tree_path_free(path); + return iterChild; + } + } + + gtk_tree_path_free(path); + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterItem); + } + + return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ +} + +static GtkTreeIter gtkTreeFindVisibleNodeFromId(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem) +{ + GtkTreeIter iterChild; + GtkTreePath* path; + int hasItem = TRUE; + + while(hasItem) + { + /* ID control to traverse items */ + ih->data->id_control--; /* not the real id since it counts only the visible ones */ + + /* StateID founded! */ + if(ih->data->id_control < 0) + return iterItem; + + path = gtk_tree_model_get_path(model, &iterItem); + + /* Check whether we have child items and it is expanded (visible) */ + if(gtk_tree_model_iter_has_child(model, &iterItem) && gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) + { + gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ + iterChild = gtkTreeFindVisibleNodeFromId(ih, model, iterChild); + + /* StateID founded! */ + if(ih->data->id_control < 0) + { + gtk_tree_path_free(path); + return iterChild; + } + } + + gtk_tree_path_free(path); + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterItem); + } + + return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ +} + +static GtkTreeIter gtkTreeGetLastVisibleNode(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem) +{ + GtkTreeIter iterChild, iterPrev = gtkTreeInvalidIter; + GtkTreePath* path = gtk_tree_model_get_path(model, &iterItem); + + /* Check whether we have child items and it is expanded (visible) */ + if(gtk_tree_model_iter_has_child(model, &iterItem) && gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) + { + int hasItem = TRUE; + gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ + + while(hasItem) + { + iterPrev = iterChild; + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterChild); + } + + iterItem = gtkTreeGetLastVisibleNode(ih, model, iterPrev); + } + gtk_tree_path_free(path); + + return iterItem; +} + +static GtkTreeIter gtkTreeFindNodeID(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, GtkTreeIter iterNode) +{ + GtkTreeIter iterChild; + int hasItem = TRUE; + + while(hasItem) + { + /* ID control to traverse items */ + ih->data->id_control++; + + /* StateID founded! */ + if (iterItem.user_data == iterNode.user_data) + return iterItem; + + /* Check whether we have child items */ + if (gtk_tree_model_iter_has_child(model, &iterItem)) + { + gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ + iterChild = gtkTreeFindNodeID(ih, model, iterChild, iterNode); + + /* StateID founded! */ + if(iterChild.user_data) + return iterChild; + } + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterItem); + } + + return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ +} + +static int gtkTreeGetNodeId(Ihandle* ih, GtkTreeIter iterItem) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterRoot; + gtk_tree_model_get_iter_first(model, &iterRoot); + + ih->data->id_control = -1; + iterItem = gtkTreeFindNodeID(ih, model, iterRoot, iterItem); + if (iterItem.user_data) + return ih->data->id_control; + else + return -1; +} + +static GtkTreeIter gtkTreeFindUserData(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, void* userdata) +{ + GtkTreeIter iterChild; + int hasItem = TRUE; + void* node_userdata; + + while(hasItem) + { + /* ID control to traverse items */ + ih->data->id_control++; + + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &node_userdata, -1); + + /* userdata founded! */ + if (node_userdata == userdata) + return iterItem; + + /* Check whether we have child items */ + if (gtk_tree_model_iter_has_child(model, &iterItem)) + { + gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ + iterChild = gtkTreeFindUserData(ih, model, iterChild, userdata); + + /* userdata founded! */ + if (iterChild.user_data) + return iterChild; + } + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterItem); + } + + return gtkTreeInvalidIter; /* invalid since gtk_tree_model_iter_next returned false */ +} + +static int gtkTreeGetUserDataId(Ihandle* ih, GtkTreeModel* model, void* userdata) +{ + GtkTreeIter iterRoot, iterItem; + gtk_tree_model_get_iter_first(model, &iterRoot); + + ih->data->id_control = -1; + iterItem = gtkTreeFindUserData(ih, model, iterRoot, userdata); + if (iterItem.user_data) + return ih->data->id_control; + else + return -1; +} + +static void gtkTreeCallNodeRemovedRec(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, IFnis cb) +{ + GtkTreeIter iterChild; + int hasItem = TRUE; + void* node_userdata; + + while(hasItem) + { + /* ID control to traverse items */ + ih->data->id_control++; + + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &node_userdata, -1); + + cb(ih, ih->data->id_control, (char*)node_userdata); + + /* Check whether we have child items */ + if (gtk_tree_model_iter_has_child(model, &iterItem)) + { + gtk_tree_model_iter_children(model, &iterChild, &iterItem); /* get the firstchild */ + gtkTreeCallNodeRemovedRec(ih, model, iterChild, cb); + } + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterItem); + } +} + +static void gtkTreeCallNodeRemoved(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem) +{ + IFnis cb = (IFnis)IupGetCallback(ih, "NODEREMOVED_CB"); + if (cb) + { + ih->data->id_control = gtkTreeGetNodeId(ih, *iterItem)-1; + gtkTreeCallNodeRemovedRec(ih, model, *iterItem, cb); + } +} + +static gboolean gtkTreeFindNodeFromID(Ihandle* ih, GtkTreeModel* model, GtkTreeIter *iterItem, int *id) +{ + GtkTreeIter iterChild; + int hasItem = TRUE; + + while(hasItem) + { + /* ID control to traverse items */ + (*id)--; + + /* StateID founded! */ + if (*id < 0) + return TRUE; + + /* Check whether we have child items */ + if (gtk_tree_model_iter_has_child(model, iterItem)) + { + gtk_tree_model_iter_children(model, &iterChild, iterItem); /* get the firstchild */ + + if (gtkTreeFindNodeFromID(ih, model, &iterChild, id)) + { + *iterItem = iterChild; + return TRUE; + } + } + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, iterItem); + } + + return FALSE; +} + +static gboolean gtkTreeFindNodeFromString(Ihandle* ih, GtkTreeModel* model, const char* name_id, GtkTreeIter *iterItem) +{ + if (name_id[0]) + { + int id; + if (iupStrToInt(name_id, &id)) + { + gtk_tree_model_get_iter_first(model, iterItem); + return gtkTreeFindNodeFromID(ih, model, iterItem, &id); + } + } + else + { + GtkTreePath* path = NULL; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL); + if (path) + { + gtk_tree_model_get_iter(model, iterItem, path); + gtk_tree_path_free(path); + return TRUE; + } + } + return FALSE; +} + +/*****************************************************************************/ +/* MANIPULATING IMAGES */ +/*****************************************************************************/ +static void gtkTreeUpdateImages(Ihandle* ih, GtkTreeModel* model, GtkTreeIter iterItem, int mode) +{ + GtkTreeIter iterChild; + int hasItem = TRUE; + int kind; + + while(hasItem) + { + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); + + if (kind == ITREE_BRANCH) + { + if (mode == ITREE_UPDATEIMAGE_EXPANDED) + { + gboolean has_image_expanded = FALSE; + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_HAS_IMAGE_EXPANDED, &has_image_expanded, -1); + if (!has_image_expanded) + gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded, -1); + } + else if(mode == ITREE_UPDATEIMAGE_COLLAPSED) + { + gboolean has_image = FALSE; + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_HAS_IMAGE, &has_image, -1); + if (!has_image) + gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed, -1); + } + + if (gtk_tree_model_iter_has_child(model, &iterItem)) + { + + /* Recursively traverse child items */ + gtk_tree_model_iter_children(model, &iterChild, &iterItem); + gtkTreeUpdateImages(ih, model, iterChild, mode); + } + } + else + { + if (mode == ITREE_UPDATEIMAGE_LEAF) + { + gboolean has_image = FALSE; + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_HAS_IMAGE, &has_image, -1); + if (!has_image) + gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_leaf, -1); + } + } + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterItem); + } +} + +static void gtkTreeExpandItem(Ihandle* ih, GtkTreePath* path, int expand) +{ + if (expand == -1) + expand = !gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path); /* toggle */ + + if (expand) + gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), path, FALSE); + else + gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path); +} + +int iupgtkGetColor(const char* value, GdkColor *color) +{ + unsigned char r, g, b; + if (iupStrToRGB(value, &r, &g, &b)) + { + iupgdkColorSet(color, r, g, b); + return 1; + } + return 0; +} + +/*****************************************************************************/ +/* ADDING ITEMS */ +/*****************************************************************************/ +void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* title, int add) +{ + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterPrev, iterNewItem, iterParent; + GtkTreePath* path; + GdkColor color = {0L,0,0,0}; + int kindPrev; + + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterPrev)) + return; + + gtk_tree_model_get(GTK_TREE_MODEL(store), &iterPrev, IUPGTK_TREE_KIND, &kindPrev, -1); + + if (kindPrev == ITREE_BRANCH && add) + gtk_tree_store_insert(store, &iterNewItem, &iterPrev, 0); /* iterPrev is parent of the new item (firstchild of it) */ + else + gtk_tree_store_insert_after(store, &iterNewItem, NULL, &iterPrev); /* iterPrev is sibling of the new item */ + + iupgtkGetColor(iupAttribGetStr(ih, "FGCOLOR"), &color); + + /* set the attributes of the new node */ + gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_HAS_IMAGE, FALSE, + IUPGTK_TREE_HAS_IMAGE_EXPANDED, FALSE, + IUPGTK_TREE_TITLE, iupgtkStrConvertToUTF8(title), + IUPGTK_TREE_KIND, kind, + IUPGTK_TREE_COLOR, &color, -1); + + if (kind == ITREE_LEAF) + gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_IMAGE, ih->data->def_image_leaf, -1); + else + gtk_tree_store_set(store, &iterNewItem, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed, + IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded, -1); + + if (kindPrev == ITREE_BRANCH && add) + iterParent = iterPrev; + else + gtk_tree_model_iter_parent(GTK_TREE_MODEL(store), &iterParent, &iterNewItem); + + /* If this is the first child of the parent, then handle the ADDEXPANDED attribute */ + if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), &iterParent) == 1) + { + int depth; + path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterParent); + depth = gtk_tree_path_get_depth(path)-1; + if (ih->data->add_expanded || depth==0) /* if this is the first child of the root, expand always */ + { + iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB", "1"); + gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), path, FALSE); + } + else + gtk_tree_view_collapse_row(GTK_TREE_VIEW(ih->handle), path); + gtk_tree_path_free(path); + } +} + +static void gtkTreeAddRootNode(Ihandle* ih) +{ + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreePath* path; + GtkTreeIter iterRoot; + GdkColor color = {0L,0,0,0}; + + iupgtkGetColor(iupAttribGetStr(ih, "FGCOLOR"), &color); + + gtk_tree_store_append(store, &iterRoot, NULL); /* root node */ + gtk_tree_store_set(store, &iterRoot, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed, + IUPGTK_TREE_HAS_IMAGE, FALSE, + IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded, + IUPGTK_TREE_HAS_IMAGE_EXPANDED, FALSE, + IUPGTK_TREE_KIND, ITREE_BRANCH, + IUPGTK_TREE_COLOR, &color, -1); + + path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterRoot); + /* MarkStart node */ + iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)path); + + /* Set the default VALUE */ + gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE); +} + +/*****************************************************************************/ +/* AUXILIAR FUNCTIONS */ +/*****************************************************************************/ +static void gtkTreeOpenCloseEvent(Ihandle* ih) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + GtkTreePath* path; + int kind; + + if (!gtkTreeFindNodeFromString(ih, model, "", &iterItem)) + return; + + path = gtk_tree_model_get_path(model, &iterItem); + if (path) + { + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); + + if (kind == ITREE_LEAF) /* leafs */ + gtk_tree_view_row_activated(GTK_TREE_VIEW(ih->handle), path, (GtkTreeViewColumn*)iupAttribGet(ih, "_IUPGTK_COLUMN")); + else /* branches */ + gtkTreeExpandItem(ih, path, -1); /* toggle */ + + gtk_tree_path_free(path); + } +} + +static gboolean gtkTreeSelected_Foreach_Func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **rowref_list) +{ + GtkTreeRowReference *rowref; + + rowref = gtk_tree_row_reference_new(model, path); + *rowref_list = g_list_append(*rowref_list, rowref); + + (void)iter; + return FALSE; /* do not stop walking the store, call us with next row */ +} + +static gboolean gtkTreeSelected_Iter_Func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **rowref_list) +{ + GtkTreeRowReference *rowref; + GtkTreeIter iterParent; + if (!gtk_tree_model_iter_parent(model, &iterParent, iter)) /* the root node can't be deleted */ + return FALSE; /* do not stop walking the store, call us with next row */ + + rowref = gtk_tree_row_reference_new(model, path); + *rowref_list = g_list_append(*rowref_list, rowref); + + return FALSE; /* do not stop walking the store, call us with next row */ +} + +/*****************************************************************************/ +/* CALLBACKS */ +/*****************************************************************************/ +static void gtkTreeCallMultiSelectionCb(Ihandle* ih) +{ + IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTISELECTION_CB"); + IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); + if (cbMulti || cbSelec) + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterRoot; + GList *rr_list = NULL; + GList *node; + int* id_rowItem; + int count_selected_rows, i = 0; + + gtk_tree_model_get_iter_first(model, &iterRoot); + + gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)gtkTreeSelected_Foreach_Func, &rr_list); + count_selected_rows = g_list_length(rr_list); + id_rowItem = malloc(sizeof(int) * count_selected_rows); + + for(node = rr_list; node != NULL; node = node->next) + { + GtkTreePath* path = gtk_tree_row_reference_get_path(node->data); + if (path) + { + GtkTreeIter iterItem; + gtk_tree_model_get_iter(model, &iterItem, path); + + id_rowItem[i] = gtkTreeGetNodeId(ih, iterItem); + i++; + + gtk_tree_path_free(path); + } + } + + g_list_foreach(rr_list, (GFunc) gtk_tree_row_reference_free, NULL); + g_list_free(rr_list); + + if (cbMulti) + cbMulti(ih, id_rowItem, count_selected_rows); + else + { + for (i=0; i<count_selected_rows; i++) + cbSelec(ih, id_rowItem[i], 1); + } + + free(id_rowItem); + } +} + + +/*****************************************************************************/ +/* GET AND SET ATTRIBUTES */ +/*****************************************************************************/ + + +static char* gtkTreeGetIndentationAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(255); +#if GTK_CHECK_VERSION(2, 12, 0) + int indent = gtk_tree_view_get_level_indentation(GTK_TREE_VIEW(ih->handle)); +#else + int indent = 0; +#endif + sprintf(str, "%d", indent); + return str; +} + +static int gtkTreeSetIndentationAttrib(Ihandle* ih, const char* value) +{ +#if GTK_CHECK_VERSION(2, 12, 0) + int indent; + if (iupStrToInt(value, &indent)) + gtk_tree_view_set_level_indentation(GTK_TREE_VIEW(ih->handle), indent); +#endif + return 0; +} + +static int gtkTreeSetTopItemAttrib(Ihandle* ih, const char* value) +{ + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterItem; + GtkTreePath* path; + + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), value, &iterItem)) + return 0; + + path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iterItem); + + if (!gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path)) + gtk_tree_view_expand_to_path(GTK_TREE_VIEW(ih->handle), path); + + gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE, 0, 0); /* scroll to visible */ + + gtk_tree_path_free(path); + + return 0; +} + +static int gtkTreeSetSpacingAttrib(Ihandle* ih, const char* value) +{ + if(!iupStrToInt(value, &ih->data->spacing)) + ih->data->spacing = 1; + + if(ih->data->spacing < 1) + ih->data->spacing = 1; + + if (ih->handle) + { + GtkCellRenderer *renderer_img = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_IMG"); + GtkCellRenderer *renderer_txt = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_TEXT"); + g_object_set(G_OBJECT(renderer_img), "ypad", ih->data->spacing, NULL); + g_object_set(G_OBJECT(renderer_txt), "ypad", ih->data->spacing, NULL); + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ +} + +static int gtkTreeSetExpandAllAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + gtk_tree_view_expand_all(GTK_TREE_VIEW(ih->handle)); + else + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterRoot; + GtkTreePath* pathRoot; + + gtk_tree_view_collapse_all(GTK_TREE_VIEW(ih->handle)); + + /* The root node is always expanded */ + gtk_tree_model_get_iter_first(model, &iterRoot); + pathRoot = gtk_tree_model_get_path(model, &iterRoot); + gtk_tree_view_expand_row(GTK_TREE_VIEW(ih->handle), pathRoot, FALSE); + gtk_tree_path_free(pathRoot); + } + + return 0; +} + +static char* gtkTreeGetDepthAttrib(Ihandle* ih, const char* name_id) +{ + char* depth; + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + return NULL; + + depth = iupStrGetMemory(10); + sprintf(depth, "%d", gtk_tree_store_iter_depth(store, &iterItem)); + return depth; +} + +static int gtkTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeModel* model; + GtkTreeIter iterItemSrc, iterItemDst, iterNewItem; + GtkTreeIter iterParent, iterNextParent; + + if (!ih->handle) /* do not store the action before map */ + return 0; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItemSrc)) + return 0; + + if (!gtkTreeFindNodeFromString(ih, model, value, &iterItemDst)) + return 0; + + /* If Drag item is an ancestor of Drop item then return */ + iterParent = iterItemDst; + while(gtk_tree_model_iter_parent(model, &iterNextParent, &iterParent)) + { + if (iterNextParent.user_data == iterItemSrc.user_data) + return 0; + iterParent = iterNextParent; + } + + /* Copying the node and its children to the new position */ + gtkTreeCopyNode(ih, model, &iterItemSrc, &iterItemDst, &iterNewItem, 0); /* not a full copy, preserve user data */ + + /* Deleting the node of its old position */ + /* do not delete the user data, we copy the references in CopyNode */ + gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItemSrc); + + return 0; +} + +static int gtkTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeModel* model; + GtkTreeIter iterItemSrc, iterItemDst, iterNewItem; + GtkTreeIter iterParent, iterNextParent; + + if (!ih->handle) /* do not store the action before map */ + return 0; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItemSrc)) + return 0; + + if (!gtkTreeFindNodeFromString(ih, model, value, &iterItemDst)) + return 0; + + /* If Drag item is an ancestor of Drop item then return */ + iterParent = iterItemDst; + while(gtk_tree_model_iter_parent(model, &iterNextParent, &iterParent)) + { + if (iterNextParent.user_data == iterItemSrc.user_data) + return 0; + iterParent = iterNextParent; + } + + /* Copying the node and its children to the new position */ + gtkTreeCopyNode(ih, model, &iterItemSrc, &iterItemDst, &iterNewItem, 1); + + return 0; +} + +static char* gtkTreeGetColorAttrib(Ihandle* ih, const char* name_id) +{ + char* str; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + GdkColor *color; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_COLOR, &color, -1); + if (!color) + return NULL; + + str = iupStrGetMemory(20); + sprintf(str, "%d %d %d", iupCOLOR16TO8(color->red), + iupCOLOR16TO8(color->green), + iupCOLOR16TO8(color->blue)); + return str; +} + +static int gtkTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterItem; + GdkColor color; + unsigned char r, g, b; + + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + return 0; + + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + iupgdkColorSet(&color, r, g, b); + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_COLOR, &color, -1); + + return 0; +} + +static char* gtkTreeGetParentAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + GtkTreeIter iterParent; + char* str; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + + if (!gtk_tree_model_iter_parent(model, &iterParent, &iterItem)) + return NULL; + + str = iupStrGetMemory(10); + sprintf(str, "%d", gtkTreeGetNodeId(ih, iterParent)); + return str; +} + +static char* gtkTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + char* str; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + + str = iupStrGetMemory(10); + sprintf(str, "%d", gtk_tree_model_iter_n_children(model, &iterItem)); + return str; +} + +static int gtkTreeCount(GtkTreeModel* model, GtkTreeIter iterBranch) +{ + GtkTreeIter iterChild; + int count = 0; + int hasItem = gtk_tree_model_iter_children(model, &iterChild, &iterBranch); /* get the firstchild */ + count++; + while(hasItem) + { + count += gtkTreeCount(model, iterChild); + + /* Go to next sibling item */ + hasItem = gtk_tree_model_iter_next(model, &iterChild); + } + + return count; +} + +static char* gtkTreeGetCountAttrib(Ihandle* ih) +{ + GtkTreeIter iterRoot; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + char* str = iupStrGetMemory(10); + gtk_tree_model_get_iter_first(model, &iterRoot); + sprintf(str, "%d", gtkTreeCount(model, iterRoot)); + return str; +} + +static char* gtkTreeGetKindAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + int kind; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); + + if(!kind) + return "BRANCH"; + else + return "LEAF"; +} + +static char* gtkTreeGetStateAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + + if (gtk_tree_model_iter_has_child(model, &iterItem)) + { + GtkTreePath* path = gtk_tree_model_get_path(model, &iterItem); + int expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(ih->handle), path); + gtk_tree_path_free(path); + + if (expanded) + return "EXPANDED"; + else + return "COLLAPSED"; + } + + return NULL; +} + +static int gtkTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + GtkTreePath* path; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return 0; + + path = gtk_tree_model_get_path(model, &iterItem); + gtkTreeExpandItem(ih, path, iupStrEqualNoCase(value, "EXPANDED")); + gtk_tree_path_free(path); + + return 0; +} + +static char* gtkTreeGetTitle(GtkTreeModel* model, GtkTreeIter iterItem) +{ + char* title; + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_TITLE, &title, -1); + return iupgtkStrConvertFromUTF8(title); +} + +static char* gtkTreeGetTitleAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + return gtkTreeGetTitle(model, iterItem); +} + +static int gtkTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + return 0; + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_TITLE, iupgtkStrConvertToUTF8(value), -1); + return 0; +} + +static int gtkTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + PangoFontDescription* fontdesc = NULL; + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + return 0; + if (value) + fontdesc = iupgtkGetPangoFontDesc(value); + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_FONT, fontdesc, -1); + return 0; +} + +static char* gtkTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id) +{ + PangoFontDescription* fontdesc; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_FONT, &fontdesc, -1); + return pango_font_description_to_string(fontdesc); +} + +static char* gtkTreeGetFindUserDataAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + int id; + char* str = (char*)(name_id+1); /* skip ':' */ + void* userdata = NULL; + if (sscanf(str, "%p", &userdata)!=1) + return NULL; + id = gtkTreeGetUserDataId(ih, model, userdata); + if (id == -1) + return NULL; + str = iupStrGetMemory(16); + sprintf(str, "%d", id); + return str; +} + +static char* gtkTreeGetUserDataAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + char* userdata; + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return NULL; + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_USERDATA, &userdata, -1); + return userdata; +} + +static int gtkTreeSetUserDataAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + return 0; + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_USERDATA, value, -1); + return 0; +} + +static char* gtkTreeGetValueAttrib(Ihandle* ih) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreePath* path = NULL; + char* str; + + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL); + if (path) + { + GtkTreeIter iterItem; + gtk_tree_model_get_iter(model, &iterItem, path); + gtk_tree_path_free(path); + + str = iupStrGetMemory(16); + sprintf(str, "%d", gtkTreeGetNodeId(ih, iterItem)); + return str; + } + + return "0"; /* default VALUE is root */ +} + +static int gtkTreeSetMarkAttrib(Ihandle* ih, const char* value) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterRoot; + + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + return 0; + + gtk_tree_model_get_iter_first(model, &iterRoot); + + if(iupStrEqualNoCase(value, "BLOCK")) + { + GtkTreePath* pathFocus; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); + gtk_tree_selection_select_range(selection, (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"), pathFocus); + gtk_tree_path_free(pathFocus); + } + else if(iupStrEqualNoCase(value, "CLEARALL")) + gtk_tree_selection_unselect_all(selection); + else if(iupStrEqualNoCase(value, "MARKALL")) + gtk_tree_selection_select_all(selection); + else if(iupStrEqualNoCase(value, "INVERTALL")) /* INVERTALL *MUST* appear before INVERT, or else INVERTALL will never be called. */ + gtkTreeInvertAllNodeMarking(ih, model, selection, &iterRoot); + else if(iupStrEqualPartial(value, "INVERT")) + { + /* iupStrEqualPartial allows the use of "INVERTid" form */ + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, model, &value[strlen("INVERT")], &iterItem)) + return 0; + + if(gtk_tree_selection_iter_is_selected(selection, &iterItem)) + gtk_tree_selection_unselect_iter(selection, &iterItem); + else + gtk_tree_selection_select_iter(selection, &iterItem); + } + else + { + GtkTreePath *path1, *path2; + GtkTreeIter iterItem1, iterItem2; + char str1[50], str2[50]; + if (iupStrToStrStr(value, str1, str2, '-')!=2) + return 0; + + if (!gtkTreeFindNodeFromString(ih, model, str1, &iterItem1)) + return 0; + if (!gtkTreeFindNodeFromString(ih, model, str2, &iterItem2)) + return 0; + + path1 = gtk_tree_model_get_path(model, &iterItem1); + path2 = gtk_tree_model_get_path(model, &iterItem2); + gtk_tree_selection_select_range(selection, path1, path2); + gtk_tree_path_free(path1); + gtk_tree_path_free(path2); + } + + return 1; +} + +static int gtkTreeSetValueAttrib(Ihandle* ih, const char* value) +{ + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterRoot, iterItem; + GtkTreePath* path; + + if (gtkTreeSetMarkAttrib(ih, value)) + return 0; + + gtk_tree_model_get_iter_first(model, &iterRoot); + + if (iupStrEqualNoCase(value, "ROOT")) + iterItem = iterRoot; + else if(iupStrEqualNoCase(value, "LAST")) + iterItem = gtkTreeGetLastVisibleNode(ih, model, iterRoot); + else if(iupStrEqualNoCase(value, "PGUP")) + { + GtkTreeIter iterPrev; + + GtkTreePath* pathFocus; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); + gtk_tree_model_get_iter(model, &iterPrev, pathFocus); + gtk_tree_path_free(pathFocus); + + ih->data->id_control = -1; + gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterPrev); + ih->data->id_control -= 10; /* less 10 visible nodes */ + + if(ih->data->id_control < 0) + ih->data->id_control = 0; /* Begin of tree = Root id */ + + iterItem = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); + } + else if(iupStrEqualNoCase(value, "PGDN")) + { + GtkTreeIter iterNext; + + GtkTreePath* pathFocus; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); + gtk_tree_model_get_iter(model, &iterNext, pathFocus); + gtk_tree_path_free(pathFocus); + + ih->data->id_control = -1; + gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterNext); + ih->data->id_control += 10; /* more 10 visible nodes */ + + iterNext = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); + + if (ih->data->id_control >= 0) + iterNext = gtkTreeGetLastVisibleNode(ih, model, iterRoot); + + iterItem = iterNext; + } + else if(iupStrEqualNoCase(value, "NEXT")) + { + GtkTreeIter iterNext; + + GtkTreePath* pathFocus; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); + gtk_tree_model_get_iter(model, &iterNext, pathFocus); + gtk_tree_path_free(pathFocus); + + ih->data->id_control = -1; + gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterNext); + ih->data->id_control++; /* more 1 visible node */ + + iterNext = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); + + if (ih->data->id_control >= 0) + iterNext = gtkTreeGetLastVisibleNode(ih, model, iterRoot); + + iterItem = iterNext; + } + else if(iupStrEqualNoCase(value, "PREVIOUS")) + { + GtkTreeIter iterPrev; + + GtkTreePath* pathFocus; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); + gtk_tree_model_get_iter(model, &iterPrev, pathFocus); + gtk_tree_path_free(pathFocus); + + ih->data->id_control = -1; + gtkTreeFindVisibleNodeId(ih, model, iterRoot, iterPrev); + ih->data->id_control--; /* less 1 visible node */ + + if (ih->data->id_control < 0) + ih->data->id_control = 0; + + iterItem = gtkTreeFindVisibleNodeFromId(ih, model, iterRoot); + if (!iterItem.user_data) + return 0; + } + else + { + if (!gtkTreeFindNodeFromString(ih, model, value, &iterItem)) + return 0; + } + + /* select */ + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + { + iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", "1"); + gtk_tree_selection_select_iter(selection, &iterItem); + } + + path = gtk_tree_model_get_path(model, &iterItem); + gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE, 0, 0); /* scroll to visible */ + gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, NULL, FALSE); /* set focus */ + gtk_tree_path_free(path); + + iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", gtkTreeGetNodeId(ih, iterItem)); + + return 0; +} + +static int gtkTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreePath *pathMarkStart, *pathMarkStartPrev; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return 0; + + pathMarkStart = gtk_tree_model_get_path(model, &iterItem); + + pathMarkStartPrev = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"); + if (pathMarkStartPrev) + gtk_tree_path_free(pathMarkStartPrev); + + iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)pathMarkStart); + + return 1; +} + +static char* gtkTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) +{ + GtkTreeSelection* selection; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return 0; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + if (gtk_tree_selection_iter_is_selected(selection, &iterItem)) + return "YES"; + else + return "NO"; +} + +static int gtkTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeSelection* selection; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return 0; + + iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", "1"); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + if (iupStrBoolean(value)) + gtk_tree_selection_select_iter(selection, &iterItem); + else + gtk_tree_selection_unselect_iter(selection, &iterItem); + + return 0; +} + +static int gtkTreeSetDelNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + if (iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */ + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem; + GtkTreeIter iterParent; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return 0; + + if (!gtk_tree_model_iter_parent(model, &iterParent, &iterItem)) /* the root node can't be deleted */ + return 0; + + gtkTreeCallNodeRemoved(ih, model, &iterItem); + + /* deleting the specified node (and it's children) */ + gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItem); + } + else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */ + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeIter iterItem, iterChild; + int hasChildren; + + if (!gtkTreeFindNodeFromString(ih, model, name_id, &iterItem)) + return 0; + + hasChildren = gtk_tree_model_iter_children(model, &iterChild, &iterItem); + + /* deleting the selected node's children */ + while(hasChildren) + { + gtkTreeCallNodeRemoved(ih, model, &iterChild); + hasChildren = gtk_tree_store_remove(GTK_TREE_STORE(model), &iterChild); + } + } + else if(iupStrEqualNoCase(value, "MARKED")) /* Delete the array of marked nodes */ + { + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + GList *rr_list = NULL; + GList *node; + + gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)gtkTreeSelected_Iter_Func, &rr_list); + + for(node = rr_list; node != NULL; node = node->next) + { + GtkTreePath* path = gtk_tree_row_reference_get_path(node->data); + if (path) + { + GtkTreeIter iterItem; + if (gtk_tree_model_get_iter(model, &iterItem, path)) + { + gtkTreeCallNodeRemoved(ih, model, &iterItem); + gtk_tree_store_remove(GTK_TREE_STORE(model), &iterItem); + } + gtk_tree_path_free(path); + } + gtk_tree_row_reference_free(node->data); + } + g_list_free(rr_list); + } + + return 0; +} + +static int gtkTreeSetRenameAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->show_rename) + { + GtkTreePath* path; + IFni cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); + GtkTreeViewColumn *focus_column; + + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, &focus_column); + + if (cbShowRename) + { + GtkTreeIter iterItem; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + gtk_tree_model_get_iter(model, &iterItem, path); + cbShowRename(ih, gtkTreeGetNodeId(ih, iterItem)); + } + + gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), path, focus_column, TRUE); + gtk_tree_path_free(path); + } + else + { + IFnis cbRenameNode = (IFnis)IupGetCallback(ih, "RENAMENODE_CB"); + if (cbRenameNode) + { + GtkTreePath* path; + GtkTreeIter iterItem; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &path, NULL); + gtk_tree_model_get_iter(model, &iterItem, path); + gtk_tree_path_free(path); + cbRenameNode(ih, gtkTreeGetNodeId(ih, iterItem), gtkTreeGetTitle(model, iterItem)); + } + } + + (void)value; + return 0; +} + +static int gtkTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int kind; + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GdkPixbuf* pixExpand = iupImageGetImage(value, ih, 0); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + return 0; + + gtk_tree_model_get(GTK_TREE_MODEL(store), &iterItem, IUPGTK_TREE_KIND, &kind, -1); + + if (kind == ITREE_BRANCH) + { + if (pixExpand) + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE_EXPANDED, pixExpand, + IUPGTK_TREE_HAS_IMAGE_EXPANDED, TRUE, -1); + else + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE_EXPANDED, ih->data->def_image_expanded, + IUPGTK_TREE_HAS_IMAGE_EXPANDED, FALSE, -1); + } + + return 1; +} + +static int gtkTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + GtkTreeStore* store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle))); + GdkPixbuf* pixImage = iupImageGetImage(value, ih, 0); + GtkTreeIter iterItem; + if (!gtkTreeFindNodeFromString(ih, GTK_TREE_MODEL(store), name_id, &iterItem)) + return 0; + + if (pixImage) + { + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE, pixImage, + IUPGTK_TREE_HAS_IMAGE, TRUE, -1); + } + else + { + int kind; + gtk_tree_model_get(GTK_TREE_MODEL(store), &iterItem, IUPGTK_TREE_KIND, &kind, -1); + if (kind == ITREE_BRANCH) + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_collapsed, + IUPGTK_TREE_HAS_IMAGE, FALSE, -1); + else + gtk_tree_store_set(store, &iterItem, IUPGTK_TREE_IMAGE, ih->data->def_image_leaf, + IUPGTK_TREE_HAS_IMAGE, FALSE, -1); + } + + return 1; +} + +static int gtkTreeSetImageBranchExpandedAttrib(Ihandle* ih, const char* value) +{ + GtkTreeIter iterRoot; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + ih->data->def_image_expanded = iupImageGetImage(value, ih, 0); + + gtk_tree_model_get_iter_first(model, &iterRoot); + + /* Update all images, starting at root node */ + gtkTreeUpdateImages(ih, model, iterRoot, ITREE_UPDATEIMAGE_EXPANDED); + + return 1; +} + +static int gtkTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value) +{ + GtkTreeIter iterRoot; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + ih->data->def_image_collapsed = iupImageGetImage(value, ih, 0); + + gtk_tree_model_get_iter_first(model, &iterRoot); + + /* Update all images, starting at root node */ + gtkTreeUpdateImages(ih, model, iterRoot, ITREE_UPDATEIMAGE_COLLAPSED); + + return 1; +} + +static int gtkTreeSetImageLeafAttrib(Ihandle* ih, const char* value) +{ + GtkTreeIter iterRoot; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + ih->data->def_image_leaf = iupImageGetImage(value, ih, 0); + + gtk_tree_model_get_iter_first(model, &iterRoot); + + /* Update all images, starting at root node */ + gtkTreeUpdateImages(ih, model, iterRoot, ITREE_UPDATEIMAGE_LEAF); + + return 1; +} + +static int gtkTreeSetBgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + + GtkScrolledWindow* scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (scrolled_window) + { + /* ignore given value, must use only from parent for the scrollbars */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + if (iupStrToRGB(parent_value, &r, &g, &b)) + { + GtkWidget* sb; + + if (!GTK_IS_SCROLLED_WINDOW(scrolled_window)) + scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUPGTK_SCROLLED_WINDOW"); + + iupgtkBaseSetBgColor((GtkWidget*)scrolled_window, r, g, b); + +#if GTK_CHECK_VERSION(2, 8, 0) + sb = gtk_scrolled_window_get_hscrollbar(scrolled_window); + if (sb) iupgtkBaseSetBgColor(sb, r, g, b); + + sb = gtk_scrolled_window_get_vscrollbar(scrolled_window); + if (sb) iupgtkBaseSetBgColor(sb, r, g, b); +#endif + } + } + + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + { + GtkCellRenderer* renderer_txt = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_TEXT"); + GtkCellRenderer* renderer_img = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_IMG"); + GdkColor color; + iupgdkColorSet(&color, r, g, b); + g_object_set(G_OBJECT(renderer_txt), "cell-background-gdk", &color, NULL); + g_object_set(G_OBJECT(renderer_img), "cell-background-gdk", &color, NULL); + } + + iupdrvBaseSetBgColorAttrib(ih, value); /* use given value for contents */ + + /* no need to update internal image cache in GTK */ + + return 1; +} + +static int gtkTreeSetFgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + iupgtkBaseSetFgColor(ih->handle, r, g, b); + + { + GtkCellRenderer* renderer_txt = (GtkCellRenderer*)iupAttribGet(ih, "_IUPGTK_RENDERER_TEXT"); + GdkColor color; + iupgdkColorSet(&color, r, g, b); + g_object_set(G_OBJECT(renderer_txt), "foreground-gdk", &color, NULL); + g_object_get(G_OBJECT(renderer_txt), "foreground-gdk", &color, NULL); + color.blue = 0; + } + + return 1; +} + +void iupdrvTreeUpdateMarkMode(Ihandle *ih) +{ + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + gtk_tree_selection_set_mode(selection, (ih->data->mark_mode==ITREE_MARK_SINGLE)? GTK_SELECTION_SINGLE: GTK_SELECTION_MULTIPLE); + + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && !ih->data->show_dragdrop) + { +#if GTK_CHECK_VERSION(2, 10, 0) + gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(ih->handle), TRUE); +#endif + } +} + + +/***********************************************************************************************/ + + +static void gtkTreeSetRenameCaretPos(GtkCellEditable *editable, const char* value) +{ + int pos = 1; + + if (iupStrToInt(value, &pos)) + { + if (pos < 1) pos = 1; + pos--; /* IUP starts at 1 */ + + gtk_editable_set_position(GTK_EDITABLE(editable), pos); + } +} + +static void gtkTreeSetRenameSelectionPos(GtkCellEditable *editable, const char* value) +{ + int start = 1, end = 1; + + if (iupStrToIntInt(value, &start, &end, ':') != 2) + return; + + if(start < 1 || end < 1) + return; + + start--; /* IUP starts at 1 */ + end--; + + gtk_editable_select_region(GTK_EDITABLE(editable), start, end); +} + +/*****************************************************************************/ +/* SIGNALS */ +/*****************************************************************************/ + +static void gtkTreeCellTextEditingStarted(GtkCellRenderer *cell, GtkCellEditable *editable, const gchar *path_string, Ihandle *ih) +{ + char* value; + GtkTreeIter iterItem; + PangoFontDescription* fontdesc = NULL; + GdkColor *color = NULL; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + + value = iupAttribGetStr(ih, "RENAMECARET"); + if (value) + gtkTreeSetRenameCaretPos(editable, value); + + value = iupAttribGetStr(ih, "RENAMESELECTION"); + if (value) + gtkTreeSetRenameSelectionPos(editable, value); + + gtk_tree_model_get_iter_from_string(model, &iterItem, path_string); + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_FONT, &fontdesc, -1); + if (fontdesc) + gtk_widget_modify_font(GTK_WIDGET(editable), fontdesc); + + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_COLOR, &color, -1); + if (color) + iupgtkBaseSetFgGdkColor(GTK_WIDGET(editable), color); + + (void)cell; +} + +static void gtkTreeCellTextEdited(GtkCellRendererText *cell, gchar *path_string, gchar *new_text, Ihandle* ih) +{ + GtkTreeModel* model; + GtkTreeIter iterItem; + IFnis cbRename; + + if (!new_text) + return; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + if (!gtk_tree_model_get_iter_from_string(model, &iterItem, path_string)) + return; + + cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB"); + if (cbRename) + { + if (cbRename(ih, gtkTreeGetNodeId(ih, iterItem), iupgtkStrConvertFromUTF8(new_text)) == IUP_IGNORE) + return; + } + + /* It is the responsibility of the application to update the model and store new_text at the position indicated by path. */ + gtk_tree_store_set(GTK_TREE_STORE(model), &iterItem, IUPGTK_TREE_TITLE, new_text, -1); + + (void)cell; +} + +static int gtkTreeCallDragDropCb(Ihandle* ih, GtkTreeIter *iterDrag, GtkTreeIter *iterDrop, int *is_ctrl) +{ + IFniiii cbDragDrop = (IFniiii)IupGetCallback(ih, "DRAGDROP_CB"); + int is_shift = 0; + char key[5]; + iupdrvGetKeyState(key); + if (key[0] == 'S') + is_shift = 1; + if (key[1] == 'C') + *is_ctrl = 1; + else + *is_ctrl = 0; + + if (cbDragDrop) + { + int drag_id = gtkTreeGetNodeId(ih, *iterDrag); + int drop_id = gtkTreeGetNodeId(ih, *iterDrop); + return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl); + } + + return IUP_CONTINUE; /* allow to move by default if callback not defined */ +} + +static void gtkTreeDragDataReceived(GtkWidget *widget, GdkDragContext *context, gint x, gint y, + GtkSelectionData *selection_data, guint info, guint time, Ihandle* ih) +{ + GtkTreePath* pathDrag = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DRAGITEM"); + GtkTreePath* pathDrop = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DROPITEM"); + int accepted = FALSE; + int is_ctrl; + + if (pathDrag && pathDrop) + { + GtkTreeIter iterDrag, iterDrop, iterParent, iterNextParent; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + + gtk_tree_model_get_iter(model, &iterDrag, pathDrag); + gtk_tree_model_get_iter(model, &iterDrop, pathDrop); + + iterParent = iterDrop; + while(gtk_tree_model_iter_parent(model, &iterNextParent, &iterParent)) + { + if (iterNextParent.user_data == iterDrag.user_data) + goto gtkTreeDragDataReceived_FINISH; + iterParent = iterNextParent; + } + + accepted = TRUE; + + if (gtkTreeCallDragDropCb(ih, &iterDrag, &iterDrop, &is_ctrl) == IUP_CONTINUE) + { + GtkTreeIter iterNewItem; + + /* Copy the dragged item to the new position. */ + gtkTreeCopyNode(ih, model, &iterDrag, &iterDrop, &iterNewItem, is_ctrl); + + if (!is_ctrl) + { + /* do not delete the user data, we copy the references in CopyNode */ + gtk_tree_store_remove(GTK_TREE_STORE(model), &iterDrag); + } + + /* set focus and selection */ + { + GtkTreePath *pathNew; + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + + pathNew = gtk_tree_model_get_path(model, &iterNewItem); + gtk_tree_selection_select_path(selection, pathNew); + + gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(ih->handle), pathNew, NULL, FALSE, 0, 0); + gtk_tree_view_set_cursor(GTK_TREE_VIEW(ih->handle), pathNew, NULL, FALSE); + + gtk_tree_path_free(pathNew); + } + } + } + +gtkTreeDragDataReceived_FINISH: + if (pathDrag) gtk_tree_path_free(pathDrag); + if (pathDrop) gtk_tree_path_free(pathDrop); + + iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", NULL); + iupAttribSetStr(ih, "_IUPTREE_DROPITEM", NULL); + + gtk_drag_finish(context, accepted, (context->action == GDK_ACTION_MOVE), time); + + (void)widget; + (void)info; + (void)x; + (void)y; + (void)selection_data; +} + +static gboolean gtkTreeDragDrop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, Ihandle* ih) +{ + GtkTreePath* path; + GtkTreeViewDropPosition pos; + GdkAtom target = GDK_NONE; + + /* unset any highlight row */ + gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW(widget), NULL, GTK_TREE_VIEW_DROP_BEFORE); + + if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, &pos)) + { + if ((pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER) && + (gtk_tree_path_compare(path, (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DRAGITEM")) != 0)) + { + target = gtk_drag_dest_find_target(widget, context, gtk_drag_dest_get_target_list(widget)); + if (target != GDK_NONE) + { + iupAttribSetStr(ih, "_IUPTREE_DROPITEM", (char*)path); + gtk_drag_get_data(widget, context, target, time); + return TRUE; + } + } + } + + (void)widget; + return FALSE; +} + +static void gtkTreeDragLeave(GtkWidget *widget, GdkDragContext *context, guint time) +{ + /* unset any highlight row */ + gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(widget), NULL, GTK_TREE_VIEW_DROP_BEFORE); + (void)context; + (void)time; +} + +static gboolean gtkTreeDragMotion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, Ihandle* ih) +{ + GtkTreePath* path; + GtkTreeViewDropPosition pos; + GtkTreePath* pathDrag = (GtkTreePath*)iupAttribGet(ih, "_IUPTREE_DRAGITEM"); + if (pathDrag && gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, &pos)) + { + if ((pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER) && + (gtk_tree_path_compare(path, pathDrag) != 0)) + { + gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(widget), path, pos); + gdk_drag_status(context, context->actions, time); + return TRUE; + } + + gtk_tree_path_free(path); + } + + (void)widget; + return FALSE; +} + +static void gtkTreeDragBegin(GtkWidget *widget, GdkDragContext *context, Ihandle* ih) +{ + int x = iupAttribGetInt(ih, "_IUPTREE_DRAG_X"); + int y = iupAttribGetInt(ih, "_IUPTREE_DRAG_Y"); + GtkTreePath* path; + GtkTreeViewDropPosition pos; + if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, &pos)) + { + if ((pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)) + { + GdkPixmap* pixmap; + iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", (char*)path); + + pixmap = gtk_tree_view_create_row_drag_icon(GTK_TREE_VIEW(ih->handle), path); + gtk_drag_source_set_icon(widget, gtk_widget_get_colormap(widget), pixmap, NULL); + g_object_unref(pixmap); + return; + } + } + + (void)context; + (void)widget; +} + +static void gtkTreeSelectionChanged(GtkTreeSelection* selection, Ihandle* ih) +{ + IFnii cbSelec; + int is_ctrl = 0; + + if (ih->data->mark_mode == ITREE_MARK_MULTIPLE) + { + char key[5]; + iupdrvGetKeyState(key); + if (key[0] == 'S') + return; + else if (key[1] == 'C') + is_ctrl = 1; + + if (iupAttribGetInt(ih, "_IUPTREE_EXTENDSELECT")==2 && !is_ctrl) + { + iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", NULL); + gtkTreeCallMultiSelectionCb(ih); + return; + } + } + + cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); + if (cbSelec) + { + int curpos = -1, is_selected = 0; + + if (iupAttribGet(ih, "_IUP_IGNORE_SELECTION")) + { + iupAttribSetStr(ih, "_IUP_IGNORE_SELECTION", NULL); + return; + } + + { + GtkTreeIter iterFocus; + GtkTreePath* pathFocus; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + gtk_tree_view_get_cursor(GTK_TREE_VIEW(ih->handle), &pathFocus, NULL); + if (pathFocus) + { + gtk_tree_model_get_iter(model, &iterFocus, pathFocus); + gtk_tree_path_free(pathFocus); + curpos = gtkTreeGetNodeId(ih, iterFocus); + is_selected = gtk_tree_selection_iter_is_selected(selection, &iterFocus); + } + } + + if (curpos == -1) + return; + + if (is_ctrl) + cbSelec(ih, curpos, is_selected); + else + { + int oldpos = iupAttribGetInt(ih, "_IUPTREE_OLDVALUE"); + if(oldpos != curpos) + { + cbSelec(ih, oldpos, 0); /* unselected */ + cbSelec(ih, curpos, 1); /* selected */ + + iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", curpos); + } + } + } +} + +static gboolean gtkTreeTestExpandRow(GtkTreeView* tree_view, GtkTreeIter *iterItem, GtkTreePath *path, Ihandle* ih) +{ + IFni cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB"); + if (cbBranchOpen) + { + if (iupAttribGet(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB")) + { + iupAttribSetStr(ih, "_IUPTREE_IGNORE_BRANCHOPEN_CB", NULL); + return FALSE; + } + + if (cbBranchOpen(ih, gtkTreeGetNodeId(ih, *iterItem)) == IUP_IGNORE) + return TRUE; /* prevent the change */ + } + + (void)path; + (void)tree_view; + return FALSE; +} + +static gboolean gtkTreeTestCollapseRow(GtkTreeView* tree_view, GtkTreeIter *iterItem, GtkTreePath *path, Ihandle* ih) +{ + IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB"); + if (cbBranchClose) + { + if (cbBranchClose(ih, gtkTreeGetNodeId(ih, *iterItem)) == IUP_IGNORE) + return TRUE; + } + + (void)path; + (void)tree_view; + return FALSE; +} + +static void gtkTreeRowActived(GtkTreeView* tree_view, GtkTreePath *path, GtkTreeViewColumn *column, Ihandle* ih) +{ + GtkTreeIter iterItem; + GtkTreeModel* model; + int kind; /* used for nodes defined as branches, but do not have children */ + IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB"); + if (!cbExecuteLeaf) + return; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + gtk_tree_model_get_iter(model, &iterItem, path); + gtk_tree_model_get(model, &iterItem, IUPGTK_TREE_KIND, &kind, -1); + + /* just to leaf nodes */ + if(gtk_tree_model_iter_has_child(model, &iterItem) == 0 && kind == ITREE_LEAF) + cbExecuteLeaf(ih, gtkTreeGetNodeId(ih, iterItem)); + + (void)column; + (void)tree_view; +} + +static int gtkTreeConvertXYToPos(Ihandle* ih, int x, int y) +{ + GtkTreePath* path; + if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(ih->handle), x, y, &path, NULL)) + { + GtkTreeIter iterItem; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + gtk_tree_model_get_iter(model, &iterItem, path); + gtk_tree_path_free (path); + return gtkTreeGetNodeId(ih, iterItem); + } + return -1; +} + +static gboolean gtkTreeButtonEvent(GtkWidget *treeview, GdkEventButton *evt, Ihandle* ih) +{ + if (iupgtkButtonEvent(treeview, evt, ih) == TRUE) + return TRUE; + + if (evt->type == GDK_BUTTON_PRESS && evt->button == 3) /* right single click */ + { + IFni cbRightClick = (IFni)IupGetCallback(ih, "RIGHTCLICK_CB"); + if (cbRightClick) + { + int id = gtkTreeConvertXYToPos(ih, (int)evt->x, (int)evt->y); + if (id != -1) + cbRightClick(ih, id); + return TRUE; + } + } + else if (evt->type == GDK_2BUTTON_PRESS && evt->button == 1) /* left double click */ + { + GtkTreePath *path; + + if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), (gint) evt->x, (gint) evt->y, &path, NULL, NULL, NULL)) + { + GtkTreeIter iter; + GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(ih->handle)); + int kind; /* used for nodes defined as branches, but do not have children */ + + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_get(model, &iter, IUPGTK_TREE_KIND, &kind, -1); + + if (kind == ITREE_BRANCH) + gtkTreeExpandItem(ih, path, -1); /* toggle */ + + gtk_tree_path_free(path); + } + } + else if (evt->type == GDK_BUTTON_RELEASE && evt->button == 1) /* left single release */ + { + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && (evt->state & GDK_SHIFT_MASK)) + gtkTreeCallMultiSelectionCb(ih); /* Multi Selection Callback */ + + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && + !(evt->state & GDK_SHIFT_MASK) && !(evt->state & GDK_CONTROL_MASK)) + { + if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT")) + iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "2"); + } + } + else if (evt->type == GDK_BUTTON_PRESS && evt->button == 1) /* left single press */ + { + iupAttribSetInt(ih, "_IUPTREE_DRAG_X", (int)evt->x); + iupAttribSetInt(ih, "_IUPTREE_DRAG_Y", (int)evt->y); + + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && + !(evt->state & GDK_SHIFT_MASK) && !(evt->state & GDK_CONTROL_MASK)) + iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "1"); + } + + return FALSE; +} + +static gboolean gtkTreeKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) +{ + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && (evt->state & GDK_SHIFT_MASK)) + { + if (evt->keyval == GDK_Up || evt->keyval == GDK_Down || evt->keyval == GDK_Home || evt->keyval == GDK_End) + gtkTreeCallMultiSelectionCb(ih); /* Multi Selection Callback */ + } + + (void)widget; + return TRUE; +} + +static gboolean gtkTreeKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) +{ + if (iupgtkKeyPressEvent(widget, evt, ih) == TRUE) + return TRUE; + + if (evt->keyval == GDK_F2) + { + gtkTreeSetRenameAttrib(ih, NULL); + return TRUE; + } + else if (evt->keyval == GDK_Return || evt->keyval == GDK_KP_Enter) + { + gtkTreeOpenCloseEvent(ih); + return TRUE; + } + + return FALSE; +} + +static void gtkTreeEnableDragDrop(Ihandle* ih) +{ + const GtkTargetEntry row_targets[] = { + { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 } + }; + + if (iupAttribGetBoolean(ih, "AUTODRAGDROP")) + { + gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW(ih->handle), + GDK_BUTTON1_MASK, + row_targets, + G_N_ELEMENTS(row_targets), + GDK_ACTION_MOVE|GDK_ACTION_COPY); + gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW(ih->handle), + row_targets, + G_N_ELEMENTS(row_targets), + GDK_ACTION_MOVE|GDK_ACTION_COPY); + } + else + { + gtk_drag_source_set(ih->handle, GDK_BUTTON1_MASK, row_targets, G_N_ELEMENTS(row_targets), GDK_ACTION_MOVE|GDK_ACTION_COPY); + gtk_drag_dest_set(ih->handle, GDK_BUTTON1_MASK, row_targets, G_N_ELEMENTS(row_targets), GDK_ACTION_MOVE|GDK_ACTION_COPY); + + g_signal_connect(G_OBJECT(ih->handle), "drag-begin", G_CALLBACK(gtkTreeDragBegin), ih); + g_signal_connect(G_OBJECT(ih->handle), "drag-motion", G_CALLBACK(gtkTreeDragMotion), ih); + g_signal_connect(G_OBJECT(ih->handle), "drag-leave", G_CALLBACK(gtkTreeDragLeave), NULL); + g_signal_connect(G_OBJECT(ih->handle), "drag-drop", G_CALLBACK(gtkTreeDragDrop), ih); + g_signal_connect(G_OBJECT(ih->handle), "drag-data-received", G_CALLBACK(gtkTreeDragDataReceived), ih); + } +} + +/*****************************************************************************/ + +static int gtkTreeMapMethod(Ihandle* ih) +{ + GtkScrolledWindow* scrolled_window = NULL; + GtkTreeStore *store; + GtkCellRenderer *renderer_img, *renderer_txt; + GtkTreeSelection* selection; + GtkTreeViewColumn *column; + + store = gtk_tree_store_new(9, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN, + G_TYPE_STRING, G_TYPE_INT, GDK_TYPE_COLOR, PANGO_TYPE_FONT_DESCRIPTION, G_TYPE_POINTER); + + ih->handle = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + + g_object_unref(store); + + if (!ih->handle) + return IUP_ERROR; + + scrolled_window = (GtkScrolledWindow*)gtk_scrolled_window_new(NULL, NULL); + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)scrolled_window); + + /* Column and renderers */ + column = gtk_tree_view_column_new(); + iupAttribSetStr(ih, "_IUPGTK_COLUMN", (char*)column); + + renderer_img = gtk_cell_renderer_pixbuf_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(column), renderer_img, FALSE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(column), renderer_img, "pixbuf", IUPGTK_TREE_IMAGE, + "pixbuf-expander-open", IUPGTK_TREE_IMAGE_EXPANDED, + "pixbuf-expander-closed", IUPGTK_TREE_IMAGE, + NULL); + iupAttribSetStr(ih, "_IUPGTK_RENDERER_IMG", (char*)renderer_img); + + renderer_txt = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(column), renderer_txt, TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(column), renderer_txt, "text", IUPGTK_TREE_TITLE, + "is-expander", IUPGTK_TREE_KIND, + "font-desc", IUPGTK_TREE_FONT, + "foreground-gdk", IUPGTK_TREE_COLOR, + NULL); + iupAttribSetStr(ih, "_IUPGTK_RENDERER_TEXT", (char*)renderer_txt); + + if (ih->data->show_rename) + g_object_set(G_OBJECT(renderer_txt), "editable", TRUE, NULL); + + g_object_set(G_OBJECT(renderer_txt), "xpad", 0, NULL); + g_object_set(G_OBJECT(renderer_txt), "ypad", 0, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(ih->handle), column); + + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(ih->handle), FALSE); + gtk_tree_view_set_enable_search(GTK_TREE_VIEW(ih->handle), FALSE); + +#if GTK_CHECK_VERSION(2, 10, 0) + if (iupAttribGetBoolean(ih, "HIDELINES")) + gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(ih->handle), FALSE); + else + gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(ih->handle), TRUE); +#endif + +#if GTK_CHECK_VERSION(2, 12, 0) + if (iupAttribGetBoolean(ih, "HIDEBUTTONS")) + gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(ih->handle), FALSE); + else + gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(ih->handle), TRUE); +#endif + + if (ih->data->show_dragdrop) + gtkTreeEnableDragDrop(ih); + + gtk_container_add((GtkContainer*)scrolled_window, ih->handle); + gtk_widget_show((GtkWidget*)scrolled_window); + gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_IN); + + gtk_scrolled_window_set_policy(scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ih->handle)); + + gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); + gtk_tree_view_set_reorderable(GTK_TREE_VIEW(ih->handle), FALSE); + + /* callbacks */ + g_signal_connect(selection, "changed", G_CALLBACK(gtkTreeSelectionChanged), ih); + + g_signal_connect(renderer_txt, "editing-started", G_CALLBACK(gtkTreeCellTextEditingStarted), ih); + g_signal_connect(renderer_txt, "edited", G_CALLBACK(gtkTreeCellTextEdited), ih); + + g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih); + g_signal_connect(G_OBJECT(ih->handle), "motion-notify-event",G_CALLBACK(iupgtkMotionNotifyEvent), ih); + + g_signal_connect(G_OBJECT(ih->handle), "test-expand-row", G_CALLBACK(gtkTreeTestExpandRow), ih); + g_signal_connect(G_OBJECT(ih->handle), "test-collapse-row", G_CALLBACK(gtkTreeTestCollapseRow), ih); + g_signal_connect(G_OBJECT(ih->handle), "row-activated", G_CALLBACK(gtkTreeRowActived), ih); + g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkTreeKeyPressEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "key-release-event", G_CALLBACK(gtkTreeKeyReleaseEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkTreeButtonEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkTreeButtonEvent), ih); + + /* add to the parent, all GTK controls must call this. */ + iupgtkBaseAddToParent(ih); + + if (!iupAttribGetBoolean(ih, "CANFOCUS")) + GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS; + + gtk_widget_realize((GtkWidget*)scrolled_window); + gtk_widget_realize(ih->handle); + + /* Initialize the default images */ + ih->data->def_image_leaf = iupImageGetImage("IMGLEAF", ih, 0); + ih->data->def_image_collapsed = iupImageGetImage("IMGCOLLAPSED", ih, 0); + ih->data->def_image_expanded = iupImageGetImage("IMGEXPANDED", ih, 0); + + gtkTreeAddRootNode(ih); + + /* configure for DRAG&DROP of files */ + if (IupGetCallback(ih, "DROPFILES_CB")) + iupAttribSetStr(ih, "DRAGDROP", "YES"); + + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)gtkTreeConvertXYToPos); + + return IUP_NOERROR; +} + +void iupdrvTreeInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkTreeMapMethod; + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkTreeSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, gtkTreeSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT); + + /* IupTree Attributes - GENERAL */ + iupClassRegisterAttribute(ic, "EXPANDALL", NULL, gtkTreeSetExpandAllAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INDENTATION", gtkTreeGetIndentationAttrib, gtkTreeSetIndentationAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "COUNT", gtkTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPACING", iupTreeGetSpacingAttrib, gtkTreeSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "TOPITEM", NULL, gtkTreeSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + + /* IupTree Attributes - IMAGES */ + iupClassRegisterAttributeId(ic, "IMAGE", NULL, gtkTreeSetImageAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "IMAGEEXPANDED", NULL, gtkTreeSetImageExpandedAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "IMAGELEAF", NULL, gtkTreeSetImageLeafAttrib, IUPAF_SAMEASSYSTEM, "IMGLEAF", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGEBRANCHCOLLAPSED", NULL, gtkTreeSetImageBranchCollapsedAttrib, IUPAF_SAMEASSYSTEM, "IMGCOLLAPSED", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGEBRANCHEXPANDED", NULL, gtkTreeSetImageBranchExpandedAttrib, IUPAF_SAMEASSYSTEM, "IMGEXPANDED", IUPAF_NO_INHERIT); + + /* IupTree Attributes - NODES */ + iupClassRegisterAttributeId(ic, "STATE", gtkTreeGetStateAttrib, gtkTreeSetStateAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "DEPTH", gtkTreeGetDepthAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "KIND", gtkTreeGetKindAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "PARENT", gtkTreeGetParentAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "COLOR", gtkTreeGetColorAttrib, gtkTreeSetColorAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "NAME", gtkTreeGetTitleAttrib, gtkTreeSetTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLE", gtkTreeGetTitleAttrib, gtkTreeSetTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "USERDATA", gtkTreeGetUserDataAttrib, gtkTreeSetUserDataAttrib, IUPAF_NO_STRING|IUPAF_NO_INHERIT); + + iupClassRegisterAttributeId(ic, "CHILDCOUNT", gtkTreeGetChildCountAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLEFONT", gtkTreeGetTitleFontAttrib, gtkTreeSetTitleFontAttrib, IUPAF_NO_INHERIT); + + /* IupTree Attributes - MARKS */ + iupClassRegisterAttributeId(ic, "MARKED", gtkTreeGetMarkedAttrib, gtkTreeSetMarkedAttrib, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARK", NULL, gtkTreeSetMarkAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "STARTING", NULL, gtkTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARKSTART", NULL, gtkTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute (ic, "VALUE", gtkTreeGetValueAttrib, gtkTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupTree Attributes - ACTION */ + iupClassRegisterAttributeId(ic, "DELNODE", NULL, gtkTreeSetDelNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "RENAME", NULL, gtkTreeSetRenameAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "MOVENODE", NULL, gtkTreeSetMoveNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "COPYNODE", NULL, gtkTreeSetCopyNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "FINDUSERDATA", gtkTreeGetFindUserDataAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute (ic, "AUTODRAGDROP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT); +} diff --git a/iup/src/gtk/iupgtk_val.c b/iup/src/gtk/iupgtk_val.c new file mode 100755 index 0000000..018af83 --- /dev/null +++ b/iup/src/gtk/iupgtk_val.c @@ -0,0 +1,208 @@ +/** \file + * \brief Valuator Control + * + * See Copyright Notice in "iup.h" + */ + +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_val.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_key.h" + +#include "iupgtk_drv.h" + + +void iupdrvValGetMinSize(Ihandle* ih, int *w, int *h) +{ + if (ih->data->type == IVAL_HORIZONTAL) + { + *w = 20; + *h = 35; + } + else + { + *w = 35; + *h = 20; + } +} + +static int gtkValSetStepAttrib(Ihandle* ih, const char* value) +{ + ih->data->step = atof(value); + gtk_range_set_increments(GTK_RANGE(ih->handle), ih->data->step, ih->data->pagestep); + return 0; /* do not store value in hash table */ +} + +static int gtkValSetPageStepAttrib(Ihandle* ih, const char* value) +{ + ih->data->pagestep = atof(value); + gtk_range_set_increments(GTK_RANGE(ih->handle), ih->data->step, ih->data->pagestep); + return 0; /* do not store value in hash table */ +} + +static int gtkValSetValueAttrib(Ihandle* ih, const char* value) +{ + double fval; + ih->data->val = atof(value); + fval = (ih->data->val-ih->data->vmin)/(ih->data->vmax - ih->data->vmin); + gtk_range_set_value(GTK_RANGE(ih->handle), fval); + return 0; /* do not store value in hash table */ +} + + +/*********************************************************************************************/ + + +static gboolean gtkValChangeValue(GtkRange *range, GtkScrollType scroll, double fval, Ihandle *ih) +{ + double old_val = ih->data->val; + IFn cb; + + if (fval < 0.0) + gtk_range_set_value(GTK_RANGE(ih->handle), 0.0); + if (fval > 1.0) + gtk_range_set_value(GTK_RANGE(ih->handle), 1.0); + + ih->data->val = fval*(ih->data->vmax - ih->data->vmin) + ih->data->vmin; + iupValCropValue(ih); + + cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB"); + if (cb) + { + if (ih->data->val == old_val) + return FALSE; + + cb(ih); + } + else + { + IFnd cb_old; + if (scroll == GTK_SCROLL_JUMP) /* scroll == 1 */ + cb_old = (IFnd)IupGetCallback(ih, "MOUSEMOVE_CB"); + else if((scroll >= GTK_SCROLL_STEP_BACKWARD) && (scroll <= GTK_SCROLL_END)) + cb_old = (IFnd)IupGetCallback(ih, "BUTTON_PRESS_CB"); + else + cb_old = (IFnd)IupGetCallback(ih, "BUTTON_RELEASE_CB"); + if (cb_old) + cb_old(ih, ih->data->val); + } + + if (fval < 0.0 || fval > 1.0) + return TRUE; + + (void)range; + return FALSE; +} + +static gboolean gtkValKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) +{ + if (iupgtkKeyPressEvent(widget, evt, ih) == TRUE) + return TRUE; + + /* change Home and End default behaviour */ + if (ih->data->inverted) + { + if (evt->keyval==GDK_Home || evt->keyval==GDK_KP_Home) + { + /* set to maximum */ + gtk_range_set_value(GTK_RANGE(ih->handle), 1.0); + gtkValChangeValue(GTK_RANGE(ih->handle), GTK_SCROLL_START, 1.0, ih); + return TRUE; + } + if (evt->keyval==GDK_End || evt->keyval==GDK_KP_End) + { + /* set to minimum */ + gtk_range_set_value(GTK_RANGE(ih->handle), 0.0); + gtkValChangeValue(GTK_RANGE(ih->handle), GTK_SCROLL_END, 0.0, ih); + return TRUE; + } + } + + return FALSE; +} + +/*********************************************************************************************/ + + +static int gtkValMapMethod(Ihandle* ih) +{ + GtkObject *adjustment; + + /* value, lower, upper, step_increment, page_increment, page_size */ + /* page_size value only makes a difference for scrollbar widgets */ + adjustment = gtk_adjustment_new (0, 0, 1.0, 0.01, 0.1, 0); + if (!adjustment) + return IUP_ERROR; + + if (ih->data->type == IVAL_HORIZONTAL) + ih->handle = gtk_hscale_new(GTK_ADJUSTMENT(adjustment)); + else + ih->handle = gtk_vscale_new(GTK_ADJUSTMENT(adjustment)); + + if (!ih->handle) + return IUP_ERROR; + + /* add to the parent, all GTK controls must call this. */ + iupgtkBaseAddToParent(ih); + + if (!iupAttribGetBoolean(ih, "CANFOCUS")) + GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS; + + g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih); + + g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkValKeyPressEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "change-value", G_CALLBACK(gtkValChangeValue), ih); + + /* configure the scale */ + gtk_scale_set_draw_value(GTK_SCALE(ih->handle), FALSE); + gtk_range_set_range(GTK_RANGE(ih->handle), 0.0, 1.0); + + if (ih->data->inverted) + gtk_range_set_inverted(GTK_RANGE(ih->handle), TRUE); + + gtk_widget_realize(ih->handle); + + /* update a mnemonic in a label if necessary */ + iupgtkUpdateMnemonic(ih); + + return IUP_NOERROR; +} + +void iupdrvValInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkValMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + + /* IupVal only */ + iupClassRegisterAttribute(ic, "VALUE", iupValGetValueAttrib, gtkValSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PAGESTEP", iupValGetPageStepAttrib, gtkValSetPageStepAttrib, IUPAF_SAMEASSYSTEM, "0.1", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "STEP", iupValGetStepAttrib, gtkValSetStepAttrib, IUPAF_SAMEASSYSTEM, "0.01", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWTICKS", NULL, NULL, NULL, NULL, IUPAF_WRITEONLY|IUPAF_READONLY); /* showticks is not supported in GTK */ +} diff --git a/iup/src/iup.c b/iup/src/iup.c new file mode 100755 index 0000000..df4bf34 --- /dev/null +++ b/iup/src/iup.c @@ -0,0 +1,86 @@ +/** \file + * \brief miscelaneous functions + * + * See Copyright Notice in "iup.h" + */ + +/*! \mainpage IUP + * + * \section intro Introduction + * + * Internal SDK documentation of the IUP library, automatically generated using Doxygen (<A HREF="http://www.doxygen.org/">http://www.doxygen.org/</A>). + * + * \section codestd Code Standards + * + * \subsection func Function Names (prefix format) + * - IupFunc - User API, implemented in the core + * - iupFunc - Internal Core API, implemented in the core, used in the core or in driver + * - iupxxxFunc - Windows Internal API, implemented in driver xxx, used in driver xxx + * - iupdrvFunc - Driver API, implemented in driver, used in the core or driver + * - xxxFunc - Driver xxx local functions + * + * \subsection glob Globais Variables (lower case format) + * - iupxxx_var + * + * \subsection loc Local Variables (lower case format, using module name) + * - iyyy_var + * + * \subsection fil File Names + * - iupyyy.h - public headers + * - iup_yyy.h/c - core + * - iupxxx_yyy.h/c - driver + * + * \subsection strc Structures + * - Iyyy + * + * \subsection com File Comments (at start) + * - Check an existant file for example. + * + * \subsection inc Include Defines + * - __IUPXXX_H (same file name, upper case, "__" preffix and replace "." by "_") + * + * \subsection doc Documentation + * - In the header, using Doxygen commands. + * - Check an existant header for example. + * + */ + +/** \defgroup util Utilities + */ + +/** \defgroup cpi Control SDK + * \par + * <H3><A HREF="../en/cpi.html">Control Creation Guide</A></H3> + */ + +#include <stdlib.h> + +#include "iup.h" + +/* This appears only here to avoid changing the iup.h header fo bug fixes */ +#define IUP_VERSION_FIX " RC3" +#define IUP_VERSION_FIX_NUMBER 0 + +const char iup_ident[] = + "$IUP: " IUP_VERSION IUP_VERSION_FIX " " IUP_COPYRIGHT " $\n" + "$URL: www.tecgraf.puc-rio.br/iup $\n"; + +/* Using this, if you look for the string TECVER, you will find also the library version. */ +const char *iup_tecver = "TECVERID.str:Iup:LIB:" IUP_VERSION IUP_VERSION_FIX; + +char* IupVersion(void) +{ + (void)iup_tecver; + (void)iup_ident; + return IUP_VERSION IUP_VERSION_FIX; +} + +char* IupVersionDate(void) +{ + return IUP_VERSION_DATE; +} + +int IupVersionNumber(void) +{ + return IUP_VERSION_NUMBER+IUP_VERSION_FIX_NUMBER; +} diff --git a/iup/src/iup.def b/iup/src/iup.def new file mode 100755 index 0000000..d0dcfbd --- /dev/null +++ b/iup/src/iup.def @@ -0,0 +1,353 @@ +EXPORTS +IupAlarm +IupAppend +IupButton +IupCanvas +IupClose +IupCreate +IupCreatep +IupCreatev +IupDestroy +IupDetach +IupDialog +IupFileDlg +IupFill +IupFlush +IupFrame +IupGetActionName +IupGetAllDialogs +IupGetAllNames +IupGetAttribute +IupGetAttributes +IupGetDialog +IupGetFile +IupGetFloat +IupGetFocus +IupGetFunction +IupGetGlobal +IupGetHandle +IupGetInt +IupGetLanguage +IupGetName +IupHbox +IupHelp +IupImage +IupHide +IupItem +IupLabel +IupList +IupListDialog +IupLoad +IupLoadBuffer +IupLoopStep +IupMainLoop +IupMap +IupMapFont +IupMenu +IupMessage +IupMessagef +IupMultiLine +IupNextField +IupOpen +IupPopup +IupPreviousField +IupRadio +IupScanf +IupSeparator +IupSetAttribute +IupSetAttributes +IupSetfAttribute +IupSetAtt +IupSetFocus +IupSetFunction +IupSetGlobal +IupSetHandle +IupSetLanguage +IupShow +IupShowXY +IupStoreAttribute +IupStoreGlobal +IupSubmenu +IupText +IupToggle +IupUnMapFont +IupUser +IupVbox +IupVersion +IupVersionDate +IupZbox +IupTimer +IupClipboard +IupGetNextChild +IupGetBrother +IupGetParent +IupVersionNumber +IupRefresh +IupGetText +IupVboxv +IupZboxv +IupHboxv +IupMenuv +IupSetCallback +IupGetCallback +IupGetChild +IupGetChildPos +IupGetChildCount +IupGetAllAttributes +IupSetAttributeHandle +IupGetAttributeHandle +IupExitLoop +IupUpdate +IupRedraw +IupImageRGB +IupImageRGBA +IupUnmap +IupReparent +IupMessageDlg +IupColorDlg +IupFontDlg +IupSbox +IupSpin +IupSpinbox +IupCboxv +IupCbox +IupVal +IupProgressBar +IupTabs +IupTabsv +IupGetClassAttributes +IupSetClassDefaultAttribute +IupSaveClassAttributes +IupGetColor +IupGetParam +IupGetParamv +iupGetParamType +iupGetParamCount +IupNormalizer +IupNormalizerv +IupGetClassType +IupGetClassName +IupInsert +IupMainLoopLevel +IupGetDialogChild +IupConvertXYToPos +IupTextConvertLinColToPos +IupTextConvertPosToLinCol +IupUpdateChildren +IupTreeSetAttribute +IupTreeStoreAttribute +IupTreeGetAttribute +IupTreeGetInt +IupTreeGetFloat +IupTreeSetfAttribute +IupTree +IupTreeGetId +IupTreeGetUserId +IupTreeSetUserId +IupSaveImageAsText + +iupdrvSetVisible +iupdrvSetStandardFontAttrib +iupdrvSetCurrentDirectory +iupdrvSetActive +iupdrvScreenToClient +iupdrvReparent +iupdrvMakeDirectory +iupdrvIsVisible +iupdrvIsFile +iupdrvIsDirectory +iupdrvIsActive +iupdrvGetWindowDecor +iupdrvGetUserName +iupdrvGetSystemVersion +iupdrvGetSystemName +iupdrvGetSystemFont +iupdrvGetScrollbarSize +iupdrvGetScreenSize +iupdrvGetScreenDepth +iupdrvGetKeyState +iupdrvGetFullSize +iupdrvGetDisplay +iupdrvGetCursorPos +iupdrvGetCurrentDirectory +iupdrvGetComputerName +iupdrvFontGetStringWidth +iupdrvFontGetMultiLineStringSize +iupdrvFontGetCharSize +iupdrvDrawFocusRect +iupdrvDisplayUpdate +iupdrvDisplayRedraw +iupdrvBaseUnMapMethod +iupdrvBaseSetZorderAttrib +iupdrvBaseSetTipVisibleAttrib +iupdrvBaseSetTipAttrib +iupdrvBaseSetCursorAttrib +iupdrvBaseLayoutUpdateMethod +iupdrvBaseGetYAttrib +iupdrvBaseGetXAttrib +iupdrvBaseGetClientSizeAttrib +iupdrvActivate +iupdrvImageCreateImageRaw +iupdrvImageGetRawInfo +iupdrvImageGetRawData +iupdrvImageDestroy +iupVersionDlg +iupTableSetFunc +iupTableSet +iupTableRemoveCurr +iupTableRemove +iupTableNext +iupTableGetTyped +iupTableGetFunc +iupTableGetCurr +iupTableGet +iupTableFirst +iupTableDestroy +iupTableCreateSized +iupTableCreate +iupTableCount +iupTableClear +iupStrToUnix +iupStrToStrStr +iupStrToRGB +iupStrToRGBA +iupStrToMac +iupStrToIntInt +iupStrToInt +iupStrToFloatFloat +iupStrToFloat +iupStrToDos +iupStrReplace +iupStrRemove +iupStrProcessMnemonic +iupStrNextLine +iupStrMessageShowError +iupStrMessageGet +iupStrLower +iupStrLineCount +iupStrInsert +iupStrGetMemoryCopy +iupStrGetMemory +iupStrFileMakeFileName +iupStrFileGetTitle +iupStrFileGetPath +iupStrFileGetExt +iupStrEqualPartial +iupStrEqualNoCase +iupStrEqual +iupStrDup +iupStrCountChar +iupStrCopyUntil +iupStrCopyN +iupStrBoolean +iupSetFontStyleAttrib +iupSetFontSizeAttrib +iupSetFontAttrib +iupRegisterFindClass +iupRegisterClass +iupObjectGetParamList +iupObjectCheck +iupMaskDestroy +iupMaskCreateInt +iupMaskCreateFloat +iupMaskCreate +iupMaskCheck +iupKeyNameToCode +iupKeyForEach +iupKeyCodeToName +iupKeyCanCaps +iupKeyCallKeyPressCb +iupKeyCallKeyCb +iupKeyProcessNavigation +iupImageStockSet +iupImageStockLoad +iupImageColorMakeInactive +iupGetFontStyleAttrib +iupGetFontSizeAttrib +iupGetFontFaceAttrib +iupGetFontAttrib +iupFontParseX +iupFontParseWin +iupFontParsePango +iupFocusCanAccept +iupError +iupGlobalIsPointer +iupDlgListVisibleInc +iupDlgListVisibleDec +iupDlgListVisibleCount +iupDlgListRemove +iupDlgListNext +iupDlgListFirst +iupDlgListAdd +iupDialogGetClass +iupDataEntry +iupClassRelease +iupClassRegisterCallback +iupClassRegisterAttributeId +iupClassRegisterAttribute +iupClassRegisterGetAttribute +iupClassObjectUnMap +iupClassObjectSetChildrenPosition +iupClassObjectSetChildrenCurrentSize +iupClassObjectSetAttribute +iupClassObjectMap +iupClassObjectLayoutUpdate +iupClassObjectGetInnerContainer +iupClassObjectGetAttribute +iupClassObjectGetAttributeInfo +iupClassObjectAttribIsNotString +iupClassObjectDlgPopup +iupClassObjectDestroy +iupClassObjectCreate +iupClassObjectComputeNaturalSize +iupClassObjectChildRemoved +iupClassObjectChildAdded +iupClassNew +iupClassCallbackGetFormat +iupChildTreeGetNativeParentHandle +iupChildTreeGetNativeParent +iupChildTreeAppend +iupCanvasGetClass +iupCallKillFocusCb +iupCallGetFocusCb +iupBaseSetVisibleAttrib +iupBaseSetSizeAttrib +iupBaseSetRasterSizeAttrib +iupBaseSetActiveAttrib +iupBaseRegisterVisualAttrib +iupBaseRegisterCommonAttrib +iupBaseGetWidAttrib +iupBaseGetVisibleAttrib +iupBaseGetSizeAttrib +iupBaseGetScrollbar +iupBaseGetRasterSizeAttrib +iupBaseGetActiveAttrib +iupBaseContainerUpdateExpand +iupBaseContainerGetExpandAttrib +iupBaseTypeVoidMapMethod +iupBaseSetPosition +iupBaseComputeNaturalSize +iupBaseSetCurrentSize +iupBaseCallValueChangedCb +iupAttribStoreStr +iupAttribSetStrf +iupAttribSetStr +iupAttribSetInt +iupAttribSetHandleName +iupAttribSetFloat +iupAttribIsPointer +iupAttribGet +iupAttribGetInherit +iupAttribGetInheritNativeParent +iupAttribGetStr +iupAttribGetInt +iupAttribGetBoolean +iupAttribGetFloat +iupAssert +iupArrayInc +iupArrayGetData +iupArrayDestroy +iupArrayCreate +iupArrayCount +iupArrayAdd +iupSaveImageAsText diff --git a/iup/src/iup.dep b/iup/src/iup.dep new file mode 100644 index 0000000..63394d5 --- /dev/null +++ b/iup/src/iup.dep @@ -0,0 +1,334 @@ +$(OBJDIR)/iup_array.o: iup_array.c iup_array.h iup_assert.h +$(OBJDIR)/iup_callback.o: iup_callback.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_assert.h +$(OBJDIR)/iup_dlglist.o: iup_dlglist.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_dlglist.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_assert.h +$(OBJDIR)/iup_attrib.o: iup_attrib.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_childtree.h iup_str.h iup_ledlex.h iup_attrib.h \ + iup_assert.h +$(OBJDIR)/iup_focus.o: iup_focus.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_focus.h iup_assert.h iup_attrib.h \ + iup_str.h iup_drv.h +$(OBJDIR)/iup_font.o: iup_font.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_str.h iup_drvfont.h iup_assert.h iup_attrib.h \ + iup_class.h iup_table.h iup_classbase.h +$(OBJDIR)/iup_globalattrib.o: iup_globalattrib.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h iup_table.h iup_globalattrib.h \ + iup_drv.h iup_drvfont.h iup_assert.h iup_str.h +$(OBJDIR)/iup_object.o: iup_object.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_assert.h iup_register.h iup_names.h +$(OBJDIR)/iup_key.o: iup_key.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_key.h iup_str.h \ + iup_object.h iup_class.h iup_table.h iup_classbase.h iup_drv.h \ + iup_focus.h +$(OBJDIR)/iup_layout.o: iup_layout.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_drv.h iup_attrib.h iup_str.h iup_layout.h \ + iup_assert.h +$(OBJDIR)/iup_ledlex.o: iup_ledlex.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_class.h iup_table.h iup_classbase.h \ + iup_ledlex.h iup_str.h iup_register.h +$(OBJDIR)/iup_names.o: iup_names.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_str.h iup_table.h iup_names.h iup_object.h \ + iup_class.h iup_classbase.h iup_assert.h +$(OBJDIR)/iup_open.o: iup_open.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_str.h iup_globalattrib.h iup_names.h iup_func.h \ + iup_drv.h iup_drvinfo.h iup_drvfont.h iup_predial.h iup_class.h \ + iup_table.h iup_classbase.h iup_register.h iup_key.h iup_image.h \ + iup_dlglist.h iup_assert.h iup_strmessage.h +$(OBJDIR)/iup_ledparse.o: iup_ledparse.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_ledlex.h iup_str.h iup_assert.h +$(OBJDIR)/iup_predial.o: iup_predial.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_predial.h iup_attrib.h iup_str.h \ + iup_strmessage.h +$(OBJDIR)/iup_register.o: iup_register.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_register.h iup_stdcontrols.h +$(OBJDIR)/iup_scanf.o: iup_scanf.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_predial.h iup_str.h iup_assert.h +$(OBJDIR)/iup_show.o: iup_show.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_layout.h iup_attrib.h iup_dialog.h iup_menu.h \ + iup_assert.h iup_str.h iup_drv.h iup_drvfont.h +$(OBJDIR)/iup_str.o: iup_str.c iup_str.h +$(OBJDIR)/iup_table.o: iup_table.c iup_table.h iup_str.h iup_assert.h +$(OBJDIR)/iup_func.o: iup_func.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_str.h iup_table.h iup_func.h iup_drv.h \ + iup_assert.h +$(OBJDIR)/iup_childtree.o: iup_childtree.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_dlglist.h iup_childtree.h iup_attrib.h iup_assert.h \ + iup_str.h iup_drv.h +$(OBJDIR)/iup.o: iup.c ../include/iup.h ../include/iupkey.h ../include/iupdef.h +$(OBJDIR)/iup_classattrib.o: iup_classattrib.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_drv.h iup_drvfont.h iup_str.h iup_attrib.h \ + iup_assert.h iup_register.h iup_globalattrib.h +$(OBJDIR)/iup_dialog.o: iup_dialog.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_class.h iup_table.h \ + iup_classbase.h iup_object.h iup_dlglist.h iup_layout.h iup_attrib.h \ + iup_drv.h iup_drvinfo.h iup_drvfont.h iup_focus.h iup_str.h \ + iup_dialog.h +$(OBJDIR)/iup_assert.o: iup_assert.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_assert.h iup_attrib.h iup_str.h \ + iup_strmessage.h +$(OBJDIR)/iup_canvas.o: iup_canvas.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_canvas.h +$(OBJDIR)/iup_messagedlg.o: iup_messagedlg.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_stdcontrols.h +$(OBJDIR)/iup_timer.o: iup_timer.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_str.h iup_stdcontrols.h iup_timer.h +$(OBJDIR)/iup_image.o: iup_image.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_attrib.h iup_str.h iup_image.h iup_assert.h \ + iup_stdcontrols.h +$(OBJDIR)/iup_label.o: iup_label.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_label.h iup_image.h +$(OBJDIR)/iup_fill.o: iup_fill.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h +$(OBJDIR)/iup_zbox.o: iup_zbox.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h +$(OBJDIR)/iup_colordlg.o: iup_colordlg.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h +$(OBJDIR)/iup_fontdlg.o: iup_fontdlg.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h +$(OBJDIR)/iup_filedlg.o: iup_filedlg.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h +$(OBJDIR)/iup_strmessage.o: iup_strmessage.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_attrib.h iup_str.h iup_strmessage.h iup_table.h +$(OBJDIR)/iup_menu.o: iup_menu.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_attrib.h iup_dialog.h iup_str.h iup_assert.h \ + iup_key.h iup_stdcontrols.h iup_drvinfo.h iup_menu.h +$(OBJDIR)/iup_frame.o: iup_frame.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_frame.h +$(OBJDIR)/iup_user.o: iup_user.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_stdcontrols.h +$(OBJDIR)/iup_button.o: iup_button.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_button.h iup_image.h +$(OBJDIR)/iup_radio.o: iup_radio.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h +$(OBJDIR)/iup_toggle.o: iup_toggle.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_toggle.h iup_image.h +$(OBJDIR)/iup_progressbar.o: iup_progressbar.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_progressbar.h +$(OBJDIR)/iup_text.o: iup_text.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_mask.h iup_array.h \ + iup_text.h iup_assert.h +$(OBJDIR)/iup_val.o: iup_val.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h ../include/iupcontrols.h \ + iup_object.h iup_class.h iup_table.h iup_classbase.h iup_attrib.h \ + iup_str.h iup_drv.h iup_stdcontrols.h iup_layout.h iup_val.h +$(OBJDIR)/iup_box.o: iup_box.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_box.h +$(OBJDIR)/iup_hbox.o: iup_hbox.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_box.h +$(OBJDIR)/iup_vbox.o: iup_vbox.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_box.h +$(OBJDIR)/iup_cbox.o: iup_cbox.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h +$(OBJDIR)/iup_class.o: iup_class.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_drv.h iup_drvfont.h iup_str.h iup_attrib.h \ + iup_assert.h +$(OBJDIR)/iup_classbase.o: iup_classbase.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_drv.h iup_drvfont.h iup_str.h \ + iup_attrib.h iup_assert.h +$(OBJDIR)/iup_maskmatch.o: iup_maskmatch.c iup_maskparse.h iup_maskmatch.h +$(OBJDIR)/iup_mask.o: iup_mask.c iup_maskparse.h iup_mask.h iup_str.h +$(OBJDIR)/iup_maskparse.o: iup_maskparse.c iup_maskparse.h iup_maskmatch.h +$(OBJDIR)/iup_tabs.o: iup_tabs.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_image.h iup_tabs.h +$(OBJDIR)/iup_spin.o: iup_spin.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h \ + iup_childtree.h +$(OBJDIR)/iup_list.o: iup_list.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_assert.h iup_object.h \ + iup_class.h iup_table.h iup_classbase.h iup_attrib.h iup_str.h \ + iup_drv.h iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_mask.h \ + iup_list.h +$(OBJDIR)/iup_getparam.o: iup_getparam.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_attrib.h iup_str.h iup_strmessage.h \ + iup_drvfont.h +$(OBJDIR)/iup_sbox.o: iup_sbox.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_stdcontrols.h iup_layout.h iup_childtree.h +$(OBJDIR)/iup_normalizer.o: iup_normalizer.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_attrib.h iup_str.h iup_array.h iup_stdcontrols.h +$(OBJDIR)/iup_tree.o: iup_tree.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_tree.h iup_assert.h +$(OBJDIR)/iupmot_common.o: mot/iupmot_common.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_childtree.h iup_key.h iup_str.h \ + iup_class.h iup_attrib.h iup_focus.h iup_drv.h iup_image.h \ + mot/iupmot_color.h mot/iupmot_drv.h +$(OBJDIR)/iupmot_color.o: mot/iupmot_color.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_attrib.h iup_str.h iup_drvinfo.h mot/iupmot_drv.h \ + mot/iupmot_color.h +$(OBJDIR)/iupmot_focus.o: mot/iupmot_focus.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_focus.h iup_attrib.h iup_assert.h iup_drv.h \ + mot/iupmot_drv.h +$(OBJDIR)/iupmot_font.o: mot/iupmot_font.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_str.h iup_attrib.h iup_array.h iup_object.h \ + iup_class.h iup_table.h iup_classbase.h iup_drv.h iup_drvfont.h \ + iup_assert.h mot/iupmot_drv.h +$(OBJDIR)/iupmot_key.o: mot/iupmot_key.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_key.h iup_str.h mot/iupmot_drv.h +$(OBJDIR)/iupmot_loop.o: mot/iupmot_loop.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h mot/iupmot_drv.h +$(OBJDIR)/iupmot_open.o: mot/iupmot_open.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_str.h iup_drv.h iup_globalattrib.h mot/iupmot_drv.h \ + mot/iupmot_color.h +$(OBJDIR)/iupmot_tips.o: mot/iupmot_tips.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_attrib.h iup_str.h iup_drv.h iup_drvfont.h \ + mot/iupmot_drv.h mot/iupmot_color.h +$(OBJDIR)/iupmot_globalattrib.o: mot/iupmot_globalattrib.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h iup_str.h iup_drv.h \ + iup_drvinfo.h iup_strmessage.h mot/iupmot_drv.h +$(OBJDIR)/iupmot_dialog.o: mot/iupmot_dialog.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_class.h iup_table.h \ + iup_classbase.h iup_object.h iup_class.h iup_childtree.h iup_dlglist.h \ + iup_attrib.h iup_drv.h iup_drvfont.h iup_drvinfo.h iup_focus.h \ + iup_str.h iup_dialog.h iup_image.h mot/iupmot_drv.h mot/iupmot_color.h +$(OBJDIR)/iupmot_messagedlg.o: mot/iupmot_messagedlg.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drvinfo.h \ + iup_dialog.h iup_strmessage.h mot/iupmot_drv.h +$(OBJDIR)/iupmot_timer.o: mot/iupmot_timer.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_assert.h \ + iup_timer.h mot/iupmot_drv.h +$(OBJDIR)/iupmot_image.o: mot/iupmot_image.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_attrib.h iup_str.h iup_image.h iup_drvinfo.h \ + mot/iupmot_drv.h mot/iupmot_color.h +$(OBJDIR)/iupmot_label.o: mot/iupmot_label.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \ + iup_str.h iup_label.h iup_drv.h iup_image.h mot/iupmot_drv.h +$(OBJDIR)/iupmot_canvas.o: mot/iupmot_canvas.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \ + iup_str.h iup_drv.h iup_drvfont.h iup_canvas.h iup_key.h \ + mot/iupmot_drv.h mot/iupmot_color.h +$(OBJDIR)/iupmot_colordlg.o: mot/iupmot_colordlg.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drvinfo.h \ + iup_dialog.h mot/iupmot_drv.h +$(OBJDIR)/iupmot_fontdlg.o: mot/iupmot_fontdlg.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drvinfo.h \ + iup_dialog.h mot/iupmot_drv.h +$(OBJDIR)/iupmot_filedlg.o: mot/iupmot_filedlg.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h ../include/iupcbs.h \ + iup_object.h iup_class.h iup_table.h iup_classbase.h iup_attrib.h \ + iup_str.h iup_drvinfo.h iup_dialog.h iup_strmessage.h mot/iupmot_drv.h +$(OBJDIR)/iupmot_frame.o: mot/iupmot_frame.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_childtree.h iup_attrib.h iup_str.h iup_dialog.h \ + iup_image.h iup_drv.h iup_drvfont.h iup_stdcontrols.h mot/iupmot_drv.h \ + mot/iupmot_color.h +$(OBJDIR)/iupmot_button.o: mot/iupmot_button.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \ + iup_str.h iup_button.h iup_drv.h iup_image.h iup_key.h mot/iupmot_drv.h +$(OBJDIR)/iupmot_toggle.o: mot/iupmot_toggle.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \ + iup_str.h iup_toggle.h iup_drv.h iup_image.h iup_key.h mot/iupmot_drv.h \ + mot/iupmot_color.h +$(OBJDIR)/iupmot_progressbar.o: mot/iupmot_progressbar.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h ../include/iupcbs.h \ + iup_object.h iup_class.h iup_table.h iup_classbase.h iup_childtree.h \ + iup_attrib.h iup_dialog.h iup_str.h iup_progressbar.h iup_drv.h \ + mot/iupmot_drv.h mot/iupmot_color.h +$(OBJDIR)/iupmot_clipboard.o: mot/iupmot_clipboard.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_image.h \ + mot/iupmot_drv.h +$(OBJDIR)/iupmot_text.o: mot/iupmot_text.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \ + iup_str.h iup_mask.h iup_drv.h iup_array.h iup_text.h mot/iupmot_drv.h \ + mot/iupmot_color.h +$(OBJDIR)/iupmot_val.o: mot/iupmot_val.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \ + iup_str.h iup_val.h iup_image.h iup_drv.h mot/iupmot_drv.h \ + mot/iupmot_color.h +$(OBJDIR)/iupmot_tabs.o: mot/iupmot_tabs.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_layout.h iup_childtree.h iup_attrib.h \ + iup_str.h iup_dialog.h iup_drv.h iup_drvfont.h iup_stdcontrols.h \ + iup_tabs.h iup_image.h mot/iupmot_drv.h mot/iupmot_color.h +$(OBJDIR)/iupmot_menu.o: mot/iupmot_menu.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \ + iup_str.h iup_label.h iup_drv.h iup_drvfont.h iup_image.h iup_menu.h \ + mot/iupmot_drv.h mot/iupmot_color.h +$(OBJDIR)/iupmot_list.o: mot/iupmot_list.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \ + iup_str.h iup_drv.h iup_mask.h iup_key.h iup_list.h mot/iupmot_drv.h \ + mot/iupmot_color.h +$(OBJDIR)/iupmot_tree.o: mot/iupmot_tree.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_childtree.h iup_dialog.h iup_layout.h \ + iup_attrib.h iup_str.h iup_drv.h iup_drvinfo.h iup_drvfont.h \ + iup_stdcontrols.h iup_key.h iup_image.h iup_array.h iup_tree.h \ + mot/iupmot_drv.h mot/iupmot_color.h +$(OBJDIR)/iupunix_help.o: mot/iupunix_help.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_str.h +$(OBJDIR)/iupunix_info.o: mot/iupunix_info.c iup_str.h iup_drvinfo.h diff --git a/iup/src/iup_array.c b/iup/src/iup_array.c new file mode 100755 index 0000000..e7d4e12 --- /dev/null +++ b/iup/src/iup_array.c @@ -0,0 +1,108 @@ +/** \file + * \brief Simple expandable array + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> + +#include "iup_array.h" +#include "iup_assert.h" + + +struct _Iarray +{ + void* data; + int count; + int max_count; + int elem_size; + int start_count; +}; + +Iarray* iupArrayCreate(int start_count, int elem_size) +{ + Iarray* iarray = (Iarray*)malloc(sizeof(Iarray)); + iarray->count = 0; + iarray->elem_size = elem_size; + iarray->max_count = start_count; + iarray->start_count = start_count; + iarray->data = malloc(elem_size*start_count); + iupASSERT(iarray->data!=NULL); + if (!iarray->data) + { + free(iarray); + return NULL; + } + memset(iarray->data, 0, elem_size*start_count); + return iarray; +} + +void iupArrayDestroy(Iarray* iarray) +{ + iupASSERT(iarray!=NULL); + if (!iarray) + return; + if (iarray->data) + { + memset(iarray->data, 0, iarray->elem_size*iarray->max_count); + free(iarray->data); + } + free(iarray); +} + +void* iupArrayGetData(Iarray* iarray) +{ + iupASSERT(iarray!=NULL); + if (!iarray) + return NULL; + return iarray->data; +} + +void* iupArrayInc(Iarray* iarray) +{ + iupASSERT(iarray!=NULL); + if (!iarray) + return NULL; + if (iarray->count >= iarray->max_count) + { + int old_count = iarray->max_count; + iarray->max_count += iarray->start_count; + iarray->data = realloc(iarray->data, iarray->elem_size*iarray->max_count); + iupASSERT(iarray->data!=NULL); + if (!iarray->data) + return NULL; + memset((unsigned char*)iarray->data + iarray->elem_size*old_count, 0, iarray->elem_size*(iarray->max_count-old_count)); + } + iarray->count++; + return iarray->data; +} + +void* iupArrayAdd(Iarray* iarray, int new_count) +{ + iupASSERT(iarray!=NULL); + if (!iarray) + return NULL; + if (iarray->count+new_count > iarray->max_count) + { + int old_count = iarray->max_count; + iarray->max_count += new_count; + iarray->data = realloc(iarray->data, iarray->elem_size*iarray->max_count); + iupASSERT(iarray->data!=NULL); + if (!iarray->data) + return NULL; + memset((unsigned char*)iarray->data + iarray->elem_size*old_count, 0, iarray->elem_size*(iarray->max_count-old_count)); + } + iarray->count += new_count; + return iarray->data; +} + +int iupArrayCount(Iarray* iarray) +{ + iupASSERT(iarray!=NULL); + if (!iarray) + return 0; + return iarray->count; +} diff --git a/iup/src/iup_array.h b/iup/src/iup_array.h new file mode 100755 index 0000000..b44e862 --- /dev/null +++ b/iup/src/iup_array.h @@ -0,0 +1,63 @@ +/** \file + * \brief Simple expandable array + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_ARRAY_H +#define __IUP_ARRAY_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** \defgroup iarray Simple Array + * \par + * Expandable array using a simple pointer. + * \par + * See \ref iup_array.h + * \ingroup util */ + +typedef struct _Iarray Iarray; + +/** Creates an array with an initial room for elements, and the element size. + * The array count starts at 0. And the maximum number of elements starts at the given count. + * The maximum number of elements is increased by the start count, every time it needs more memory. + * Must call \ref iupArrayInc to proper allocates memory. + * \ingroup iarray */ +Iarray* iupArrayCreate(int start_count, int elem_size); + +/** Destroys the array. + * \ingroup iarray */ +void iupArrayDestroy(Iarray* iarray); + +/** Returns the pointer that contains the array. + * \ingroup iarray */ +void* iupArrayGetData(Iarray* iarray); + +/** Increments the number of elements in the array. + * The array count starts at 0. + * If the maximum number of elements is reached, the memory allocated is increased by the initial start count. + * Returns the pointer that contains the array. + * \ingroup iarray */ +void* iupArrayInc(Iarray* iarray); + +/** Increments the number of elements in the array by a given count. + * The array count starts at 0. + * If the maximum number of elements is reached, the memory allocated is increased by the given count. + * Returns the pointer that contains the array. + * \ingroup iarray */ +void* iupArrayAdd(Iarray* iarray, int new_count); + +/** Returns the actual number of elements in the array. + * \ingroup iarray */ +int iupArrayCount(Iarray* iarray); + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_assert.c b/iup/src/iup_assert.c new file mode 100755 index 0000000..11de909 --- /dev/null +++ b/iup/src/iup_assert.c @@ -0,0 +1,54 @@ +/** \file + * \brief String Utilities + * + * See Copyright Notice in "iup.h" + */ + + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <limits.h> +#include <stdarg.h> + +#include "iup.h" + +#include "iup_assert.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_strmessage.h" + +/* from iup_open, but it is not exported, used only here */ +int iupIsOpened(void); + +void iupError(const char* format, ...) +{ + static char msg[SHRT_MAX]; + va_list arglist; + va_start(arglist, format); + vsprintf(msg, format, arglist); + va_end(arglist); +#if IUP_ASSERT_CONSOLE + fprintf(stderr, msg); +#else + if (iupIsOpened()) + iupStrMessageShowError(NULL, msg); + else + fprintf(stderr, msg); +#endif +} + +void iupAssert(const char* expr, const char* file, int line, const char* func) +{ + if (func) + iupError("File: %s\n" + "Line: %d\n" + "Function: %s\n" + "Assertive: (%s)", + file, line, func, expr); + else + iupError("File: %s\n" + "Line: %d\n" + "Assertive: (%s)", + file, line, expr); +} diff --git a/iup/src/iup_assert.h b/iup/src/iup_assert.h new file mode 100755 index 0000000..03cec99 --- /dev/null +++ b/iup/src/iup_assert.h @@ -0,0 +1,68 @@ +/** \file + * \brief Assert Utilities + * + * See Copyright Notice in "iup.h" + */ + + +#ifndef __IUP_ASSERT_H +#define __IUP_ASSERT_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup assert Assert Utilities + * \par + * All functions of the main API (Iup***) calls iupASSERT to check the parameters. + * \par + * The IUP main library must be recompiled with the IUP_ASSERT define to enable these checks. + * iupASSERT is not called inside driver dependent functions nor in each control implementation, + * it is used only in the functions of the main API and in some utilities. + * \par + * See \ref iup_assert.h + * \ingroup util */ + +/* internal functions */ +void iupAssert(const char* expr, const char* file, int line, const char* func); +void iupError(const char* format, ...); + +/** \def iupASSERT + * \brief If the expression if false, + * displays a message with information of the source code where the assert happen. + * + * \param _expr The evaluated expression. + * \par + * It is a macro that calls a function only if IUP_ASSERT is defined. + * \ingroup assert */ + +/** \def iupERROR + * \brief Displays an error message. Also used by the iupASSERT. + * \par + * It is a macro that calls a function only if IUP_ASSERT is defined. + * \ingroup assert */ + +#ifndef IUP_ASSERT +#define iupASSERT(_expr) ((void)0) +#define iupERROR(_msg) ((void)0) +#define iupERROR1(_msg, _p1) ((void)0) +#define iupERROR2(_msg, _p1, _p2) ((void)0) +#else +#ifdef __FUNCTION__ +#define iupASSERT(_expr) ((_expr)? (void)0: iupAssert(#_expr, __FILE__, __LINE__, __FUNCTION__)) +#else +#define iupASSERT(_expr) ((_expr)? (void)0: iupAssert(#_expr, __FILE__, __LINE__, NULL)) +#endif /* __FUNCTION__ */ + +#define iupERROR(_msg) iupError(_msg) +#define iupERROR1(_msg, _p1) iupError(_msg, _p1) +#define iupERROR2(_msg, _p1, _p2) iupError(_msg, _p1, _p2) + +#endif /* IUP_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_attrib.c b/iup/src/iup_attrib.c new file mode 100755 index 0000000..2bbb80a --- /dev/null +++ b/iup/src/iup_attrib.c @@ -0,0 +1,673 @@ +/** \file + * \brief attributes enviroment management + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <limits.h> +#include <stdarg.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_str.h" +#include "iup_ledlex.h" +#include "iup_attrib.h" +#include "iup_assert.h" + + +int IupGetAllAttributes(Ihandle* ih, char** names, int n) +{ + char *name; + int i = 0; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return 0; + + if (!names || !n) + return iupTableCount(ih->attrib); + + name = iupTableFirst(ih->attrib); + while (name) + { + names[i] = name; + i++; + if (i == n) + break; + + name = iupTableNext(ih->attrib); + } + + return i; +} + +char* IupGetAttributes(Ihandle *ih) +{ + char *buffer; + char *name, *value; + char sb[128]; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + buffer = iupStrGetMemory(10240); + buffer[0] = 0; + + name = iupTableFirst(ih->attrib); + while (name) + { + if (!iupAttribIsInternal(name)) + { + if (buffer[0] != 0) + strcat(buffer,","); + + value = iupTableGetCurr(ih->attrib); + if (iupAttribIsPointer(ih, name)) + { + sprintf(sb, "%p", (void*) value); + value = sb; + } + strcat(buffer, name); + strcat(buffer,"=\""); + strcat(buffer, value); + strcat(buffer,"\""); + } + + name = iupTableNext(ih->attrib); + } + + return buffer; +} + +void iupAttribUpdateFromParent(Ihandle* ih) +{ + Iclass* ic = ih->iclass; + char *name = iupTableFirst(ic->attrib_func); + while (name) + { + /* if inheritable and NOT defined at the element */ + if (iupClassObjectCurAttribIsInherit(ic) && !iupAttribGet(ih, name)) + { + /* check in the parent tree if the attribute is defined */ + Ihandle* parent = ih->parent; + while (parent) + { + char* value = iupTableGet(parent->attrib, name); + if (value) + { + int inherit; + /* set on the class */ + iupClassObjectSetAttribute(ih, name, value, &inherit); + break; + } + parent = parent->parent; + } + } + + name = iupTableNext(ic->attrib_func); + } +} + +static void iAttribNotifyChildren(Ihandle *ih, const char* name, const char *value) +{ + int inherit; + Ihandle* child = ih->firstchild; + while (child) + { + if (!iupTableGet(child->attrib, name)) + { + /* set on the class */ + iupClassObjectSetAttribute(child, name, value, &inherit); + + if (inherit) /* inherit can be different for the child */ + iAttribNotifyChildren(child, name, value); + } + + child = child->brother; + } +} + +void iupAttribUpdate(Ihandle* ih) +{ + char** name_array; + char *name, *value; + int count, i = 0, inherit, store; + + count = iupTableCount(ih->attrib); + if (!count) + return; + + name_array = (char**)malloc(count * sizeof(char*)); + + /* store the names before updating so we can add or remove attributes during the update */ + name = iupTableFirst(ih->attrib); + while (name) + { + name_array[i] = name; + name = iupTableNext(ih->attrib); + i++; + } + + /* for all defined attributes updates the native system */ + for (i = 0; i < count; i++) + { + name = name_array[i]; + if (!iupAttribIsInternal(name)) + { + /* retrieve from the table */ + value = iupTableGet(ih->attrib, name); + + /* set on the class */ + store = iupClassObjectSetAttribute(ih, name, value, &inherit); + + if (inherit) + iAttribNotifyChildren(ih, name, value); + + if (store == 0) + iupTableRemove(ih->attrib, name); /* remove from the table acording to the class SetAttribute */ + } + } + + free(name_array); +} + +void IupSetAttribute(Ihandle *ih, const char* name, const char *value) +{ + int inherit; + + iupASSERT(name!=NULL); + if (!name) + return; + + if (!ih) + { + IupSetGlobal(name, value); + return; + } + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + if (iupAttribIsInternal(name)) + iupAttribSetStr(ih, name, value); + else + { + if (iupClassObjectSetAttribute(ih, name, value, &inherit)!=0) /* store strings and pointers */ + iupAttribSetStr(ih, name, value); + + if (inherit) + iAttribNotifyChildren(ih, name, value); + } +} + +void IupStoreAttribute(Ihandle *ih, const char* name, const char *value) +{ + int inherit; + + if (!name) + return; + + if (!ih) + { + IupStoreGlobal(name, value); + return; + } + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + if (iupAttribIsInternal(name)) + iupAttribStoreStr(ih, name, value); + else + { + if (iupClassObjectSetAttribute(ih, name, value, &inherit)==1) /* store only strings */ + iupAttribStoreStr(ih, name, value); + + if (inherit) + iAttribNotifyChildren(ih, name, value); + } +} + +char* IupGetAttribute(Ihandle *ih, const char* name) +{ + int inherit; + char *value, *def_value; + + iupASSERT(name!=NULL); + if (!name) + return NULL; + + if (!ih) + return IupGetGlobal(name); + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + value = iupClassObjectGetAttribute(ih, name, &def_value, &inherit); + if (!value) + value = iupAttribGet(ih, name); + + if (!value && !iupAttribIsInternal(name)) + { + if (inherit) + { + while (!value) + { + ih = ih->parent; + if (!ih) + break; + + value = iupAttribGet(ih, name); + } + } + + if (!value) + value = def_value; + } + + return value; +} + +float IupGetFloat(Ihandle *ih, const char* name) +{ + float f = 0; + char *value = IupGetAttribute(ih, name); + if (value) + iupStrToFloat(value, &f); + return f; +} + +int IupGetInt(Ihandle *ih, const char* name) +{ + int i = 0; + char *value = IupGetAttribute(ih, name); + if (value) + { + if (!iupStrToInt(value, &i)) + { + if (iupStrBoolean(value)) + i = 1; + } + } + return i; +} + +int IupGetInt2(Ihandle *ih, const char* name) +{ + int i1 = 0, i2 = 0; + char *value = IupGetAttribute(ih, name); + if (value) + { + if (!iupStrToIntInt(value, &i1, &i2, 'x')) + iupStrToIntInt(value, &i1, &i2, ':'); + } + return i2; +} + +int IupGetIntInt(Ihandle *ih, const char* name, int *i1, int *i2) +{ + int _i1 = 0, _i2 = 0; + char *value = IupGetAttribute(ih, name); + if (value) + { + int count = iupStrToIntInt(value, &_i1, &_i2, 'x'); + if (!count) count = iupStrToIntInt(value, &_i1, &_i2, ':'); + if (i1) *i1 = _i1; + if (i2) *i2 = _i2; + return count; + } + return 0; +} + +void IupSetfAttribute(Ihandle *ih, const char* name, const char* f, ...) +{ + static char value[SHRT_MAX]; + va_list arglist; + va_start(arglist, f); + vsprintf(value, f, arglist); + va_end(arglist); + IupStoreAttribute(ih, name, value); +} + +void iupAttribSetHandleName(Ihandle *ih) +{ + char str_name[100]; + sprintf(str_name, "_IUP_NAME(%p)", ih); + IupSetHandle(str_name, ih); +} + +void IupSetAttributeHandle(Ihandle *ih, const char* name, Ihandle *ih_named) +{ + int inherit; + char* handle_name; + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + iupASSERT(name!=NULL); + if (!name) + return; + + handle_name = IupGetName(ih_named); + if (!handle_name) + { + iupAttribSetHandleName(ih_named); + handle_name = IupGetName(ih_named); + } + + iupClassObjectSetAttribute(ih, name, handle_name, &inherit); + iupAttribStoreStr(ih, name, handle_name); +} + +Ihandle* IupGetAttributeHandle(Ihandle *ih, const char* name) +{ + char* handle_name = iupAttribGetInherit(ih, name); + if (handle_name) + return IupGetHandle(handle_name); + return NULL; +} + +Ihandle* IupSetAtt(const char* handle_name, Ihandle* ih, const char* name, ...) +{ + const char *attr, *val; + va_list arg; + va_start (arg, name); + attr = name; + while (attr) + { + val = va_arg(arg, const char*); + IupSetAttribute(ih, attr, val); + attr = va_arg(arg, const char*); + } + va_end(arg); + if (handle_name) IupSetHandle(handle_name, ih); + return ih; +} + +void iupAttribSetStr(Ihandle* ih, const char* name, const char* value) +{ + if (!value) + iupTableRemove(ih->attrib, name); + else + iupTableSet(ih->attrib, name, (void*)value, IUPTABLE_POINTER); +} + +void iupAttribStoreStr(Ihandle* ih, const char* name, const char* value) +{ + if (!value) + iupTableRemove(ih->attrib, name); + else + iupTableSet(ih->attrib, name, (void*)value, IUPTABLE_STRING); +} + +void iupAttribSetStrf(Ihandle *ih, const char* name, const char* f, ...) +{ + static char value[SHRT_MAX]; + va_list arglist; + va_start(arglist, f); + vsprintf(value, f, arglist); + va_end(arglist); + iupAttribStoreStr(ih, name, value); +} + +void iupAttribSetInt(Ihandle *ih, const char* name, int num) +{ + iupAttribSetStrf(ih, name, "%d", num); +} + +void iupAttribSetFloat(Ihandle *ih, const char* name, float num) +{ + iupAttribSetStrf(ih, name, "%f", (double)num); +} + +int iupAttribGetBoolean(Ihandle* ih, const char* name) +{ + char *value = iupAttribGetStr(ih, name); + if (value) + { + if (iupStrBoolean(value)) + return 1; + } + return 0; +} + +int iupAttribGetInt(Ihandle* ih, const char* name) +{ + int i = 0; + char *value = iupAttribGetStr(ih, name); + if (value) + { + if (!iupStrToInt(value, &i)) + { + if (iupStrBoolean(value)) + i = 1; + } + } + return i; +} + +float iupAttribGetFloat(Ihandle* ih, const char* name) +{ + float f = 0; + char *value = iupAttribGetStr(ih, name); + if (value) + iupStrToFloat(value, &f); + return f; +} + +char* iupAttribGet(Ihandle* ih, const char* name) +{ + if (!ih || !name) + return NULL; + return iupTableGet(ih->attrib, name); +} + +char* iupAttribGetStr(Ihandle* ih, const char* name) +{ + char* value; + if (!ih || !name) + return NULL; + + value = iupTableGet(ih->attrib, name); + + if (!value && !iupAttribIsInternal(name)) + { + int inherit; + char *def_value; + iupClassObjectGetAttributeInfo(ih, name, &def_value, &inherit); + + if (inherit) + { + while (!value) + { + ih = ih->parent; + if (!ih) + break; + + value = iupAttribGet(ih, name); + } + } + + if (!value) + value = def_value; + } + + return value; +} + +char* iupAttribGetInherit(Ihandle* ih, const char* name) +{ + char* value; + if (!ih || !name) + return NULL; + + value = iupAttribGet(ih, name); /* Check on the element first */ + while (!value) + { + ih = ih->parent; /* iheritance here independs on the attribute */ + if (!ih) + return NULL; + + value = iupAttribGet(ih, name); + } + return value; +} + +char* iupAttribGetInheritNativeParent(Ihandle* ih, const char* name) +{ + char* value; + if (!ih || !name) + return NULL; + + value = NULL; /* Do NOT check on the element first */ + while (!value) + { + ih = iupChildTreeGetNativeParent(ih); + if (!ih) + return NULL; + + value = iupAttribGet(ih, name); + } + + return value; +} + +static const char* env_str = NULL; +static void iAttribCapture(char* env_buffer, char* dlm) +{ + int i=0; + int c; + do + { + c = *env_str; ++env_str; + if (i < 256) + env_buffer[i++] = (char) c; + } while (c && !strchr(dlm,c)); + env_buffer[i-1]='\0'; /* discard delimiter */ +} + +static int iAttribToken(char* env_buffer) +{ + for (;;) + { + int c = *env_str; ++env_str; + switch (c) + { + case 0: + return IUPLEX_TK_END; + + case ' ': /* ignore whitespace */ + case '\t': + case '\n': + case '\r': + case '\f': + case '\v': + continue; + + case '=': /* attribuicao */ + return IUPLEX_TK_SET; + + case ',': + return IUPLEX_TK_COMMA; + + case '\"': /* string */ + iAttribCapture(env_buffer, "\""); + return IUPLEX_TK_NAME; + + default: + if (c > 32) /* identifier */ + { + --env_str; /* unget first character of env_buffer */ + iAttribCapture(env_buffer, "=, \t\n\r\f\v"); /* get env_buffer until delimiter */ + --env_str; /* unget delimiter */ + return IUPLEX_TK_NAME; + } + } + } +} + +static void iAttribParse(Ihandle *ih, const char* str) +{ + char env_buffer[256]; + char* name=NULL; + char* value=NULL; + char state = 'a'; /* get attribute */ + int end = 0; + + env_str = str; + + for (;;) + { + switch (iAttribToken(env_buffer)) + { + case IUPLEX_TK_END: /* procedimento igual ao IUPLEX_TK_COMMA */ + end = 1; + case IUPLEX_TK_COMMA: + if (name) + { + IupStoreAttribute(ih, name, value); + free(name); + } + if (end) + return; + name = value = NULL; + state = 'a'; + break; + + case IUPLEX_TK_SET: + state = 'v'; /* get value */ + break; + + case IUPLEX_TK_NAME: + if (state == 'a') + name = iupStrDup(env_buffer); + else + value = env_buffer; + break; + } + } +} + +Ihandle* IupSetAttributes(Ihandle *ih, const char* str) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return ih; + if (str) + iAttribParse(ih, str); + return ih; +} + +int iupAttribIsPointer(Ihandle* ih, const char* name) +{ + return iupClassObjectAttribIsNotString(ih, name); +} + +typedef int (*Iconvertxytopos)(Ihandle* ih, int x, int y); + +int IupConvertXYToPos(Ihandle* ih, int x, int y) +{ + Iconvertxytopos drvConvertXYToPos; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return -1; + + if (!ih->handle) + return -1; + + drvConvertXYToPos = (Iconvertxytopos)IupGetCallback(ih, "_IUP_XY2POS_CB"); + if (drvConvertXYToPos) + return drvConvertXYToPos(ih, x, y); + + return -1; +} diff --git a/iup/src/iup_attrib.h b/iup/src/iup_attrib.h new file mode 100755 index 0000000..993dd3c --- /dev/null +++ b/iup/src/iup_attrib.h @@ -0,0 +1,137 @@ +/** \file + * \brief Attributes Environment Management + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_ATTRIB_H +#define __IUP_ATTRIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup attrib Attribute Environment + * \par + * When attributes are not stored at the control + * they are stored in a hash table (see \ref table). + * \par + * As a general rule use: + * - IupGetAttribute, IupSetAttribute, ... : when care about control implementation, hash table, inheritance and default value + * - iupAttribGetStr,Int,Float: when care about inheritance, hash table and default value + * - iupAttribGet,... : ONLY access the hash table + * These different functions have very different performances and results. So use them wiselly. + * \par + * See \ref iup_attrib.h + * \ingroup cpi */ + + +/** Returns true if the attribute name if in the internal format "_IUP...". + * \ingroup attrib */ +#define iupAttribIsInternal(_name) ((_name[0] == '_' && _name[1] == 'I' && _name[2] == 'U' && _name[3] == 'P')? 1: 0) + +/** Returns true if the attribute name is a known pointer. + * \ingroup attrib */ +int iupAttribIsPointer(Ihandle* ih, const char *name); + +/** Sets the attribute only in the hash table as a pointer. + * It ignores children. + * \ingroup attrib */ +void iupAttribSetStr(Ihandle* ih, const char* name, const char* value); + +/** Sets the attribute only in the hash table as a string. + * The string is internally duplicated. + * It ignores children. + * \ingroup attrib */ +void iupAttribStoreStr(Ihandle* ih, const char* name, const char* value); + +/** Sets the attribute only in the hash table as a string. + * The string is internally duplicated. Use same format as sprintf. + * It ignores children. + * \ingroup attrib */ +void iupAttribSetStrf(Ihandle *ih, const char* name, const char* format, ...); + +/** Sets an integer attribute only in the hash table. + * It will be stored as a string. + * It ignores children. + * \ingroup attrib */ +void iupAttribSetInt(Ihandle *ih, const char* name, int num); + +/** Sets an floating point attribute only in the hash table. + * It will be stored as a string. + * It ignores children. + * \ingroup attrib */ +void iupAttribSetFloat(Ihandle *ih, const char* name, float num); + +/** Returns the attribute from the hash table only. + * \ingroup attrib */ +char* iupAttribGet(Ihandle* ih, const char* name); + +/** Returns the attribute from the hash table only, + * but if not defined then checks in its parent tree. + * \ingroup attrib */ +char* iupAttribGetInherit(Ihandle* ih, const char* name); + +/** Returns the attribute from the hash table of a native parent. + * Don't check for default values. Don't check at the element. + * Used for BGCOLOR and BACKGROUND attributes. + * \ingroup attrib */ +char* iupAttribGetInheritNativeParent(Ihandle* ih, const char* name); + +/** Returns the attribute from the hash table as a string, + * but if not defined then checks in its parent tree if allowed by the control implementation, + * if still not defined then returns the registered default value if any. + * \ingroup attrib */ +char* iupAttribGetStr(Ihandle* ih, const char* name); + +/** Same as \ref iupAttribGetStr but returns an integer number. + * Checks also for boolean values. + * \ingroup attrib */ +int iupAttribGetInt(Ihandle* ih, const char* name); + +/** Same as \ref iupAttribGetStr but checks for boolean values. + * Use \ref iupStrBoolean. + * \ingroup attrib */ +int iupAttribGetBoolean(Ihandle* ih, const char* name); + +/** Same as \ref iupAttribGetStr but returns an floating point number. + * \ingroup attrib */ +float iupAttribGetFloat(Ihandle* ih, const char* name); + +/** Set an internal name to a handle. + * \ingroup attrib */ +void iupAttribSetHandleName(Ihandle *ih); + + +/* For all attributes in the evironment, call the class SetAttribute only. + * Called only after the element is mapped. */ +void iupAttribUpdate(Ihandle* ih); + +/* For all registered inherited attributes, checks the parent tree and + * call the class SetAttribute if the attribute is defined. + * Called only after the element is mapped. */ +void iupAttribUpdateFromParent(Ihandle* ih); + + + +/* Other functions declared in <iup.h> and implemented here. +IupGetAllAttributes +IupGetAttributes +IupSetAttributes +IupSetAttribute +IupStoreAttribute +IupGetAttribute +IupGetFloat +IupGetInt +IupGetInt2 +IupSetfAttribute +IupSetAttributeHandle +IupGetAttributeHandle +*/ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_box.c b/iup/src/iup_box.c new file mode 100755 index 0000000..54e56d9 --- /dev/null +++ b/iup/src/iup_box.c @@ -0,0 +1,238 @@ +/** \file + * \brief Base for box Controls. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" +#include "iup_box.h" + + +static int iBoxCreateMethod(Ihandle* ih, void** params) +{ + ih->data = iupALLOCCTRLDATA(); + + if (params) + { + Ihandle** iparams = (Ihandle**)params; + while (*iparams) + { + IupAppend(ih, *iparams); + iparams++; + } + } + + return IUP_NOERROR; +} + +static char* iBoxGetClientSizeAttrib(Ihandle* ih) +{ + char* str; + int width, height; + + if (ih->handle) + { + width = ih->currentwidth; + height = ih->currentheight; + } + else + { + width = ih->userwidth; + height = ih->userheight; + } + + if (!width && !height) + return NULL; + + str = iupStrGetMemory(50); + + width -= 2*ih->data->margin_x; + height -= 2*ih->data->margin_y; + + sprintf(str, "%dx%d", width, height); + return str; +} + +static int iBoxSetCGapAttrib(Ihandle* ih, const char* value) +{ + int cgap; + iupStrToInt(value, &cgap); + if (iupStrEqual(ih->iclass->name, "vbox")) + { + int charheight; + iupdrvFontGetCharSize(ih, NULL, &charheight); + ih->data->gap = iupHEIGHT2RASTER(cgap, charheight); + } + else + { + int charwidth; + iupdrvFontGetCharSize(ih, &charwidth, NULL); + ih->data->gap = iupWIDTH2RASTER(cgap, charwidth); + } + return 0; +} + +static char* iBoxGetCGapAttrib(Ihandle* ih) +{ + char *str = iupStrGetMemory(50); + if (iupStrEqual(ih->iclass->name, "vbox")) + { + int charheight; + iupdrvFontGetCharSize(ih, NULL, &charheight); + sprintf(str, "%d", iupRASTER2HEIGHT(ih->data->gap, charheight)); + } + else + { + int charwidth; + iupdrvFontGetCharSize(ih, &charwidth, NULL); + sprintf(str, "%d", iupRASTER2WIDTH(ih->data->gap, charwidth)); + } + return str; +} + +static int iBoxSetGapAttrib(Ihandle* ih, const char* value) +{ + iupStrToInt(value, &ih->data->gap); + return 0; +} + +static char* iBoxGetGapAttrib(Ihandle* ih) +{ + char *str = iupStrGetMemory(50); + sprintf(str, "%d", ih->data->gap); + return str; +} + +static int iBoxSetHomogeneousAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + ih->data->is_homogeneous = 1; + else + ih->data->is_homogeneous = 0; + return 0; +} + +static char* iBoxGetHomogeneousAttrib(Ihandle* ih) +{ + if (ih->data->is_homogeneous) + return "YES"; + else + return "NO"; +} + +static int iBoxSetExpandChildrenAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + { + if (iupStrEqual(ih->iclass->name, "vbox")) + ih->data->expand_children = IUP_EXPAND_WIDTH; /* in vert. box, expand horizontally */ + else + ih->data->expand_children = IUP_EXPAND_HEIGHT; /* in horiz. box, expand vertically */ + } + else + ih->data->expand_children = 0; + return 0; +} + +static char* iBoxGetExpandChildrenAttrib(Ihandle* ih) +{ + if (ih->data->expand_children) + return "YES"; + else + return "NO"; +} + +static int iBoxSetNormalizeSizeAttrib(Ihandle* ih, const char* value) +{ + ih->data->normalize_size = iupNormalizeGetNormalizeSize(value); + return 0; +} + +static char* iBoxGetNormalizeSizeAttrib(Ihandle* ih) +{ + return iupNormalizeGetNormalizeSizeStr(ih->data->normalize_size); +} + +static int iBoxSetCMarginAttrib(Ihandle* ih, const char* value) +{ + int cmargin_x=-1, cmargin_y=-1; + int charwidth, charheight; + iupdrvFontGetCharSize(ih, &charwidth, &charheight); + iupStrToIntInt(value, &cmargin_x, &cmargin_y, 'x'); + if (cmargin_x!=-1) + ih->data->margin_x = iupHEIGHT2RASTER(cmargin_x, charheight); + if (cmargin_y!=-1) + ih->data->margin_x = iupWIDTH2RASTER(cmargin_y, charwidth); + return 0; +} + +static char* iBoxGetCMarginAttrib(Ihandle* ih) +{ + char *str = iupStrGetMemory(50); + int charwidth, charheight; + iupdrvFontGetCharSize(ih, &charwidth, &charheight); + sprintf(str, "%dx%d", iupRASTER2WIDTH(ih->data->margin_x, charwidth), iupRASTER2HEIGHT(ih->data->margin_y, charheight)); + return str; +} + +static int iBoxSetMarginAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->margin_x, &ih->data->margin_y, 'x'); + return 0; +} + +static char* iBoxGetMarginAttrib(Ihandle* ih) +{ + char *str = iupStrGetMemory(50); + sprintf(str, "%dx%d", ih->data->margin_x, ih->data->margin_y); + return str; +} + + +/******************************************************************************/ + + +Iclass* iupBoxClassBase(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->format = "g"; /* array of Ihandle */ + ic->nativetype = IUP_TYPEVOID; + ic->childtype = IUP_CHILDMANY; + ic->is_interactive = 0; + + /* Class functions */ + ic->Create = iBoxCreateMethod; + ic->Map = iupBaseTypeVoidMapMethod; + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Base Container */ + iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CLIENTSIZE", iBoxGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* boxes only */ + iupClassRegisterAttribute(ic, "GAP", iBoxGetGapAttrib, iBoxSetGapAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "CGAP", iBoxGetCGapAttrib, iBoxSetCGapAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "MARGIN", iBoxGetMarginAttrib, iBoxSetMarginAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "CMARGIN", iBoxGetCMarginAttrib, iBoxSetCMarginAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + + iupClassRegisterAttribute(ic, "EXPANDCHILDREN", iBoxGetExpandChildrenAttrib, iBoxSetExpandChildrenAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "HOMOGENEOUS", iBoxGetHomogeneousAttrib, iBoxSetHomogeneousAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NORMALIZESIZE", iBoxGetNormalizeSizeAttrib, iBoxSetNormalizeSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} diff --git a/iup/src/iup_box.h b/iup/src/iup_box.h new file mode 100755 index 0000000..5d79263 --- /dev/null +++ b/iup/src/iup_box.h @@ -0,0 +1,40 @@ +/** \file + * \brief Base for box Controls. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_BOX_H +#define __IUP_BOX_H + +#ifdef __cplusplus +extern "C" { +#endif + + +struct _IcontrolData +{ + int alignment, + expand_children, + is_homogeneous, + normalize_size, + margin_x, + margin_y, + gap; + int children_naturalsize, /* calculated in ComputeNaturalSize, used in SetChildrenCurrentSize */ + homogeneous_size; /* calculated in SetChildrenCurrentSize, used in SetChildrenPosition */ +}; + +Iclass* iupBoxClassBase(void); + +/* Implemented in iup_normalizer.c */ +void iupNormalizeSizeBoxChild(Ihandle *ih, int normalize, int children_natural_maxwidth, int children_natural_maxheight); +int iupNormalizeGetNormalizeSize(const char* value); +char* iupNormalizeGetNormalizeSizeStr(int normalize); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_button.c b/iup/src/iup_button.c new file mode 100755 index 0000000..7719663 --- /dev/null +++ b/iup/src/iup_button.c @@ -0,0 +1,206 @@ +/** \file + * \brief Button Control. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" +#include "iup_button.h" +#include "iup_image.h" + + +char* iupButtonGetPaddingAttrib(Ihandle* ih) +{ + char *str = iupStrGetMemory(50); + sprintf(str, "%dx%d", ih->data->horiz_padding, ih->data->vert_padding); + return str; +} + +static int iButtonSetImagePositionAttrib(Ihandle* ih, const char* value) +{ + if (!ih->handle) /* set only before map */ + { + if (iupStrEqualNoCase(value, "RIGHT")) + ih->data->img_position = IUP_IMGPOS_RIGHT; + else if (iupStrEqualNoCase(value, "BOTTOM")) + ih->data->img_position = IUP_IMGPOS_BOTTOM; + else if (iupStrEqualNoCase(value, "TOP")) + ih->data->img_position = IUP_IMGPOS_TOP; + else /* "LEFT" */ + ih->data->img_position = IUP_IMGPOS_LEFT; + } + return 0; +} + +static char* iButtonGetImagePositionAttrib(Ihandle *ih) +{ + char* img_pos2str[4] = {"LEFT", "RIGHT", "TOP", "BOTTOM"}; + char *str = iupStrGetMemory(50); + sprintf(str, "%s", img_pos2str[ih->data->img_position]); + return str; +} + +static int iButtonSetSpacingAttrib(Ihandle* ih, const char* value) +{ + if (!ih->handle) /* set only before map */ + iupStrToInt(value, &ih->data->spacing); + return 0; +} + +static char* iButtonGetSpacingAttrib(Ihandle *ih) +{ + char *str = iupStrGetMemory(50); + sprintf(str, "%d", ih->data->spacing); + return str; +} + + +/*****************************************************************************************/ + + +static int iButtonCreateMethod(Ihandle* ih, void** params) +{ + if (params) + { + if (params[0]) iupAttribStoreStr(ih, "TITLE", (char*)(params[0])); + if (params[1]) iupAttribStoreStr(ih, "ACTION", (char*)(params[1])); + } + ih->data = iupALLOCCTRLDATA(); + + ih->data->spacing = 2; + + /* used only by the Windows driver */ + ih->data->horiz_alignment = IUP_ALIGN_ACENTER; + ih->data->vert_alignment = IUP_ALIGN_ACENTER; + return IUP_NOERROR; +} + +static void iButtonComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + int natural_w = 0, + natural_h = 0, + type = ih->data->type; + (void)expand; /* unset if not a container */ + + if (!ih->handle) + { + /* if not mapped must initialize the internal values */ + char* value = iupAttribGet(ih, "IMAGE"); + if (value) + { + type = IUP_BUTTON_IMAGE; + if (iupAttribGet(ih, "TITLE")) + type |= IUP_BUTTON_TEXT; + } + else + type = IUP_BUTTON_TEXT; + } + + if (type & IUP_BUTTON_IMAGE) + { + iupImageGetInfo(iupAttribGet(ih, "IMAGE"), &natural_w, &natural_h, NULL); + + if (type & IUP_BUTTON_TEXT) + { + int text_w, text_h; + /* must use IupGetAttribute to check from the native implementation */ + char* title = IupGetAttribute(ih, "TITLE"); + iupdrvFontGetMultiLineStringSize(ih, title, &text_w, &text_h); + + if (ih->data->img_position == IUP_IMGPOS_RIGHT || + ih->data->img_position == IUP_IMGPOS_LEFT) + { + natural_w += text_w + ih->data->spacing; + natural_h = iupMAX(natural_h, text_h); + } + else + { + natural_w = iupMAX(natural_w, text_w); + natural_h += text_h + ih->data->spacing; + } + } + } + else /* IUP_BUTTON_TEXT only */ + { + /* must use IupGetAttribute to check from the native implementation */ + char* title = IupGetAttribute(ih, "TITLE"); + char* str = iupStrProcessMnemonic(title, NULL, 0); /* remove & */ + iupdrvFontGetMultiLineStringSize(ih, str, &natural_w, &natural_h); + if (str && str!=title) free(str); + } + + /* even when IMPRESS is set, must compute the borders space */ + iupdrvButtonAddBorders(&natural_w, &natural_h); + + natural_w += 2*ih->data->horiz_padding; + natural_h += 2*ih->data->vert_padding; + + *w = natural_w; + *h = natural_h; +} + + +/******************************************************************************/ + + +Ihandle* IupButton(const char* title, const char* action) +{ + void *params[3]; + params[0] = (void*)title; + params[1] = (void*)action; + params[2] = NULL; + return IupCreatev("button", params); +} + +Iclass* iupButtonGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "button"; + ic->format = "SA"; /* one optional string, and one optional callback name */ + ic->nativetype = IUP_TYPECONTROL; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + + /* Class functions */ + ic->Create = iButtonCreateMethod; + ic->ComputeNaturalSize = iButtonComputeNaturalSizeMethod; + + ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Callbacks */ + iupClassRegisterCallback(ic, "BUTTON_CB", "iiiis"); + iupClassRegisterCallback(ic, "ACTION", ""); + + /* Common Callbacks */ + iupBaseRegisterCommonCallbacks(ic); + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Visual */ + iupBaseRegisterVisualAttrib(ic); + + /* IupButton only */ + iupClassRegisterAttribute(ic, "SPACING", iButtonGetSpacingAttrib, iButtonSetSpacingAttrib, IUPAF_SAMEASSYSTEM, "2", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGEPOSITION", iButtonGetImagePositionAttrib, iButtonSetImagePositionAttrib, IUPAF_SAMEASSYSTEM, "LEFT", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMPRESSBORDER", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FLAT", NULL, NULL, NULL, NULL, IUPAF_DEFAULT); + + iupdrvButtonInitClass(ic); + + return ic; +} diff --git a/iup/src/iup_button.h b/iup/src/iup_button.h new file mode 100755 index 0000000..f85720a --- /dev/null +++ b/iup/src/iup_button.h @@ -0,0 +1,39 @@ +/** \file + * \brief Button Controls Private Declarations + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_BUTTON_H +#define __IUP_BUTTON_H + +#ifdef __cplusplus +extern "C" { +#endif + + +void iupdrvButtonInitClass(Iclass* ic); +void iupdrvButtonAddBorders(int *x, int *y); + +char* iupButtonGetPaddingAttrib(Ihandle* ih); + +enum{IUP_BUTTON_IMAGE=0x01, IUP_BUTTON_TEXT=0x02, IUP_BUTTON_BOTH=0x03}; +enum{IUP_IMGPOS_LEFT, IUP_IMGPOS_RIGHT, IUP_IMGPOS_TOP, IUP_IMGPOS_BOTTOM}; + +struct _IcontrolData +{ + int type, /* the 2 buttons possibilities */ + horiz_padding, vert_padding; /* button margin */ + int spacing, img_position; /* used when both text and image are displayed */ + + /* used only by the Windows driver */ + int horiz_alignment, vert_alignment; + unsigned long fgcolor; +}; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_callback.c b/iup/src/iup_callback.c new file mode 100755 index 0000000..e000287 --- /dev/null +++ b/iup/src/iup_callback.c @@ -0,0 +1,90 @@ +/** \file + * \brief get/set callback + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdarg.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_assert.h" + + +Icallback IupGetCallback(Ihandle *ih, const char *name) +{ + Icallback func = NULL; + void* value; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + iupASSERT(name!=NULL); + if (!name) + return NULL; + + func = (Icallback)iupTableGetFunc(ih->attrib, name, &value); + + if (!func && value) + { + /* if not a IUPTABLE_FUNCPOINTER then it is an old fashion name */ + func = IupGetFunction((const char*)value); + } + + return func; +} + +Icallback IupSetCallback(Ihandle *ih, const char *name, Icallback func) +{ + Icallback old_func = NULL; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + iupASSERT(name!=NULL); + if (!name) + return NULL; + + if (!func) + iupTableRemove(ih->attrib, name); + else + { + void* value; + old_func = (Icallback)iupTableGetFunc(ih->attrib, name, &value); + if (!old_func && value) + old_func = IupGetFunction((const char*)value); + + iupTableSetFunc(ih->attrib, name, (Ifunc)func); + } + + return old_func; +} + +Ihandle* IupSetCallbacks(Ihandle* ih, const char *name, Icallback func, ...) +{ + va_list arglist; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + IupSetCallback(ih, name, func); + + va_start(arglist, func); + + name=va_arg(arglist, const char*); + while (name) + { + func=va_arg(arglist, Icallback); + IupSetCallback(ih, name, func); + + name=va_arg(arglist, const char*); + } + + va_end (arglist); + return ih; +} diff --git a/iup/src/iup_canvas.c b/iup/src/iup_canvas.c new file mode 100755 index 0000000..5eda988 --- /dev/null +++ b/iup/src/iup_canvas.c @@ -0,0 +1,169 @@ +/** \file + * \brief Canvas Control. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" +#include "iup_canvas.h" + + +void iupCanvasCalcScrollIntPos(double min, double max, double page, double pos, + int imin, int imax, int *ipage, int *ipos) +{ + double range = max-min; + int irange = imax-imin; + double ratio = ((double)irange)/range; + + *ipage = (int)(page*ratio); + if (*ipage > irange) *ipage = irange; + if (*ipage < 1) *ipage = 1; + + if (ipos) + { + *ipos = (int)((pos-min)*ratio) + imin; + if (*ipos < imin) *ipos = imin; + if (*ipos > (imax - *ipage)) *ipos = imax - *ipage; + } +} + +void iupCanvasCalcScrollRealPos(double min, double max, double *pos, + int imin, int imax, int ipage, int *ipos) +{ + double range = max-min; + int irange = imax-imin; + double ratio = ((double)irange)/range; + + if (*ipos < imin) *ipos = imin; + if (*ipos > (imax - ipage)) *ipos = imax - ipage; + + *pos = min + ((double)(*ipos-imin))/ratio; +} + +char* iupCanvasGetPosXAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(20); + sprintf(str, "%f", ih->data->posx); + return str; +} + +char* iupCanvasGetPosYAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(20); + sprintf(str, "%f", ih->data->posy); + return str; +} + +static int iCanvasCreateMethod(Ihandle* ih, void** params) +{ + if (params && params[0]) + { + char* action = (char*)params[0]; + iupAttribStoreStr(ih, "ACTION", action); + } + + ih->data = iupALLOCCTRLDATA(); + + /* default EXPAND is YES */ + ih->expand = IUP_EXPAND_BOTH; + + return IUP_NOERROR; +} + +static void iCanvasComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + int natural_w = 0, natural_h = 0; + (void)expand; /* unset if not a container */ + + /* canvas natural size is 1 character */ + iupdrvFontGetCharSize(ih, &natural_w, &natural_h); + + *w = natural_w; + *h = natural_h; +} + + +/******************************************************************************/ + + +Ihandle* IupCanvas(const char* action) +{ + void *params[2]; + params[0] = (void*)action; + params[1] = NULL; + return IupCreatev("canvas", params); +} + +Iclass* iupCanvasGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "canvas"; + ic->format = "A"; /* one optional callback name */ + ic->nativetype = IUP_TYPECANVAS; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + + /* Class functions */ + ic->Create = iCanvasCreateMethod; + ic->ComputeNaturalSize = iCanvasComputeNaturalSizeMethod; + + ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Callbacks */ + iupClassRegisterCallback(ic, "DROPFILES_CB", "siii"); + iupClassRegisterCallback(ic, "RESIZE_CB", "ii"); + iupClassRegisterCallback(ic, "FOCUS_CB", "i"); + iupClassRegisterCallback(ic, "WOM_CB", "i"); + iupClassRegisterCallback(ic, "BUTTON_CB", "iiiis"); + iupClassRegisterCallback(ic, "MOTION_CB", "iis"); + iupClassRegisterCallback(ic, "KEYPRESS_CB", "ii"); + iupClassRegisterCallback(ic, "ACTION", "ff"); + iupClassRegisterCallback(ic, "SCROLL_CB", "iff"); + iupClassRegisterCallback(ic, "WHEEL_CB", "fiis"); + + /* Common Callbacks */ + iupBaseRegisterCommonCallbacks(ic); + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + { + /* Change the default to YES */ + IattribGetFunc _get; + IattribSetFunc _set; + iupClassRegisterGetAttribute(ic, "EXPAND", &_get, &_set, NULL, NULL, NULL); + iupClassRegisterAttribute(ic, "EXPAND", _get, _set, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + } + + /* Visual */ + iupBaseRegisterVisualAttrib(ic); + + /* IupCanvas only */ + iupClassRegisterAttribute(ic, "CURSOR", NULL, iupdrvBaseSetCursorAttrib, IUPAF_SAMEASSYSTEM, "ARROW", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "XMIN", NULL, NULL, IUPAF_SAMEASSYSTEM, "0.0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "XMAX", NULL, NULL, IUPAF_SAMEASSYSTEM, "1.0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "YMIN", NULL, NULL, IUPAF_SAMEASSYSTEM, "0.0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "YMAX", NULL, NULL, IUPAF_SAMEASSYSTEM, "1.0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "LINEX", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "LINEY", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "BORDER", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "SCROLLBAR", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + + iupdrvCanvasInitClass(ic); + + return ic; +} diff --git a/iup/src/iup_canvas.h b/iup/src/iup_canvas.h new file mode 100755 index 0000000..29d644c --- /dev/null +++ b/iup/src/iup_canvas.h @@ -0,0 +1,37 @@ +/** \file + * \brief Canvas Controls Private Declarations + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_CANVAS_H +#define __IUP_CANVAS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +void iupdrvCanvasInitClass(Iclass* ic); +void iupCanvasCalcScrollIntPos(double min, double max, double page, double pos, + int imin, int imax, int *ipage, int *ipos); +void iupCanvasCalcScrollRealPos(double min, double max, double *pos, + int imin, int imax, int ipage, int *ipos); +char* iupCanvasGetPosXAttrib(Ihandle* ih); +char* iupCanvasGetPosYAttrib(Ihandle* ih); + +#define IUP_SB_MIN 0 +#define IUP_SB_MAX INT_MAX-1 + +struct _IcontrolData +{ + int sb; /* scrollbar configuration, valid only after map, use iupBaseGetScrollbar before map */ + float posx, posy; +}; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_cbox.c b/iup/src/iup_cbox.c new file mode 100755 index 0000000..5a1d409 --- /dev/null +++ b/iup/src/iup_cbox.c @@ -0,0 +1,143 @@ +/** \file + * \brief cbox control + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" + + +static int iCboxCreateMethod(Ihandle* ih, void** params) +{ + if (params) + { + Ihandle** iparams = (Ihandle**)params; + while (*iparams) + { + IupAppend(ih, *iparams); + iparams++; + } + } + + return IUP_NOERROR; +} + +static void iCboxComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + Ihandle* child; + int children_expand, + children_naturalwidth, children_naturalheight; + int cx, cy; + + /* calculate total children natural size (even for hidden children) */ + children_expand = 0; + children_naturalwidth = 0; + children_naturalheight = 0; + + for (child = ih->firstchild; child; child = child->brother) + { + /* update child natural size first */ + iupBaseComputeNaturalSize(child); + + cx = iupAttribGetInt(child, "CX"); + cy = iupAttribGetInt(child, "CY"); + + children_expand |= child->expand; + children_naturalwidth = iupMAX(children_naturalwidth, cx+child->naturalwidth); + children_naturalheight = iupMAX(children_naturalheight, cy+child->naturalheight); + } + + *expand = children_expand; + *w = children_naturalwidth; + *h = children_naturalheight; +} + +static void iCboxSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink) +{ + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + { + /* update children to their own natural size */ + iupBaseSetCurrentSize(child, child->naturalwidth, child->naturalheight, shrink); + } +} + +static void iCboxSetChildrenPositionMethod(Ihandle* ih, int x, int y) +{ + int cx, cy; + Ihandle* child; + + for (child = ih->firstchild; child; child = child->brother) + { + cx = iupAttribGetInt(child, "CX"); + cy = iupAttribGetInt(child, "CY"); + + /* update child */ + iupBaseSetPosition(child, x+cx, y+cy); + } +} + + +/******************************************************************************/ + + +Ihandle *IupCboxv(Ihandle** children) +{ + return IupCreatev("cbox", (void**)children); +} + +Ihandle *IupCbox (Ihandle * child,...) +{ + Ihandle **children; + Ihandle *ih; + + va_list arglist; + va_start(arglist, child); + children = (Ihandle **)iupObjectGetParamList(child, arglist); + va_end(arglist); + + ih = IupCreatev("cbox", (void**)children); + free(children); + + return ih; +} + +Iclass* iupCboxGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "cbox"; + ic->format = "g"; /* array of Ihandle */ + ic->nativetype = IUP_TYPEVOID; + ic->childtype = IUP_CHILDMANY; + ic->is_interactive = 0; + + /* Class functions */ + ic->Create = iCboxCreateMethod; + ic->Map = iupBaseTypeVoidMapMethod; + + ic->ComputeNaturalSize = iCboxComputeNaturalSizeMethod; + ic->SetChildrenCurrentSize = iCboxSetChildrenCurrentSizeMethod; + ic->SetChildrenPosition = iCboxSetChildrenPositionMethod; + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Base Container */ + iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CLIENTSIZE", iupBaseGetRasterSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} diff --git a/iup/src/iup_childtree.c b/iup/src/iup_childtree.c new file mode 100755 index 0000000..1d4066e --- /dev/null +++ b/iup/src/iup_childtree.c @@ -0,0 +1,455 @@ +/** \file + * \brief Control tree hierarchy manager. + * implements also IupDestroy + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_dlglist.h" +#include "iup_childtree.h" +#include "iup_class.h" +#include "iup_attrib.h" +#include "iup_assert.h" +#include "iup_str.h" +#include "iup_drv.h" + + +Ihandle* IupGetDialog(Ihandle* ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + for (ih = ih; ih->parent; ih = ih->parent) + ; /* empty*/ + + if (ih->iclass->nativetype == IUP_TYPEDIALOG) + return ih; + else if (ih->iclass->nativetype == IUP_TYPEMENU) + { + Ihandle *dlg; + /* if ih is a menu then */ + /* searches all the dialogs that may have been associated with the menu. */ + for (dlg = iupDlgListFirst(); dlg; dlg = iupDlgListNext()) + { + if (IupGetAttributeHandle(dlg, "MENU") == ih) + return dlg; + } + } + + return NULL; +} + +static void iChildDetach(Ihandle* parent, Ihandle* child) +{ + Ihandle *c, + *c_prev = NULL; + + /* Cleans the child entry inside the parent's child list */ + for (c = parent->firstchild; c; c = c->brother) + { + if (c == child) /* Found the right child */ + { + if (c_prev == NULL) + parent->firstchild = child->brother; + else + c_prev->brother = child->brother; + + child->brother = NULL; + child->parent = NULL; + return; + } + + c_prev = c; + } +} + +void IupDetach(Ihandle *child) +{ + Ihandle *parent, *top_parent; + + iupASSERT(iupObjectCheck(child)); + if (!iupObjectCheck(child)) + return; + + IupUnmap(child); + + /* Not valid if does NOT has a parent */ + if (!child->parent) + return; + + parent = child->parent; + top_parent = iupChildTreeGetNativeParent(child); + + iChildDetach(parent, child); + iupClassObjectChildRemoved(parent, child); + + while (parent && parent != top_parent) + { + parent = parent->parent; + if (parent) + iupClassObjectChildRemoved(parent, child); + } +} + +static int iChildFindRec(Ihandle* parent, Ihandle* child) +{ + Ihandle *c; + + /* Finds the reference child entry inside the parent's child list */ + for (c = parent->firstchild; c; c = c->brother) + { + if (c == child) /* Found the right child */ + return 1; + + if (iChildFindRec(c, child)) + return 1; + } + + return 0; +} + +static int iChildTreeCheckInside(Ihandle* parent, Ihandle* child) +{ + /* top parent */ + while (parent->parent) + parent = parent->parent; + + return iChildFindRec(parent, child); +} + +static int iChildFind(Ihandle* parent, Ihandle* child) +{ + Ihandle *c; + + /* Finds the reference child entry inside the parent's child list */ + for (c = parent->firstchild; c; c = c->brother) + { + if (c == child) /* Found the right child */ + return 1; + } + + return 0; +} + +static void iChildInsert(Ihandle* parent, Ihandle* ref_child, Ihandle* child) +{ + Ihandle *c, + *c_prev = NULL; + + if (!ref_child) + ref_child = parent->firstchild; + + /* Finds the reference child entry inside the parent's child list */ + for (c = parent->firstchild; c; c = c->brother) + { + if (c == ref_child) /* Found the right child */ + { + child->parent = parent; + child->brother = ref_child; + + if (c_prev == NULL) + parent->firstchild = child; + else + c_prev->brother = child; + return; + } + + c_prev = c; + } +} + +Ihandle* IupInsert(Ihandle* parent, Ihandle* ref_child, Ihandle* child) +{ + Ihandle* top_parent = parent; + + /* ref_child can be NULL */ + + iupASSERT(iupObjectCheck(parent)); + if (!iupObjectCheck(parent)) + return NULL; + + iupASSERT(iupObjectCheck(child)); + if (!iupObjectCheck(child)) + return NULL; + +#ifdef IUP_ASSERT + if (iChildTreeCheckInside(parent, child)) + { + iupError("Duplicate Child Found!\n(type(%s) - name(%s))", child->iclass->name, IupGetName(child)); + return NULL; + } +#endif + + + /* this will return the actual parent */ + parent = iupClassObjectGetInnerContainer(top_parent); + if (!parent) + return NULL; + + if (parent->iclass->childtype == IUP_CHILDNONE) + return NULL; + if (parent->iclass->childtype == IUP_CHILD_ONE && parent->firstchild) + return NULL; + + + /* if already at the parent box, allow to move even if mapped */ + if (parent->iclass->nativetype == IUP_TYPEVOID && + iChildFind(parent, child)) + { + iChildDetach(parent, child); + iChildInsert(parent, ref_child, child); + } + else + { + /* Not valid if it is mapped */ + if (child->handle) + return NULL; + + iChildInsert(parent, ref_child, child); + iupClassObjectChildAdded(parent, child); + if (top_parent != parent) + iupClassObjectChildAdded(top_parent, child); + } + + return parent; +} + +void iupChildTreeAppend(Ihandle* parent, Ihandle* child) +{ + child->parent = parent; + + if (parent->firstchild == NULL) + parent->firstchild = child; + else + { + Ihandle* c = parent->firstchild; + while (c->brother) + c = c->brother; + c->brother = child; + } +} + +Ihandle* IupAppend(Ihandle* parent, Ihandle* child) +{ + Ihandle* top_parent = parent; + + iupASSERT(iupObjectCheck(parent)); + if (!iupObjectCheck(parent)) + return NULL; + + iupASSERT(iupObjectCheck(child)); + if (!iupObjectCheck(child)) + return NULL; + +#ifdef IUP_ASSERT + if (iChildTreeCheckInside(parent, child)) + { + iupError("Duplicate Child Found!\n(type(%s) - name(%s))", child->iclass->name, IupGetName(child)); + return NULL; + } +#endif + + + /* this will return the actual parent */ + parent = iupClassObjectGetInnerContainer(top_parent); + if (!parent) + return NULL; + + if (parent->iclass->childtype == IUP_CHILDNONE) + return NULL; + if (parent->iclass->childtype == IUP_CHILD_ONE && parent->firstchild) + return NULL; + + + /* if already at the parent box, allow to move even if mapped */ + if (parent->iclass->nativetype == IUP_TYPEVOID && + iChildFind(parent, child)) + { + iChildDetach(parent, child); + iupChildTreeAppend(parent, child); + } + else + { + /* Not valid if it is mapped */ + if (child->handle) + return NULL; + + iupChildTreeAppend(parent, child); + iupClassObjectChildAdded(parent, child); + if (top_parent != parent) + iupClassObjectChildAdded(top_parent, child); + } + + return parent; +} + +static void iChildReparent(Ihandle* child, Ihandle* new_parent) +{ + Ihandle *c; + + /* Forward the reparent to all native children */ + + for (c = child->firstchild; c; c = c->brother) + { + if (c->iclass->nativetype != IUP_TYPEVOID) + iupdrvReparent(c); + else + iChildReparent(c, new_parent); + } +} + +int IupReparent(Ihandle* child, Ihandle* parent) +{ + Ihandle* top_parent = parent; + Ihandle* old_parent; + + iupASSERT(iupObjectCheck(parent)); + if (!iupObjectCheck(parent)) + return IUP_ERROR; + + iupASSERT(iupObjectCheck(child)); + if (!iupObjectCheck(child)) + return IUP_ERROR; + + + /* this will return the actual parent */ + parent = iupClassObjectGetInnerContainer(top_parent); + if (!parent) + return IUP_ERROR; + + if (parent->iclass->childtype == IUP_CHILDNONE) + return IUP_ERROR; + if (parent->iclass->childtype == IUP_CHILD_ONE && parent->firstchild) + return IUP_ERROR; + + + /* both must be already mapped or both unmapped */ + if ((!parent->handle && child->handle) || + ( parent->handle && !child->handle)) + return IUP_ERROR; + + + /* detach from old parent */ + old_parent = child->parent; + iChildDetach(old_parent, child); + iupClassObjectChildRemoved(old_parent, child); + + + /* attach to new parent */ + iupChildTreeAppend(parent, child); + iupClassObjectChildAdded(parent, child); + if (top_parent != parent) + iupClassObjectChildAdded(top_parent, child); + + + /* no need to remap, just notify the native system */ + if (child->handle && parent->handle) + { + if (child->iclass->nativetype != IUP_TYPEVOID) + iupdrvReparent(child); + else + iChildReparent(child, parent); + } + + return IUP_NOERROR; +} + +Ihandle* IupGetChild(Ihandle* ih, int pos) +{ + int p; + Ihandle* child; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + for (p = 0, child = ih->firstchild; child; child = child->brother, p++) + { + if (p == pos) + return child; + } + + return NULL; +} + +int IupGetChildPos(Ihandle* ih, Ihandle* child) +{ + int pos; + Ihandle* c; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return -1; + + for (pos = 0, c = ih->firstchild; c; c = c->brother, pos++) + { + if (c == child) + return pos; + } + return -1; +} + +int IupGetChildCount(Ihandle* ih) +{ + int count = 0; + Ihandle* child; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return -1; + + for (child = ih->firstchild; child; child = child->brother) + count++; + + return count; +} + +Ihandle* IupGetNextChild(Ihandle* ih, Ihandle* child) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + if (!child) + return ih->firstchild; + else + return child->brother; +} + +Ihandle* IupGetBrother(Ihandle* ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + return ih->brother; +} + +Ihandle* IupGetParent(Ihandle *ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + return ih->parent; +} + +Ihandle* iupChildTreeGetNativeParent(Ihandle* ih) +{ + Ihandle* parent = ih->parent; + while (parent && parent->iclass->nativetype == IUP_TYPEVOID) + parent = parent->parent; + return parent; +} + +InativeHandle* iupChildTreeGetNativeParentHandle(Ihandle* ih) +{ + Ihandle* native_parent = iupChildTreeGetNativeParent(ih); + return (InativeHandle*)iupClassObjectGetInnerNativeContainerHandle(native_parent, ih); +} diff --git a/iup/src/iup_childtree.h b/iup/src/iup_childtree.h new file mode 100755 index 0000000..4376c0b --- /dev/null +++ b/iup/src/iup_childtree.h @@ -0,0 +1,54 @@ +/** \file + * \brief Control Hierarchy Tree management. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_CHILDTREE_H +#define __IUP_CHILDTREE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup childtree Child Tree Utilities + * \par + * Some native containers have an internal native child that + * will be the actual container of the children. This native container is + * returned by \ref iupClassObjectGetInnerNativeContainerHandle. + * \par + * Some native elements need an extra parent, the ih->handle points to the main element itself, + * NOT to the extra parent. This extra parent is stored as "_IUP_EXTRAPARENT". + * \par + * See \ref iup_childtree.h + * \ingroup object */ + +/** Returns the native parent. It simply excludes containers that are from IUP_TYPEVOID classes. + * \ingroup childtree */ +Ihandle* iupChildTreeGetNativeParent(Ihandle* ih); + +/** Returns the native parent handle. Uses \ref iupChildTreeGetNativeParent and \ref iupClassObjectGetInnerNativeContainerHandle. + * \ingroup childtree */ +InativeHandle* iupChildTreeGetNativeParentHandle(Ihandle* ih); + +/** Adds the child directly to the parent tree. + * \ingroup childtree */ +void iupChildTreeAppend(Ihandle* parent, Ihandle* child); + + +/* Other functions declared in <iup.h> and implemented here. +IupGetDialog +IupDetach +IupAppend +IupGetChild +IupGetNextChild +IupGetBrother +IupGetParent +*/ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_class.c b/iup/src/iup_class.c new file mode 100755 index 0000000..d2c4b02 --- /dev/null +++ b/iup/src/iup_class.c @@ -0,0 +1,314 @@ +/** \file + * \brief IUP Ihandle Class C Interface + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_str.h" +#include "iup_attrib.h" +#include "iup_assert.h" + + + +/***************************************************************** + Method Stubs +*****************************************************************/ + +static int iClassCreate(Iclass* ic, Ihandle* ih, void** params) +{ + int ret = IUP_NOERROR; + if (ic->parent) + ret = iClassCreate(ic->parent, ih, params); + + if (ret == IUP_NOERROR && ic->Create) + ret = ic->Create(ih, params); + + return ret; +} + +static int iClassMap(Iclass* ic, Ihandle* ih) +{ + int ret = IUP_NOERROR; + if (ic->parent) + ret = iClassMap(ic->parent, ih); + + if (ret == IUP_NOERROR && ic->Map) + ret = ic->Map(ih); + + return ret; +} + +static void iClassUnMap(Iclass* ic, Ihandle* ih) +{ + /* must be before the parent class */ + if (ic->UnMap) + ic->UnMap(ih); + + if (ic->parent) + iClassUnMap(ic->parent, ih); +} + +static void iClassDestroy(Iclass* ic, Ihandle* ih) +{ + /* must destroy child class before the parent class */ + if (ic->Destroy) + ic->Destroy(ih); + + if (ic->parent) + iClassDestroy(ic->parent, ih); +} + +static void iClassComputeNaturalSize(Iclass* ic, Ihandle* ih, int *w, int *h, int *expand) +{ + if (ic->parent) + iClassComputeNaturalSize(ic->parent, ih, w, h, expand); + + if (ic->ComputeNaturalSize) + ic->ComputeNaturalSize(ih, w, h, expand); +} + +static void iClassSetChildrenCurrentSize(Iclass* ic, Ihandle* ih, int shrink) +{ + if (ic->parent) + iClassSetChildrenCurrentSize(ic->parent, ih, shrink); + + if (ic->SetChildrenCurrentSize) + ic->SetChildrenCurrentSize(ih, shrink); +} + +static void iClassSetChildrenPosition(Iclass* ic, Ihandle* ih, int x, int y) +{ + if (ic->parent) + iClassSetChildrenPosition(ic->parent, ih, x, y); + + if (ic->SetChildrenPosition) + ic->SetChildrenPosition(ih, x, y); +} + +static Ihandle* iClassGetInnerContainer(Iclass* ic, Ihandle* ih) +{ + Ihandle* ih_container = ih; + + if (ic->parent) + ih_container = iClassGetInnerContainer(ic->parent, ih); + + /* if the class implements the function it will ignore the result of the parent class */ + + if (ic->GetInnerContainer) + ih_container = ic->GetInnerContainer(ih); + + return ih_container; +} + +static void* iClassGetInnerNativeContainerHandle(Iclass* ic, Ihandle* ih, Ihandle* child) +{ + void* container_handle = ih->handle; + + if (ic->parent) + container_handle = iClassGetInnerNativeContainerHandle(ic->parent, ih, child); + + /* if the class implements the function it will ignore the result of the parent class */ + + if (ic->GetInnerNativeContainerHandle) + container_handle = ic->GetInnerNativeContainerHandle(ih, child); + + return container_handle; +} + +static void iClassObjectChildAdded(Iclass* ic, Ihandle* ih, Ihandle* child) +{ + if (ic->parent) + iClassObjectChildAdded(ic->parent, ih, child); + + if (ic->ChildAdded) + ic->ChildAdded(ih, child); +} + +static void iClassObjectChildRemoved(Iclass* ic, Ihandle* ih, Ihandle* child) +{ + if (ic->parent) + iClassObjectChildRemoved(ic->parent, ih, child); + + if (ic->ChildRemoved) + ic->ChildRemoved(ih, child); +} + +static void iClassLayoutUpdate(Iclass* ic, Ihandle *ih) +{ + if (ic->parent) + iClassLayoutUpdate(ic->parent, ih); + + if (ic->LayoutUpdate) + ic->LayoutUpdate(ih); +} + +static int iClassDlgPopup(Iclass* ic, Ihandle* ih, int x, int y) +{ + int ret = IUP_INVALID; /* IUP_INVALID means it is not implemented */ + if (ic->parent) + ret = iClassDlgPopup(ic->parent, ih, x, y); + + if (ret != IUP_ERROR && ic->DlgPopup) + ret = ic->DlgPopup(ih, x, y); + + return ret; +} + +int iupClassObjectCreate(Ihandle* ih, void** params) +{ + return iClassCreate(ih->iclass, ih, params); +} + +int iupClassObjectMap(Ihandle* ih) +{ + return iClassMap(ih->iclass, ih); +} + +void iupClassObjectUnMap(Ihandle* ih) +{ + iClassUnMap(ih->iclass, ih); +} + +void iupClassObjectDestroy(Ihandle* ih) +{ + iClassDestroy(ih->iclass, ih); +} + +void iupClassObjectComputeNaturalSize(Ihandle* ih, int *w, int *h, int *expand) +{ + iClassComputeNaturalSize(ih->iclass, ih, w, h, expand); +} + +void iupClassObjectSetChildrenCurrentSize(Ihandle* ih, int shrink) +{ + iClassSetChildrenCurrentSize(ih->iclass, ih, shrink); +} + +void iupClassObjectSetChildrenPosition(Ihandle* ih, int x, int y) +{ + iClassSetChildrenPosition(ih->iclass, ih, x, y); +} + +Ihandle* iupClassObjectGetInnerContainer(Ihandle* ih) +{ + return iClassGetInnerContainer(ih->iclass, ih); +} + +void* iupClassObjectGetInnerNativeContainerHandle(Ihandle* ih, Ihandle* child) +{ + return iClassGetInnerNativeContainerHandle(ih->iclass, ih, child); +} + +void iupClassObjectChildAdded(Ihandle* ih, Ihandle* child) +{ + iClassObjectChildAdded(ih->iclass, ih, child); +} + +void iupClassObjectChildRemoved(Ihandle* ih, Ihandle* child) +{ + iClassObjectChildRemoved(ih->iclass, ih, child); +} + +void iupClassObjectLayoutUpdate(Ihandle *ih) +{ + iClassLayoutUpdate(ih->iclass, ih); +} + +int iupClassObjectDlgPopup(Ihandle* ih, int x, int y) +{ + return iClassDlgPopup(ih->iclass, ih, x, y); +} + + +/***************************************************************** + Class Definition +*****************************************************************/ + + +static void iClassReleaseAttribFuncTable(Iclass* ic) +{ + char* name = iupTableFirst(ic->attrib_func); + while (name) + { + void* afunc = iupTableGetCurr(ic->attrib_func); + free(afunc); + + name = iupTableNext(ic->attrib_func); + } + + iupTableDestroy(ic->attrib_func); +} + +Iclass* iupClassNew(Iclass* parent) +{ + Iclass* ic = malloc(sizeof(Iclass)); + memset(ic, 0, sizeof(Iclass)); + + if (parent) + ic->attrib_func = parent->attrib_func; + else + ic->attrib_func = iupTableCreate(IUPTABLE_STRINGINDEXED); + + ic->parent = parent; + + return ic; +} + +void iupClassRelease(Iclass* ic) +{ + Iclass* parent; + + /* must release only the actual class */ + if (ic->Release) + ic->Release(ic); + + /* must free all classes, since a new instance is created when we inherit */ + parent = ic->parent; + while (parent) + { + Iclass* tmp = parent; + parent = parent->parent; + free(tmp); + } + + /* attributes functions table is released only once */ + iClassReleaseAttribFuncTable(ic); + + free(ic); +} + + +/***************************************************************** + Main API +*****************************************************************/ + + +char* IupGetClassName(Ihandle *ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + return ih->iclass->name; +} + +char* IupGetClassType(Ihandle *ih) +{ + static char* type2str[] = {"void", "control", "canvas", "dialog", "image", "menu"}; + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + return type2str[ih->iclass->nativetype]; +} + diff --git a/iup/src/iup_class.h b/iup/src/iup_class.h new file mode 100755 index 0000000..a5318f3 --- /dev/null +++ b/iup/src/iup_class.h @@ -0,0 +1,414 @@ +/** \file + * \brief Ihandle Class Interface + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_CLASS_H +#define __IUP_CLASS_H + +#include "iup_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup iclass Ihandle Class + * \par + * See \ref iup_class.h + * \ingroup cpi */ + +/** Known native types. + * \ingroup iclass */ +typedef enum _InativeType { + IUP_TYPEVOID, /**< No native representation - HBOX, VBOX, ZBOX, FILL, RADIO (handle==(void*)-1 always) */ + IUP_TYPECONTROL, /**< Native controls - BUTTON, LABEL, TOGGLE, LIST, TEXT, MULTILINE, FRAME, others */ + IUP_TYPECANVAS, /**< Drawing canvas, also used as a base control for custom controls. */ + IUP_TYPEDIALOG, /**< DIALOG */ + IUP_TYPEIMAGE, /**< IMAGE */ + IUP_TYPEMENU /**< MENU, SUBMENU, ITEM, SEPARATOR */ +} InativeType; + +/** Possible number of children. + * \ingroup iclass */ +typedef enum _IchildType { + IUP_CHILDNONE, + IUP_CHILD_ONE, + IUP_CHILDMANY +} IchildType; + +typedef struct Iclass_ Iclass; + +/** Ihandle Class Structure + * \ingroup iclass */ +struct Iclass_ +{ + /* Class configuration parameters. */ + char* name; /**< class name. No default, must be initialized. */ + char* format; /**< Creation parameters format of the class when specified. \n + * It can have none, one or more of the following. + * - "b" = (unsigned char) - byte + * - "c" = (unsigned char*) - array of byte + * - "i" = (int) - integer + * - "j" = (int*) - array of integer + * - "f" = (float) - real + * - "s" = (char*) - string + * - "a" = (char*) - name of an action + * - "h" = (Ihandle*) - element handle + * - "g" = (Ihandle**) - array of element handle + * If upper case then it is optional. Default is no parameters. */ + InativeType nativetype; /**< native type. Default is IUP_TYPEVOID. */ + IchildType childtype; /**< children count enum: none, one, or many. Default is IUP_CHILDNONE. Used only by IupAppend and IupInsert to control the number of children. */ + int is_interactive; /**< keyboard interactive boolean, + * true if the class can have the keyboard input focus. Default is false. */ + int has_attrib_id; /**< boolean to indicate if any attribute is numbered. Default is false. */ + + Iclass* parent; /**< class parent to implement inheritance. + * Class name must be different. + * Creation parameters should be the same or repace the parents creation function. + * Native type should be the same. + * Child type should be a more restrictive or equal type (many->one->none). + * Attribute functions will have only one common table. + * All methods can be changed, set to NULL, switched, etc. */ + + Itable* attrib_func; /**< table of functions to handle attributes, only one per class tree */ + + /* Class methods. */ + + /** Method that release the memory allocated by the class. + * Called only once at \ref iupClassRelease. + */ + void (*Release)(Iclass* ic); + + + + /** Method that creates the element and process the creation parameters. \n + * Called only from IupCreate. \n + * The parameters can be NULL for all the controls. \n + * The control should also depend on attributes set before IupMap. \n + * Must return IUP_NOERROR or IUP_ERROR. \n + * Can be NULL, like all methods. + */ + int (*Create)(Ihandle* ih, void** params); + + /** Method that map (create) the control to the native system. \n + * Called only from IupMap. \n + * Must return IUP_NOERROR or IUP_ERROR. + */ + int (*Map)(Ihandle* ih); + + /** Method that unmap (destroy) the control from the native system. \n + * Called only from IupUnmap if the control is mapped. \n + * Must return IUP_NOERROR or IUP_ERROR. + */ + void (*UnMap)(Ihandle* ih); + + /** Method that destroys the element. \n + * Called only from IupDestroy. Always called even if the control is not mapped. + */ + void (*Destroy)(Ihandle* ih); + + + + /** Returns the actual parent to add a child. The default implementation returns itself. \n + * Called only from IupAppend or IupReparent. \n + * This allows IUP elements to be a combination of other IUP elements in a single IUP element. + */ + Ihandle* (*GetInnerContainer)(Ihandle* ih); + + /** Returns the internal native parent. The default implementation returns the handle of itself. \n + * Called from \ref iupChildTreeGetNativeParentHandle. \n + * This allows native elements to have an internal container + * that will be the actual native parent, or in other words allows native elements to be a combination of + * other native elements in a single IUP element. The actual native parent may depend on the child tree (IupTabs). + */ + void* (*GetInnerNativeContainerHandle)(Ihandle* ih, Ihandle* child); + + /** Notifies the element that a child was appended using IupAppend. \n + * Called only from IupAppend or IupReparent. The child is not mapped, but the parent can be mapped. + */ + void (*ChildAdded)(Ihandle* ih, Ihandle* child); + + /** Notifies the element that a child was removed using IupDetach. \n + * Called only from IupDetach or IupReparent. The child is not mapped, but the parent can be mapped. + */ + void (*ChildRemoved)(Ihandle* ih, Ihandle* child); + + + /** Method that update size and position of the native control. \n + * Called only from iupLayoutUpdate and if the element is mapped. + */ + void (*LayoutUpdate)(Ihandle* ih); + + + + /** Method that computes the natural size based on the user size and the actual natural size. \n + * Should update expand if a container, but does NOT depends on expand to compute the natural size. \n + * Must call the \ref iupBaseComputeNaturalSize for each children. + * First calculate the native size for the children, then for the element. \n + * Also called before the element is mapped, so it must be independent of the native control. + * First call done at iupLayoutCompute for the dialog. + */ + void (*ComputeNaturalSize)(Ihandle* ih, int *w, int *h, int *children_expand); + + /** Method that calculates and updates the current size of children based on the available size, + * the natural size and the expand configuration. \n + * Called only if there is any children.\n + * Must call \ref iupBaseSetCurrentSize for each children. + * shrink is the dialog attribute passed here for optimization. \n + * Also called before the element is mapped, so it must be independent of the native control. + * First call done at iupLayoutCompute for the dialog. + */ + void (*SetChildrenCurrentSize)(Ihandle* ih, int shrink); + + /** Method that calculates and updates the position relative to the parent. \n + * Called only if there is any children.\n + * Must call \ref iupBaseSetPosition for each children. + * Also called before the element is mapped, so it must be independent of the native control. + * First call done at iupLayoutCompute for the dialog. + */ + void (*SetChildrenPosition)(Ihandle* ih, int x, int y); + + + + /** Method that shows a popup dialog. Called only for native pre-defined dialogs. \n + * The element is not mapped. \n + * Must return IUP_ERROR or IUP_NOERROR. \n + * Called only from iupDialogPopup. + */ + int (*DlgPopup)(Ihandle* ih, int x, int y); +}; + + + +/** Allocates memory for the Iclass structure and + * initializes the attribute handling functions table. + * \ingroup iclass */ +Iclass* iupClassNew(Iclass* ic_parent); + +/** Release the memory allocated by the class. + * Calls the \ref Iclass::Release method. \n + * Called from iupRegisterFinish. + * \ingroup iclass */ +void iupClassRelease(Iclass* ic); + + + +/** GetAttribute called for a specific attribute. + * Used by \ref iupClassRegisterAttribute. + * \ingroup iclass */ +typedef char* (*IattribGetFunc)(Ihandle* ih); + +/** GetAttribute called for a specific attribute when has_attrib_id is true. \n + * Same as IattribGetFunc but handle attribute names with number ids at the end. \n + * When calling iupClassRegisterAttribute just use a typecast. \n + * Pure numbers are translated into IDVALUEid. + * Used by \ref iupClassRegisterAttribute. + * \ingroup iclass */ +typedef char* (*IattribGetIdFunc)(Ihandle* ih, const char* name_id); + +/** SetAttribute called for a specific attribute. \n + * If returns 0, the attribute will not be stored in the hash table + * (except inheritble attributes that are always stored in the hash table). \n + * When IupSetAttribute is called using value=NULL, the default_value is passed to this function. + * Used by \ref iupClassRegisterAttribute. + * \ingroup iclass */ +typedef int (*IattribSetFunc)(Ihandle* ih, const char* value); + +/** SetAttribute called for a specific attribute when has_attrib_id is true. \n + * Same as IattribSetFunc but handle attribute names with number ids at the end. \n + * When calling iupClassRegisterAttribute just use a typecast. \n + * Pure numbers are translated into IDVALUEid, ex: "1" = "IDVALUE1". + * Used by \ref iupClassRegisterAttribute. + * \ingroup iclass */ +typedef int (*IattribSetIdFunc)(Ihandle* ih, const char* name_id, const char* value); + +/** Attribute flags. + * Used by \ref iupClassRegisterAttribute. + * \ingroup iclass */ +typedef enum _IattribFlags{ + IUPAF_DEFAULT=0, /**< inheritable, can has a default value, is a string, can call the set/get functions only if mapped, no ID */ + IUPAF_NO_INHERIT=1, /**< is not inheritable */ + IUPAF_NO_DEFAULTVALUE=2, /**< can not has a default value */ + IUPAF_NO_STRING=4, /**< is not a string */ + IUPAF_NOT_MAPPED=8, /**< will call the set/get functions also when not mapped */ + IUPAF_HAS_ID=16, /**< can has an ID at the end of the name, automatically set by \ref iupClassRegisterAttributeId */ + IUPAF_READONLY=32, /**< is read-only, can not be changed */ + IUPAF_WRITEONLY=64 /**< is write-only, usually an action */ +} IattribFlags; + +#define IUPAF_SAMEASSYSTEM ((char*)-1) /**< means that the default value is the same as the system default value, used only in \ref iupClassRegisterAttribute */ + + +/** Register attribute handling functions. get, set and default_value can be NULL. + * default_value should point to a constant string, it will not be duplicated internally. \n + * Notice that when an attribute is not defined then default_value=NULL, + * is inheritable can has a default value and is a string. \n + * Since there is only one attribute function table per class tree, + * if you register the same attribute in a child class, then it will replace the parent registration. \n + * If an attribute is not inheritable or not a string then it MUST be registered. + * Internal attributes (starting with "_IUP") can never be registered. + * \ingroup iclass */ +void iupClassRegisterAttribute(Iclass* ic, const char* name, + IattribGetFunc get, + IattribSetFunc set, + const char* default_value, + const char* system_default, + int flags); + +/** Same as \ref iupClassRegisterAttribute for attributes with Ids. + * \ingroup iclass */ +void iupClassRegisterAttributeId(Iclass* ic, const char* name, + IattribGetIdFunc get, + IattribSetIdFunc set, + int flags); + +/** Returns the attribute handling functions. + * \ingroup iclass */ +void iupClassRegisterGetAttribute(Iclass* ic, const char* name, + IattribGetFunc *get, + IattribSetFunc *set, + const char* *default_value, + const char* *system_default, + int *flags); + +/** Register the parameters of a callback. + * Used by language bindings. + * format follows the format specification of the class creation parameters format, + * but it adds the "double" option and remove array options. + * It can have none, one or more of the following. \n + * - "b" = (unsigned char) - byte + * - "i" = (int) - integer + * - "f" = (float) - real + * - "d" = (double) - real + * - "s" = (char*) - string + * - "v" = (void*) - generic pointer + * - "h" = (Ihandle*) - element handle + * The default return value for all callbacks is "i" (int). + * But the return value can be specified using one of the above parameters, + * after all parameters using "=" to separate it from them. + * \ingroup iclass */ +void iupClassRegisterCallback(Iclass* ic, const char* name, const char* format); + +/** Returns the format of the parameters of a registered callback. + * If NULL then the default callback definition is assumed. + * \ingroup iclass */ +char* iupClassCallbackGetFormat(Iclass* ic, const char* name); + + + +/** \defgroup iclassobject Class Object Functions + * \par + * Stubs for the class methods. They implement inheritance and check if method is NULL. + * \par + * See \ref iup_class.h + * \ingroup iclass + */ + +/** Calls \ref Iclass::Create method. + * \ingroup iclassobject + */ +int iupClassObjectCreate(Ihandle* ih, void** params); + +/** Calls \ref Iclass::Map method. + * \ingroup iclassobject + */ +int iupClassObjectMap(Ihandle* ih); + +/** Calls \ref Iclass::UnMap method. + * \ingroup iclassobject + */ +void iupClassObjectUnMap(Ihandle* ih); + +/** Calls \ref Iclass::Destroy method. + * \ingroup iclassobject + */ +void iupClassObjectDestroy(Ihandle* ih); + +/** Calls \ref Iclass::GetInnerContainer method. + * The parent class is ignored. If necessary the child class must handle the parent class internally. + * \ingroup iclassobject + */ +Ihandle* iupClassObjectGetInnerContainer(Ihandle* ih); + +/** Calls \ref Iclass::GetInnerNativeContainerHandle method. Returns ih->handle if there is no inner parent. + * The parent class is ignored. If necessary the child class must handle the parent class internally. + * \ingroup iclassobject + */ +void* iupClassObjectGetInnerNativeContainerHandle(Ihandle* ih, Ihandle* child); + +/** Calls \ref Iclass::ChildAdded method. + * \ingroup iclassobject + */ +void iupClassObjectChildAdded(Ihandle* ih, Ihandle* child); + +/** Calls \ref Iclass::ChildRemoved method. + * \ingroup iclassobject + */ +void iupClassObjectChildRemoved(Ihandle* ih, Ihandle* child); + +/** Calls \ref Iclass::LayoutUpdate method. + * \ingroup iclassobject + */ +void iupClassObjectLayoutUpdate(Ihandle* ih); + +/** Calls \ref Iclass::ComputeNaturalSize method. + * \ingroup iclassobject + */ +void iupClassObjectComputeNaturalSize(Ihandle* ih, int *w, int *h, int *children_expand); + +/** Calls \ref Iclass::SetChildrenCurrentSize method. + * \ingroup iclassobject + */ +void iupClassObjectSetChildrenCurrentSize(Ihandle* ih, int shrink); + +/** Calls \ref Iclass::SetChildrenPosition method. + * \ingroup iclassobject + */ +void iupClassObjectSetChildrenPosition(Ihandle* ih, int x, int y); + +/** Calls \ref Iclass::DlgPopup method. + * \ingroup iclassobject + */ +int iupClassObjectDlgPopup(Ihandle* ih, int x, int y); + + + +/* Handle attributes, but since the attribute function table is shared by the class hierarchy, + * the attribute function is retrieved only from the current class. + * Set is called from iupAttribUpdate (IupMap), IupStoreAttribute and IupSetAttribute. + * Get is called only from IupGetAttribute. + */ +int iupClassObjectSetAttribute(Ihandle* ih, const char* name, const char* value, int *inherit); +char* iupClassObjectGetAttribute(Ihandle* ih, const char* name, char* *def_value, int *inherit); + +/* Used only in iupAttribGetStr */ +void iupClassObjectGetAttributeInfo(Ihandle* ih, const char* name, char* *def_value, int *inherit); + +/* Used only in iupAttribIsPointer */ +int iupClassObjectAttribIsNotString(Ihandle* ih, const char* name); + +/* Used only in iupAttribUpdateFromParent */ +int iupClassObjectCurAttribIsInherit(Iclass* ic); + +/* Used in iupObjectCreate and IupMap */ +void iupClassObjectEnsureDefaultAttributes(Ihandle* ih); + +/* Used in documentation tests. */ +char* iupClassGetDefaultAttribute(const char* classname, const char *attrib_name); + + +/* Other functions declared in <iup.h> and implemented here. +IupGetClassType +IupGetClassName +*/ + + +#ifdef __cplusplus +} +#endif + +#include "iup_classbase.h" + +#endif diff --git a/iup/src/iup_classattrib.c b/iup/src/iup_classattrib.c new file mode 100755 index 0000000..df8f873 --- /dev/null +++ b/iup/src/iup_classattrib.c @@ -0,0 +1,508 @@ +/** \file + * \brief Ihandle Class Attribute Management + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_str.h" +#include "iup_attrib.h" +#include "iup_assert.h" +#include "iup_register.h" +#include "iup_globalattrib.h" + + +typedef struct _IattribFunc +{ + IattribGetFunc get; + IattribSetFunc set; + const char* default_value; + const char* system_default; + int call_global_default; + int flags; +} IattribFunc; + + +static int iClassIsGlobalDefault(const char* name) +{ + if (iupStrEqual(name, "DEFAULTFONT")) + return 1; + if (iupStrEqual(name, "DLGBGCOLOR")) + return 1; + if (iupStrEqual(name, "DLGFGCOLOR")) + return 1; + if (iupStrEqual(name, "TXTBGCOLOR")) + return 1; + if (iupStrEqual(name, "TXTFGCOLOR")) + return 1; + if (iupStrEqual(name, "MENUBGCOLOR")) + return 1; + return 0; +} + +static const char* iClassFindId(const char* name) +{ + while(*name) + { + if (*name >= '0' && *name <= '9') + return name; + if (*name == '*' || *name == ':') + return name; + + name++; + } + return NULL; +} + +static const char* iClassCutNameId(const char* name, const char* name_id) +{ + char* str; + int len = name_id - name; + if (len == 0) + return NULL; + + str = iupStrGetMemory(len+1); + memcpy(str, name, len); + str[len] = 0; + return str; +} + + +static char* iClassGetDefaultValue(IattribFunc* afunc) +{ + if (afunc->call_global_default) + return IupGetGlobal(afunc->default_value); + else + return (char*)afunc->default_value; +} + +int iupClassObjectSetAttribute(Ihandle* ih, const char* name, const char * value, int *inherit) +{ + IattribFunc* afunc; + + if (ih->iclass->has_attrib_id) + { + const char* name_id = iClassFindId(name); + if (name_id) + { + IattribFunc* afunc; + const char* partial_name = iClassCutNameId(name, name_id); + if (!partial_name) + partial_name = "IDVALUE"; /* pure numbers are used as attributes in IupList and IupMatrix, + translate them into IDVALUE. */ + afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, partial_name); + if (afunc) + { + *inherit = 0; /* id numbered attributes are NON inheritable always */ + + if (afunc->flags & IUPAF_READONLY) + { + if (afunc->flags & IUPAF_NO_STRING) + return -1; /* value is NOT a string, can NOT call iupAttribStoreStr */ + return 0; + } + + if (afunc->set && (ih->handle || afunc->flags & IUPAF_NOT_MAPPED)) + { + /* id numbered attributes have default value NULL always */ + IattribSetIdFunc id_set = (IattribSetIdFunc)afunc->set; + return id_set(ih, name_id, value); + } + + if (afunc->flags & IUPAF_NO_STRING) + return -1; /* value is NOT a string, can NOT call iupAttribStoreStr */ + + return 1; /* if the function exists, then must return here */ + } + } + } + + /* if not has_attrib_id, or not found an ID, or not found the partial name, check using the full name */ + + afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, name); + *inherit = 1; /* default is inheritable */ + if (afunc) + { + *inherit = !(afunc->flags & IUPAF_NO_INHERIT) && !(afunc->flags & IUPAF_NO_STRING); + + if (afunc->flags & IUPAF_READONLY) + { + if (afunc->flags & IUPAF_NO_STRING) + return -1; /* value is NOT a string, can NOT call iupAttribStoreStr */ + return 0; + } + + if (afunc->set && (ih->handle || afunc->flags & IUPAF_NOT_MAPPED)) + { + int ret; + if (!value) + { + /* inheritable attributes when reset must check the parent value */ + if (*inherit && ih->parent) + value = iupAttribGetInherit(ih->parent, name); + + if (!value) + value = iClassGetDefaultValue(afunc); + } + + if (afunc->flags & IUPAF_HAS_ID) + { + IattribSetIdFunc id_set = (IattribSetIdFunc)afunc->set; + return id_set(ih, "", value); /* empty Id */ + } + else + ret = afunc->set(ih, value); + + if (ret == 1 && afunc->flags & IUPAF_NO_STRING) + return -1; /* value is NOT a string, can NOT call iupAttribStoreStr */ + + if (*inherit) + return 1; /* inheritable attributes are always stored in the hash table, */ + else /* to indicate that they are set at the control. */ + return ret; + } + } + + return 1; +} + +char* iupClassObjectGetAttribute(Ihandle* ih, const char* name, char* *def_value, int *inherit) +{ + IattribFunc* afunc; + + if (ih->iclass->has_attrib_id) + { + const char* name_id = iClassFindId(name); + if (name_id) + { + IattribFunc* afunc; + const char* partial_name = iClassCutNameId(name, name_id); + if (!partial_name) + partial_name = "IDVALUE"; /* pure numbers are used as attributes in IupList and IupMatrix, + translate them into IDVALUE. */ + afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, partial_name); + if (afunc) + { + *def_value = NULL; /* id numbered attributes have default value NULL always */ + *inherit = 0; /* id numbered attributes are NON inheritable always */ + + if (afunc->flags & IUPAF_WRITEONLY) + return NULL; + + if (afunc->get && (ih->handle || afunc->flags & IUPAF_NOT_MAPPED)) + { + IattribGetIdFunc id_get = (IattribGetIdFunc)afunc->get; + return id_get(ih, name_id); + } + else + return NULL; /* if the function exists, then must return here */ + } + } + } + + /* if not has_attrib_id, or not found an ID, or not found the partial name, check using the full name */ + + afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, name); + *def_value = NULL; + *inherit = 1; /* default is inheritable */ + if (afunc) + { + *def_value = iClassGetDefaultValue(afunc); + *inherit = !(afunc->flags & IUPAF_NO_INHERIT) && !(afunc->flags & IUPAF_NO_STRING); + + if (afunc->flags & IUPAF_WRITEONLY) + return NULL; + + if (afunc->get && (ih->handle || afunc->flags & IUPAF_NOT_MAPPED)) + { + if (afunc->flags & IUPAF_HAS_ID) + { + IattribGetIdFunc id_get = (IattribGetIdFunc)afunc->get; + return id_get(ih, ""); /* empty Id */ + } + else + return afunc->get(ih); + } + } + return NULL; +} + +void iupClassObjectGetAttributeInfo(Ihandle* ih, const char* name, char* *def_value, int *inherit) +{ + IattribFunc* afunc; + + if (ih->iclass->has_attrib_id) + { + const char* name_id = iClassFindId(name); + if (name_id) + { + IattribFunc* afunc; + const char* partial_name = iClassCutNameId(name, name_id); + if (!partial_name) + partial_name = "IDVALUE"; /* pure numbers are used as attributes in IupList and IupMatrix, + translate them into IDVALUE. */ + afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, partial_name); + if (afunc) + { + *def_value = NULL; /* id numbered attributes have default value NULL always */ + *inherit = 0; /* id numbered attributes are NON inheritable always */ + return; /* if the function exists, then must return here */ + } + } + } + + /* if not has_attrib_id, or not found an ID, or not found the partial name, check using the full name */ + + afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, name); + *def_value = NULL; + *inherit = 1; /* default is inheritable */ + if (afunc) + { + *def_value = iClassGetDefaultValue(afunc); + *inherit = !(afunc->flags & IUPAF_NO_INHERIT) && !(afunc->flags & IUPAF_NO_STRING); + } +} + +int iupClassObjectCurAttribIsInherit(Iclass* ic) +{ + IattribFunc* afunc = (IattribFunc*)iupTableGetCurr(ic->attrib_func); + if (afunc && !(afunc->flags & IUPAF_NO_INHERIT)) + return 1; + return 0; +} + +int iupClassObjectAttribIsNotString(Ihandle* ih, const char* name) +{ + IattribFunc* afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, name); + if (afunc && afunc->flags & IUPAF_NO_STRING) + return 1; + return 0; +} + +void iupClassRegisterAttribute(Iclass* ic, const char* name, + IattribGetFunc _get, IattribSetFunc _set, + const char* _default_value, const char* _system_default, int _flags) +{ + IattribFunc* afunc = (IattribFunc*)iupTableGet(ic->attrib_func, name); + if (afunc) + free(afunc); /* overwrite a previous registration */ + + afunc = (IattribFunc*)malloc(sizeof(IattribFunc)); + afunc->get = _get; + afunc->set = _set; + if (_default_value == IUPAF_SAMEASSYSTEM) + afunc->default_value = _system_default; + else + afunc->default_value = _default_value; + afunc->system_default = _system_default; + afunc->flags = _flags; + + if (iClassIsGlobalDefault(afunc->default_value)) + afunc->call_global_default = 1; + else + afunc->call_global_default = 0; + + iupTableSet(ic->attrib_func, name, (void*)afunc, IUPTABLE_POINTER); +} + +void iupClassRegisterAttributeId(Iclass* ic, const char* name, + IattribGetIdFunc _get, IattribSetIdFunc _set, + int _flags) +{ + IattribFunc* afunc = (IattribFunc*)iupTableGet(ic->attrib_func, name); + if (afunc) + free(afunc); /* overwrite a previous registration */ + + afunc = (IattribFunc*)malloc(sizeof(IattribFunc)); + afunc->get = (IattribGetFunc)_get; + afunc->set = (IattribSetFunc)_set; + afunc->default_value = NULL; + afunc->system_default = NULL; + afunc->flags = _flags|IUPAF_HAS_ID|IUPAF_NO_INHERIT|IUPAF_NO_DEFAULTVALUE; + afunc->call_global_default = 0; + + iupTableSet(ic->attrib_func, name, (void*)afunc, IUPTABLE_POINTER); +} + +void iupClassRegisterGetAttribute(Iclass* ic, const char* name, + IattribGetFunc *_get, IattribSetFunc *_set, + const char* *_default_value, const char* *_system_default, int *_flags) +{ + IattribFunc* afunc = (IattribFunc*)iupTableGet(ic->attrib_func, name); + if (afunc) + { + if (_get) *_get = afunc->get; + if (_set) *_set = afunc->set; + if (_default_value) *_default_value = afunc->default_value; + if (_system_default) *_system_default = afunc->system_default; + if (_flags) *_flags = afunc->flags; + } +} + +void iupClassRegisterCallback(Iclass* ic, const char* name, const char* format) +{ + /* Since attributes and callbacks do not conflict + we can use the same structure to store the callback format using the default_value. */ + iupClassRegisterAttribute(ic, name, NULL, NULL, format, NULL, IUPAF_NO_INHERIT); +} + +char* iupClassCallbackGetFormat(Iclass* ic, const char* name) +{ + IattribFunc* afunc = (IattribFunc*)iupTableGet(ic->attrib_func, name); + if (afunc) + return (char*)afunc->default_value; + return NULL; +} + +int IupGetClassAttributes(const char* classname, char** names, int n) +{ + Iclass* ic; + int i = 0; + char* name; + + iupASSERT(classname!=NULL); + if (!classname) + return 0; + + ic = iupRegisterFindClass(classname); + if (!ic) + return -1; + + if (!names || !n) + return iupTableCount(ic->attrib_func); + + name = iupTableFirst(ic->attrib_func); + while (name) + { + names[i] = name; + i++; + if (i == n) + break; + + name = iupTableNext(ic->attrib_func); + } + + return i; +} + +void IupSetClassDefaultAttribute(const char* classname, const char *name, const char* default_value) +{ + Iclass* ic; + IattribFunc* afunc; + + iupASSERT(classname!=NULL); + if (!classname) + return; + + iupASSERT(name!=NULL); + if (!name) + return; + + ic = iupRegisterFindClass(name); + if (!ic) + return; + + afunc = (IattribFunc*)iupTableGet(ic->attrib_func, name); + if (afunc && (!(afunc->flags & IUPAF_NO_DEFAULTVALUE) || !(afunc->flags & IUPAF_NO_STRING) || !(afunc->flags & IUPAF_HAS_ID))) + { + if (default_value == IUPAF_SAMEASSYSTEM) + afunc->default_value = afunc->system_default; + else + afunc->default_value = default_value; + + if (iClassIsGlobalDefault(afunc->default_value)) + afunc->call_global_default = 1; + else + afunc->call_global_default = 0; + } + else if (default_value) + iupClassRegisterAttribute(ic, name, NULL, NULL, default_value, NULL, IUPAF_DEFAULT); +} + +void IupSaveClassAttributes(Ihandle* ih) +{ + Iclass* ic; + char *name; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + ic = ih->iclass; + + name = iupTableFirst(ic->attrib_func); + while (name) + { + IattribFunc* afunc = (IattribFunc*)iupTableGet(ih->iclass->attrib_func, name); + if (afunc && !(afunc->flags & IUPAF_NO_STRING)) + { + int inherit; + char *def_value; + char *value = iupClassObjectGetAttribute(ih, name, &def_value, &inherit); + if (value && value != iupAttribGet(ih, name)) + iupAttribStoreStr(ih, name, value); + } + + name = iupTableNext(ic->attrib_func); + } +} + +void iupClassObjectEnsureDefaultAttributes(Ihandle* ih) +{ + Iclass* ic; + char *name; + + ic = ih->iclass; + + name = iupTableFirst(ic->attrib_func); + while (name) + { + IattribFunc* afunc = (IattribFunc*)iupTableGetCurr(ic->attrib_func); + if (afunc && afunc->set && (afunc->default_value || afunc->system_default) && + (!(afunc->flags & IUPAF_NO_DEFAULTVALUE) || !(afunc->flags & IUPAF_NO_STRING) || !(afunc->flags & IUPAF_HAS_ID))) + { + if ((!iupStrEqualNoCase(afunc->default_value, afunc->system_default)) || + (afunc->call_global_default && iupGlobalDefaultColorChanged(afunc->default_value))) + { + if ((!ih->handle && (afunc->flags & IUPAF_NOT_MAPPED)) || + (ih->handle && !(afunc->flags & IUPAF_NOT_MAPPED) && !iupAttribGet(ih, name))) + afunc->set(ih, iClassGetDefaultValue(afunc)); + } + } + + name = iupTableNext(ic->attrib_func); + } +} + +char* iupClassGetDefaultAttribute(const char* classname, const char *attrib_name) +{ + Iclass* ic; + IattribFunc* afunc; + + iupASSERT(classname!=NULL); + if (!classname) + return NULL; + + iupASSERT(attrib_name!=NULL); + if (!attrib_name) + return NULL; + + ic = iupRegisterFindClass(classname); + if (!ic) + return NULL; + + afunc = (IattribFunc*)iupTableGet(ic->attrib_func, attrib_name); + if (afunc) + return (char*)afunc->default_value; + else + return NULL; +} diff --git a/iup/src/iup_classbase.c b/iup/src/iup_classbase.c new file mode 100755 index 0000000..9cb9e63 --- /dev/null +++ b/iup/src/iup_classbase.c @@ -0,0 +1,466 @@ +/** \file + * \brief Ihandle Class Base Functions + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_str.h" +#include "iup_attrib.h" +#include "iup_assert.h" + + +void iupBaseCallValueChangedCb(Ihandle* ih) +{ + IFn vc_cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB"); + if (vc_cb) + vc_cb(ih); +} + +int iupBaseTypeVoidMapMethod(Ihandle* ih) +{ + ih->handle = (InativeHandle*)-1; /* fake value just to indicate that it is already mapped */ + return IUP_NOERROR; +} + +char* iupBaseGetWidAttrib(Ihandle *ih) +{ + return (char*)ih->handle; +} + +void iupBaseUpdateSizeFromFont(Ihandle* ih) +{ + char* value = iupAttribGet(ih, "SIZE"); + if (!value) + return; + + iupBaseSetSizeAttrib(ih, value); +} + +int iupBaseSetSizeAttrib(Ihandle* ih, const char* value) +{ + if (!value) + { + ih->userwidth = 0; + ih->userheight = 0; + } + else + { + /* if not specified, the value is 0 */ + int w = 0, h = 0; + int charwidth, charheight; + iupdrvFontGetCharSize(ih, &charwidth, &charheight); + iupStrToIntInt(value, &w, &h, 'x'); + if (w < 0) w = 0; + if (h < 0) h = 0; + + ih->userwidth = iupWIDTH2RASTER(w, charwidth); + ih->userheight = iupHEIGHT2RASTER(h, charheight); + } + return 1; /* always save in the hash table, so when FONT is changed SIZE can be updated */ +} + +char* iupBaseGetSizeAttrib(Ihandle* ih) +{ + char* str; + int charwidth, charheight, width, height; + + if (ih->handle) + { + width = ih->currentwidth; + height = ih->currentheight; + } + else + { + width = ih->userwidth; + height = ih->userheight; + } + + iupdrvFontGetCharSize(ih, &charwidth, &charheight); + if (charwidth == 0 || charheight == 0) + return NULL; /* if font failed get from the hash table */ + + str = iupStrGetMemory(50); + sprintf(str, "%dx%d", iupRASTER2WIDTH(width, charwidth), + iupRASTER2HEIGHT(height, charheight)); + return str; +} + +int iupBaseSetRasterSizeAttrib(Ihandle* ih, const char* value) +{ + if (!value) + { + ih->userwidth = 0; + ih->userheight = 0; + } + else + { + /* if not specified, the value is 0 */ + int w = 0, h = 0; + iupStrToIntInt(value, &w, &h, 'x'); + if (w < 0) w = 0; + if (h < 0) h = 0; + ih->userwidth = w; + ih->userheight = h; + } + iupAttribSetStr(ih, "SIZE", NULL); /* clear SIZE in hash table */ + return 0; +} + +char* iupBaseGetRasterSizeAttrib(Ihandle* ih) +{ + char* str; + int width, height; + + if (ih->handle) + { + width = ih->currentwidth; + height = ih->currentheight; + } + else + { + width = ih->userwidth; + height = ih->userheight; + } + + if (!width && !height) + return NULL; + + str = iupStrGetMemory(50); + sprintf(str, "%dx%d", width, height); + return str; +} + +char* iupBaseGetCharSizeAttrib(Ihandle* ih) +{ + char* str; + int charwidth, charheight; + + iupdrvFontGetCharSize(ih, &charwidth, &charheight); + if (charwidth == 0 || charheight == 0) + return NULL; + + str = iupStrGetMemory(50); + sprintf(str, "%dx%d", charwidth, charheight); + return str; +} + +static char* iBaseGetPositionAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(50); + sprintf(str, "%d,%d", ih->x, ih->y); + return str; +} + +static int iBaseSetPositionAttrib(Ihandle* ih, const char* value) +{ + if (ih->is_floating) + iupStrToIntInt(value, &ih->x, &ih->y, ','); + return 0; +} + +char* iupBaseGetActiveAttrib(Ihandle *ih) +{ + if (iupdrvIsActive(ih)) + return "YES"; + else + return "NO"; +} + +static int iBaseNativeParentIsActive(Ihandle* ih) +{ + if (!ih->parent) + return 1; + + if (ih->parent->iclass->nativetype == IUP_TYPEVOID) + return iBaseNativeParentIsActive(ih->parent); + else + return iupdrvIsActive(ih->parent); +} + +int iupBaseSetActiveAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + { + if (iBaseNativeParentIsActive(ih)) + iupdrvSetActive(ih, 1); + } + else + iupdrvSetActive(ih, 0); + return 0; +} + +char* iupBaseGetVisibleAttrib(Ihandle* ih) +{ + if (iupdrvIsVisible(ih)) + return "YES"; + else + return "NO"; +} + +int iupBaseSetVisibleAttrib(Ihandle* ih, const char* value) +{ + iupdrvSetVisible(ih, iupStrBoolean(value)); + return 0; +} + +char* iupBaseNativeParentGetBgColorAttrib(Ihandle* ih) +{ + /* Used only by those who need a transparent background */ + char* color = iupAttribGetInheritNativeParent(ih, "BGCOLOR"); + if (!color) color = iupAttribGetInheritNativeParent(ih, "BACKGROUND"); + if (!color) color = IupGetGlobal("DLGBGCOLOR"); + return color; +} + +char* iupBaseNativeParentGetBgColor(Ihandle* ih) +{ + /* Used in SetBgColorAttrib */ + char* color = iupAttribGetInheritNativeParent(ih, "BGCOLOR"); + if (!color) color = IupGetGlobal("DLGBGCOLOR"); + return color; +} + +int iupBaseGetScrollbar(Ihandle* ih) +{ + int sb = IUP_SB_NONE; /* NO scrollbar by default */ + char* value = IupGetAttribute(ih, "SCROLLBAR"); + if (value) + { + if (iupStrEqualNoCase(value, "YES")) + sb = IUP_SB_HORIZ | IUP_SB_VERT; + else if (iupStrEqualNoCase(value, "HORIZONTAL")) + sb = IUP_SB_HORIZ; + else if (iupStrEqualNoCase(value, "VERTICAL")) + sb = IUP_SB_VERT; + } + return sb; +} + +static int iBaseSetNormalizerGroupAttrib(Ihandle* ih, const char* value) +{ + Ihandle* ih_normalizer = IupGetHandle(value); + if (!ih_normalizer) + { + ih_normalizer = IupNormalizer(NULL); + IupSetHandle(value, ih_normalizer); + } + + IupSetAttribute(ih_normalizer, "ADDCONTROL_HANDLE", (char*)ih); + return 1; +} + +static Ihandle* iBaseFindChild(Ihandle* ih, const char* name) +{ + Ihandle* child = ih->firstchild; + while (child) + { + char* child_name = iupAttribGet(child, "NAME"); + if (child_name && iupStrEqualNoCase(name, child_name)) + return child; + + if (child->firstchild) + { + Ihandle* c = iBaseFindChild(child, name); + if (c) return c; + } + + child = child->brother; + } + return NULL; +} + +Ihandle* IupGetDialogChild(Ihandle* ih, const char* name) +{ + Ihandle *child, *dialog; + char attrib[1024] = "_IUP_DIALOG_CHILD_"; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + if (!name) + return NULL; + + dialog = IupGetDialog(ih); + if (dialog) ih = dialog; + + strcat(attrib, name); + child = (Ihandle*)iupAttribGet(ih, attrib); + if (child) return child; + + if (ih->firstchild) + { + child = iBaseFindChild(ih, name); + if (child) return child; + } + return NULL; +} + +int iupBaseSetNameAttrib(Ihandle* ih, const char* value) +{ + Ihandle* dialog = IupGetDialog(ih); + if (dialog) + { + char attrib[1024] = "_IUP_DIALOG_CHILD_"; + strcat(attrib, value); + iupAttribSetStr(dialog, attrib, (char*)ih); + } + return 1; +} + +static int iBaseSetFloatingAttrib(Ihandle* ih, const char* value) +{ + ih->is_floating = iupStrBoolean(value); + return 0; +} + +static char* iBaseGetFloatingAttrib(Ihandle* ih) +{ + if (ih->is_floating) + return "YES"; + else + return "NO"; +} + +static int iBaseSetMaxSizeAttrib(Ihandle* ih, const char* value) +{ + if (value) + ih->has_maxsize = 1; + else + ih->has_maxsize = 0; + return 1; +} + +static int iBaseSetMinSizeAttrib(Ihandle* ih, const char* value) +{ + if (value) + ih->has_minsize = 1; + else + ih->has_minsize = 0; + return 1; +} + +static int iBaseSetExpandAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "YES")) + ih->expand = IUP_EXPAND_BOTH; + else if (iupStrEqualNoCase(value, "HORIZONTAL")) + ih->expand = IUP_EXPAND_WIDTH; + else if (iupStrEqualNoCase(value, "VERTICAL")) + ih->expand = IUP_EXPAND_HEIGHT; + else + ih->expand = IUP_EXPAND_NONE; + return 0; +} + +static char* iBaseGetExpandAttrib(Ihandle* ih) +{ + if (ih->expand & IUP_EXPAND_BOTH) + return "YES"; + else if (ih->expand & IUP_EXPAND_WIDTH) + return "HORIZONTAL"; + else if (ih->expand & IUP_EXPAND_HEIGHT) + return "VERTICAL"; + else + return "NO"; +} + +void iupBaseContainerUpdateExpand(Ihandle* ih) +{ + char *expand = iupAttribGetInherit(ih, "EXPAND"); + if (!expand) + ih->expand = IUP_EXPAND_BOTH; /* default for containers is YES */ + else + { + if (iupStrEqualNoCase(expand, "NO")) + ih->expand = IUP_EXPAND_NONE; + else if (iupStrEqualNoCase(expand, "HORIZONTAL")) + ih->expand = IUP_EXPAND_WIDTH; + else if (iupStrEqualNoCase(expand, "VERTICAL")) + ih->expand = IUP_EXPAND_HEIGHT; + else + ih->expand = IUP_EXPAND_BOTH; /* default for containers is YES */ + } +} + +/* EXPAND is registered with IUP_NO_INHERIT because it is not inheritable, + but it is inheritable for containers. + So if you set at a container it will not affect its children, + but children that are containers will get the same value. */ +char* iupBaseContainerGetExpandAttrib(Ihandle* ih) +{ + return iupAttribGetInherit(ih, "EXPAND"); +} + +void iupBaseRegisterCommonAttrib(Iclass* ic) +{ + iupClassRegisterAttribute(ic, "WID", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "NAME", NULL, iupBaseSetNameAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FLOATING", iBaseGetFloatingAttrib, iBaseSetFloatingAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "EXPAND", iBaseGetExpandAttrib, iBaseSetExpandAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NORMALIZERGROUP", NULL, iBaseSetNormalizerGroupAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* make sure everyone has the correct default value */ + iupClassRegisterAttribute(ic, "VISIBLE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "ACTIVE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + if (ic->is_interactive) + iupClassRegisterAttribute(ic, "CANFOCUS", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + else + iupClassRegisterAttribute(ic, "CANFOCUS", NULL, NULL, IUPAF_SAMEASSYSTEM, "NO", IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "SIZE", iupBaseGetSizeAttrib, iupBaseSetSizeAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "RASTERSIZE", iupBaseGetRasterSizeAttrib, iupBaseSetRasterSizeAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CHARSIZE", iupBaseGetCharSizeAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "POSITION", iBaseGetPositionAttrib, iBaseSetPositionAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MAXSIZE", NULL, iBaseSetMaxSizeAttrib, IUPAF_SAMEASSYSTEM, "65535x65535", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MINSIZE", NULL, iBaseSetMinSizeAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, iupdrvSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* use inheritance to retrieve standard fonts */ + iupClassRegisterAttribute(ic, "FONT", iupGetFontAttrib, iupSetFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "FONTSTYLE", iupGetFontStyleAttrib, iupSetFontStyleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FONTSIZE", iupGetFontSizeAttrib, iupSetFontSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FONTFACE", iupGetFontFaceAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupdrvBaseRegisterCommonAttrib(ic); +} + +void iupBaseRegisterVisualAttrib(Iclass* ic) +{ + iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, iupBaseSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); /* VISIBLE inheritance comes from the native system */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + + iupClassRegisterAttribute(ic, "ZORDER", NULL, iupdrvBaseSetZorderAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "X", iupdrvBaseGetXAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "Y", iupdrvBaseGetYAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "TIP", NULL, iupdrvBaseSetTipAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TIPVISIBLE", NULL, iupdrvBaseSetTipVisibleAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TIPDELAY", NULL, NULL, IUPAF_SAMEASSYSTEM, "5000", IUPAF_NOT_MAPPED); /* 5 seconds */ + iupClassRegisterAttribute(ic, "TIPBGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "255 255 225", IUPAF_NOT_MAPPED); /* Light Yellow */ + iupClassRegisterAttribute(ic, "TIPFGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "0 0 0", IUPAF_NOT_MAPPED); /* black */ +} + +void iupBaseRegisterCommonCallbacks(Iclass* ic) +{ + iupClassRegisterAttribute(ic, "MAP_CB", NULL, NULL, "", NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "UNMAP_CB", NULL, NULL, "", NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "GETFOCUS_CB", NULL, NULL, "", NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "KILLFOCUS_CB", NULL, NULL, "", NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ENTERWINDOW_CB", NULL, NULL, "", NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "LEAVEWINDOW_CB", NULL, NULL, "", NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "HELP_CB", NULL, NULL, "", NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "K_ANY", NULL, NULL, "i", NULL, IUPAF_NO_INHERIT); +} diff --git a/iup/src/iup_classbase.h b/iup/src/iup_classbase.h new file mode 100755 index 0000000..1ced9c6 --- /dev/null +++ b/iup/src/iup_classbase.h @@ -0,0 +1,175 @@ +/** \file + * \brief Base Class + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_CLASSBASE_H +#define __IUP_CLASSBASE_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup iclassbase Base Class + * \par + * See \ref iup_classbase.h + * \ingroup iclass + */ + + +/** Register all common base attributes: \n + * WID \n + * SIZE, RASTERSIZE, POSITION \n + * FONT (and derived) \n\n + * All controls that are positioned inside a dialog must register all common base attributes. + * \ingroup iclassbase */ +void iupBaseRegisterCommonAttrib(Iclass* ic); + +/** Register all visual base attributes: \n + * VISIBLE, ACTIVE \n + * ZORDER, X, Y \n + * TIP (and derived) \n\n + * All controls that are positioned inside a dialog must register all visual base attributes. + * \ingroup iclassbase */ +void iupBaseRegisterVisualAttrib(Iclass* ic); + +/** Register all common callbacks: \n +* MAP_CB, UNMAP_CB, GETFOCUS_CB, KILLFOCUS_CB, ENTERWINDOW_CB, LEAVEWINDOW_CB, K_ANY, HELP_CB. +* \ingroup iclassbase */ +void iupBaseRegisterCommonCallbacks(Iclass* ic); + +/* Register driver dependent common attributes. + Used only from iupBaseRegisterCommonAttrib */ +void iupdrvBaseRegisterCommonAttrib(Iclass* ic); + +/** Updates the expand member of the IUP object from the EXPAND attribute. + * Should be called in the beginning of the ComputeNaturalSize for a container. + * \ingroup iclassbase */ +void iupBaseContainerUpdateExpand(Ihandle* ih); + +/** Initializes the natural size using the user size, then + * if a container then update the "expand" member from the EXPAND attribute, then + * call \ref iupClassObjectComputeNaturalSize for containers if they have children or + * call \ref iupClassObjectComputeNaturalSize for non-containers if user size is not defined. + * Must be called for each children in the container. \n + * First call is in iupLayoutCompute. + * \ingroup iclassbase */ +void iupBaseComputeNaturalSize(Ihandle* ih); + +/** Update the current size from the available size, the natural size, expand and shrink. + * Call \ref iupClassObjectSetChildrenCurrentSize for containers if they have children. + * Must be called for each children in the container. \n + * First call is in iupLayoutCompute. + * \ingroup iclassbase */ +void iupBaseSetCurrentSize(Ihandle* ih, int w, int h, int shrink); + +/** Set the current position and update children position for containers. + * Call \ref iupClassObjectSetChildrenPosition for containers if they have children. + * Must be called for each children in the container. \n + * First call is in iupLayoutCompute. + * \ingroup iclassbase */ +void iupBaseSetPosition(Ihandle* ih, int x, int y); + +/* Updates the SIZE attribute if defined. + Called only from iupdrvSetStandardFontAttrib. */ +void iupBaseUpdateSizeFromFont(Ihandle* ih); + + +/** \defgroup iclassbasemethod Base Class Methods + * \par + * See \ref iup_classbase.h + * \ingroup iclassbase + */ + +/** Driver dependent \ref Iclass::LayoutUpdate method. + * \ingroup iclassbasemethod */ +void iupdrvBaseLayoutUpdateMethod(Ihandle *ih); + +/** Driver dependent \ref Iclass::UnMap method. + * \ingroup iclassbasemethod */ +void iupdrvBaseUnMapMethod(Ihandle* ih); + +/** Native type void \ref Iclass::Map method. + * \ingroup iclassbasemethod */ +int iupBaseTypeVoidMapMethod(Ihandle* ih); + + +/** \defgroup iclassbaseattribfunc Base Class Attribute Functions + * \par + * Used by the controls for iupClassRegisterAttribute. + * \par + * See \ref iup_classbase.h + * \ingroup iclassbase + * @{ + */ + +/* common */ +char* iupBaseGetWidAttrib(Ihandle* ih); +int iupBaseSetNameAttrib(Ihandle* ih, const char* value); +int iupBaseSetRasterSizeAttrib(Ihandle* ih, const char* value); +int iupBaseSetSizeAttrib(Ihandle* ih, const char* value); +char* iupBaseGetSizeAttrib(Ihandle* ih); +char* iupBaseGetRasterSizeAttrib(Ihandle* ih); + +/* visual */ +char* iupBaseGetVisibleAttrib(Ihandle* ih); +int iupBaseSetVisibleAttrib(Ihandle* ih, const char* value); +char* iupBaseGetActiveAttrib(Ihandle *ih); +int iupBaseSetActiveAttrib(Ihandle* ih, const char* value); +int iupdrvBaseSetZorderAttrib(Ihandle* ih, const char* value); +char *iupdrvBaseGetXAttrib(Ihandle *ih); +char *iupdrvBaseGetYAttrib(Ihandle *ih); +int iupdrvBaseSetTipAttrib(Ihandle* ih, const char* value); +int iupdrvBaseSetTipVisibleAttrib(Ihandle* ih, const char* value); +int iupdrvBaseSetBgColorAttrib(Ihandle* ih, const char* value); +int iupdrvBaseSetFgColorAttrib(Ihandle* ih, const char* value); +char* iupBaseNativeParentGetBgColorAttrib(Ihandle* ih); + +/* other */ +char* iupBaseContainerGetExpandAttrib(Ihandle* ih); +int iupdrvBaseSetCursorAttrib(Ihandle* ih, const char* value); +char* iupdrvBaseGetClientSizeAttrib(Ihandle* ih); + +/* Windows Only */ +char* iupdrvBaseGetTitleAttrib(Ihandle* ih); +int iupdrvBaseSetTitleAttrib(Ihandle* ih, const char* value); + +/** @} */ + + + +/** \defgroup iclassbaseutil Base Class Utilities + * \par + * See \ref iup_classbase.h + * \ingroup iclassbase + * @{ + */ + +#define iupMAX(_a,_b) ((_a)>(_b)?(_a):(_b)) +#define iupROUND(_x) ((int)((_x)>0? (_x)+0.5: (_x)-0.5)) + +#define iupCOLOR8TO16(_x) ((unsigned short)(_x*257)) /* 65535/255 = 257 */ +#define iupCOLOR16TO8(_x) ((unsigned char)(_x/257)) + +#define iupBYTECROP(_x) ((unsigned char)((_x)<0?0:((_x)>255)?255:(_x))) + +enum{IUP_ALIGN_ALEFT, IUP_ALIGN_ACENTER, IUP_ALIGN_ARIGHT}; +#define IUP_ALIGN_ABOTTOM IUP_ALIGN_ARIGHT +#define IUP_ALIGN_ATOP IUP_ALIGN_ALEFT + +enum{IUP_SB_NONE, IUP_SB_HORIZ, IUP_SB_VERT}; +int iupBaseGetScrollbar(Ihandle* ih); + +char* iupBaseNativeParentGetBgColor(Ihandle* ih); +void iupBaseCallValueChangedCb(Ihandle* ih); + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_colordlg.c b/iup/src/iup_colordlg.c new file mode 100755 index 0000000..d3835cd --- /dev/null +++ b/iup/src/iup_colordlg.c @@ -0,0 +1,44 @@ +/** \file + * \brief IupColorDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_stdcontrols.h" + + +Ihandle* IupColorDlg(void) +{ + return IupCreate("colordlg"); +} + +Iclass* iupColorDlgGetClass(void) +{ + Iclass* ic = iupClassNew(iupDialogGetClass()); + + ic->name = "colordlg"; + ic->nativetype = IUP_TYPEDIALOG; + ic->is_interactive = 1; + + /* reset not used native dialog methods */ + ic->parent->LayoutUpdate = NULL; + ic->parent->SetChildrenPosition = NULL; + ic->parent->Map = NULL; + ic->parent->UnMap = NULL; + + iupdrvColorDlgInitClass(ic); + + return ic; +} diff --git a/iup/src/iup_dialog.c b/iup/src/iup_dialog.c new file mode 100755 index 0000000..d70e12c --- /dev/null +++ b/iup/src/iup_dialog.c @@ -0,0 +1,747 @@ +/** \file + * \brief IupDialog class + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_class.h" +#include "iup_object.h" +#include "iup_dlglist.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_drv.h" +#include "iup_drvinfo.h" +#include "iup_drvfont.h" +#include "iup_focus.h" +#include "iup_str.h" +#define _IUPDLG_PRIVATE +#include "iup_dialog.h" + + +static int dlg_popup_level = 1; + +InativeHandle* iupDialogGetNativeParent(Ihandle* ih) +{ + Ihandle* parent = IupGetAttributeHandle(ih, "PARENTDIALOG"); + if (parent && parent->handle) + return parent->handle; + else + return (InativeHandle*)iupAttribGet(ih, "NATIVEPARENT"); +} + +static void iupDialogAdjustPos(Ihandle *ih, int *x, int *y) +{ + int cursor_x = 0, cursor_y = 0; + int screen_width = 0, screen_height = 0; + int current_x = 0, current_y = 0; + int parent_x = 0, parent_y = 0; + + /* the dialog is already mapped here */ + + if (*x == IUP_CURRENT || *y == IUP_CURRENT) + { + /* if first time, there is no current position */ + if (!ih->data->first_show) + { + int center = IUP_CENTER; + InativeHandle* parent = iupDialogGetNativeParent(ih); + if (parent) + center = IUP_CENTERPARENT; + + if (*x == IUP_CURRENT) *x = center; + if (*y == IUP_CURRENT) *y = center; + } + else + iupdrvDialogGetPosition(ih->handle, ¤t_x, ¤t_y); + } + + if (*x == IUP_CENTER || *y == IUP_CENTER || + *x == IUP_RIGHT || *y == IUP_RIGHT || + *x == IUP_CENTERPARENT || *y == IUP_CENTERPARENT) + iupdrvGetScreenSize(&screen_width, &screen_height); + + if (*x == IUP_CENTERPARENT || *y == IUP_CENTERPARENT) + { + InativeHandle* parent = iupDialogGetNativeParent(ih); + if (parent) + { + iupdrvDialogGetPosition(parent, &parent_x, &parent_y); + + if (*x == IUP_CENTERPARENT && *y == IUP_CENTERPARENT) + iupdrvDialogGetSize(parent, &screen_width, &screen_height); + else if (*x == IUP_CENTERPARENT) + iupdrvDialogGetSize(parent, &screen_width, NULL); + else if (*y == IUP_CENTERPARENT) + iupdrvDialogGetSize(parent, NULL, &screen_height); + } + } + + if (*x == IUP_MOUSEPOS || *y == IUP_MOUSEPOS) + iupdrvGetCursorPos(&cursor_x, &cursor_y); + + if (iupAttribGetBoolean(ih, "MDICHILD")) + { + Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE"); + if (client) + { + /* position is relative to mdi client */ + parent_x = 0; + parent_y = 0; + + /* screen size is now the size of the mdi client */ + screen_width = client->currentwidth; + screen_height = client->currentheight; + + iupdrvScreenToClient(client, ¤t_x, ¤t_y); + iupdrvScreenToClient(client, &cursor_x, &cursor_y); + } + } + + switch (*x) + { + case IUP_CENTERPARENT: + *x = (screen_width - ih->currentwidth)/2 + parent_x; + break; + case IUP_CENTER: + *x = (screen_width - ih->currentwidth)/2; + break; + case IUP_LEFT: + *x = 0; + break; + case IUP_RIGHT: + *x = screen_width - ih->currentwidth; + break; + case IUP_MOUSEPOS: + *x = cursor_x; + break; + case IUP_CURRENT: + *x = current_x; + break; + } + + switch (*y) + { + case IUP_CENTERPARENT: + *y = (screen_height - ih->currentheight)/2 + parent_y; + break; + case IUP_CENTER: + *y = (screen_height - ih->currentheight)/2; + break; + case IUP_LEFT: + *y = 0; + break; + case IUP_RIGHT: + *y = screen_height - ih->currentheight; + break; + case IUP_MOUSEPOS: + *y = cursor_y; + break; + case IUP_CURRENT: + *y = current_y; + break; + } +} + +static void iDialogSetModal(Ihandle* ih_popup) +{ + Ihandle *ih; + iupAttribSetStr(ih_popup, "MODAL", "YES"); + + /* disable all visible dialogs, and mark popup level */ + for (ih = iupDlgListFirst(); ih; ih = iupDlgListNext()) + { + if (ih != ih_popup && + ih->handle && + iupdrvDialogIsVisible(ih) && + ih->data->popup_level == 0) + { + iupdrvSetActive(ih, 0); + ih->data->popup_level = dlg_popup_level; + } + } + + dlg_popup_level++; +} + +static void iDialogUnSetModal(Ihandle* ih_popup) +{ + Ihandle *ih; + if (!iupAttribGetBoolean(ih_popup, "MODAL")) + return; + + iupAttribSetStr(ih_popup, "MODAL", NULL); + + /* must enable all visible dialogs at the marked popup level */ + for (ih = iupDlgListFirst(); ih; ih = iupDlgListNext()) + { + if (ih->handle) + { + if (ih->data->popup_level == dlg_popup_level-1) + { + iupdrvSetActive(ih, 1); + ih->data->popup_level = 0; + } + } + } + + dlg_popup_level--; +} + +static int iDialogCreateMethod(Ihandle* ih, void** params) +{ + ih->data = iupALLOCCTRLDATA(); + + ih->data->child_id = 100; /* initial number */ + ih->data->show_state = IUP_HIDE; + + if (params) + { + Ihandle** iparams = (Ihandle**)params; + if (*iparams) + IupAppend(ih, *iparams); + } + + iupDlgListAdd(ih); + + return IUP_NOERROR; +} + +static void iDialogDestroyMethod(Ihandle* ih) +{ + iupDlgListRemove(ih); +} + +static void iDialogComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + int decorwidth, decorheight; + Ihandle* child = ih->firstchild; + + iupDialogGetDecorSize(ih, &decorwidth, &decorheight); + *w = decorwidth; + *h = decorheight; + + if (child) + { + /* update child natural size first */ + iupBaseComputeNaturalSize(child); + + *expand = child->expand; + *w += child->naturalwidth; + *h += child->naturalheight; + } +} + +static void iDialogSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink) +{ + int decorwidth, decorheight, client_width, client_height; + + if (shrink) + { + client_width = ih->currentwidth; + client_height = ih->currentheight; + } + else + { + client_width = iupMAX(ih->naturalwidth, ih->currentwidth); + client_height = iupMAX(ih->naturalheight, ih->currentheight); + } + + iupDialogGetDecorSize(ih, &decorwidth, &decorheight); + + client_width -= decorwidth; + client_height -= decorheight; + if (client_width < 0) client_width = 0; + if (client_height < 0) client_height = 0; + + iupBaseSetCurrentSize(ih->firstchild, client_width, client_height, shrink); +} + +static void iDialogSetChildrenPositionMethod(Ihandle* ih, int x, int y) +{ + (void)x; + (void)y; + + /* Child coordinates are relative to client left-top corner. */ + iupBaseSetPosition(ih->firstchild, 0, 0); +} + +static void iDialogAfterShow(Ihandle* ih) +{ + Ihandle* old_focus; + IFni show_cb; + + /* process all pending messages */ + IupFlush(); + + old_focus = IupGetFocus(); + + show_cb = (IFni)IupGetCallback(ih, "SHOW_CB"); + if (show_cb && show_cb(ih, ih->data->show_state) == IUP_CLOSE) + { + IupExitLoop(); + return; + } + + if (ih->data->show_state == IUP_SHOW) + { + if (show_cb) + IupFlush(); /* again to update focus */ + + /* do it only if show_cb did NOT changed the current focus */ + if (old_focus == IupGetFocus()) + { + Ihandle *startfocus = IupGetAttributeHandle(ih, "STARTFOCUS"); + if (startfocus) + IupSetFocus(startfocus); + else + IupNextField(ih); + } + } +} + +int iupDialogGetChildId(Ihandle* ih) +{ + int id; + ih = IupGetDialog(ih); + if (!ih) return -1; + id = ih->data->child_id; + ih->data->child_id = id+1; + return id; +} + +char* iupDialogGetChildIdStr(Ihandle* ih) +{ + char *str = iupStrGetMemory(50); + Ihandle* dialog = IupGetDialog(ih); + sprintf(str, "iup-%s-%d", ih->iclass->name, dialog->data->child_id); + return str; +} + +int iupDialogPopup(Ihandle* ih, int x, int y) +{ + int was_visible; + + int ret = iupClassObjectDlgPopup(ih, x, y); + if (ret != IUP_INVALID) /* IUP_INVALID means it is not implemented */ + return ret; + + ih->data->show_state = IUP_SHOW; + + /* save visible state before iupdrvDialogSetPlacement */ + /* because it can also show the window when changing placement. */ + was_visible = iupdrvDialogIsVisible(ih); + + /* Update the position and placement */ + if (!iupdrvDialogSetPlacement(ih)) + { + iupDialogAdjustPos(ih, &x, &y); + iupdrvDialogSetPosition(ih, x, y); + } + + if (was_visible) /* already visible */ + { + /* only re-show to raise the window */ + iupdrvDialogSetVisible(ih, 1); + + /* flush, then process show_cb and startfocus */ + iDialogAfterShow(ih); + return IUP_NOERROR; + } + + if (iupAttribGetBoolean(ih, "MODAL")) /* already a popup */ + return IUP_NOERROR; + + iDialogSetModal(ih); + + ih->data->first_show = 1; + + /* actually show the window */ + /* test if placement turn the dialog visible */ + if (!iupdrvDialogIsVisible(ih)) + iupdrvDialogSetVisible(ih, 1); + + /* increment visible count */ + iupDlgListVisibleInc(); + + /* flush, then process show_cb and startfocus */ + iDialogAfterShow(ih); + + /* interrupt processing here */ + IupMainLoop(); + + /* if window is still valid (IupDestroy not called), + hide the dialog if still visible. */ + if (iupObjectCheck(ih)) + { + iDialogUnSetModal(ih); + IupHide(ih); + } + + return IUP_NOERROR; +} + +int iupDialogShowXY(Ihandle* ih, int x, int y) +{ + int was_visible; + + /* Calling IupShow for a visible dialog shown with IupPopup does nothing. */ + if (iupAttribGetBoolean(ih, "MODAL")) /* already a popup */ + return IUP_NOERROR; + + if (ih->data->popup_level != 0) + { + /* was disabled by a Popup, re-enable it */ + iupdrvSetActive(ih, 1); + ih->data->popup_level = 0; /* Now it is at the current popup level */ + } + + /* save visible state before iupdrvDialogSetPlacement */ + /* because it can also show the window when changing placement. */ + was_visible = iupdrvDialogIsVisible(ih); + + /* Update the position and placement */ + if (!iupdrvDialogSetPlacement(ih)) + { + iupDialogAdjustPos(ih, &x, &y); + iupdrvDialogSetPosition(ih, x, y); + } + + if (was_visible) /* already visible */ + { + /* only re-show to raise the window */ + iupdrvDialogSetVisible(ih, 1); + + /* flush, then process show_cb and startfocus */ + iDialogAfterShow(ih); + return IUP_NOERROR; + } + + ih->data->first_show = 1; + + /* actually show the window */ + /* test if placement turn the dialog visible */ + if (!iupdrvDialogIsVisible(ih)) + iupdrvDialogSetVisible(ih, 1); + + /* increment visible count */ + iupDlgListVisibleInc(); + + /* flush, then process show_cb and startfocus */ + iDialogAfterShow(ih); + + return IUP_NOERROR; +} + +void iupDialogHide(Ihandle* ih) +{ + /* hidden at the system and marked hidden in IUP */ + if (!iupdrvDialogIsVisible(ih) && ih->data->show_state == IUP_HIDE) + return; + + /* marked hidden in IUP */ + ih->data->show_state = IUP_HIDE; + + /* if called IupHide for a Popup window */ + if (iupAttribGetBoolean(ih, "MODAL")) + { + iDialogUnSetModal(ih); + IupExitLoop(); + } + + ih->data->ignore_resize = 1; + + /* actually hide the window */ + iupdrvDialogSetVisible(ih, 0); + + ih->data->ignore_resize = 0; + + /* decrement visible count */ + iupDlgListVisibleDec(); + + if (iupDlgListVisibleCount() <= 0) + { + /* if this is the last window visible, + exit message loop except when LOCKLOOP==YES */ + if (!iupStrBoolean(IupGetGlobal("LOCKLOOP"))) + IupExitLoop(); + } + + /* flush, then process show_cb and startfocus */ + iDialogAfterShow(ih); +} + + +/****************************************************************/ + + +static int iDialogSizeGetScale(const char* sz) +{ + if (!sz || sz[0] == 0) return 0; + if (iupStrEqualNoCase(sz, "FULL")) return 1; + if (iupStrEqualNoCase(sz, "HALF")) return 2; + if (iupStrEqualNoCase(sz, "THIRD")) return 3; + if (iupStrEqualNoCase(sz, "QUARTER")) return 4; + if (iupStrEqualNoCase(sz, "EIGHTH")) return 8; + return 0; +} + +static int iDialogSetSizeAttrib(Ihandle* ih, const char* value) +{ + if (!value) + { + ih->userwidth = 0; + ih->userheight = 0; + } + else + { + char *sh, sw[40]; + strcpy(sw, value); + sh = strchr(sw, 'x'); + if (!sh) + sh = ""; + else + { + *sh = '\0'; /* to mark the end of sw */ + ++sh; + } + + { + int charwidth, charheight; + int screen_width, screen_height; + int wscale = iDialogSizeGetScale(sw); + int hscale = iDialogSizeGetScale(sh); + + int width = 0, height = 0; + iupStrToIntInt(value, &width, &height, 'x'); + if (width < 0) width = 0; + if (height < 0) height = 0; + + iupdrvFontGetCharSize(ih, &charwidth, &charheight); + + /* desktop size, excluding task bars and menu bars */ + iupdrvGetScreenSize(&screen_width, &screen_height); + + if (wscale) + width = screen_width/wscale; + else + width = iupWIDTH2RASTER(width, charwidth); + + if (hscale) + height = screen_height/hscale; + else + height = iupHEIGHT2RASTER(height, charheight); + + ih->userwidth = width; + ih->userheight = height; + } + } + + /* must reset the current size, */ + /* so the user or the natural size will be used to resize the dialog */ + ih->currentwidth = 0; + ih->currentheight = 0; + + return 0; +} + +static int iDialogSetRasterSizeAttrib(Ihandle* ih, const char* value) +{ + if (!value) + { + ih->userwidth = 0; + ih->userheight = 0; + } + else + { + int w = 0, h = 0; + iupStrToIntInt(value, &w, &h, 'x'); + if (w < 0) w = 0; + if (h < 0) h = 0; + ih->userwidth = w; + ih->userheight = h; + } + + /* must reset the current size also, */ + /* so the user or the natural size will be used to resize the dialog */ + ih->currentwidth = 0; + ih->currentheight = 0; + + return 0; +} + +static int iDialogSetVisibleAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + IupShow(ih); + else + IupHide(ih); + return 0; +} + +void iupDialogUpdatePosition(Ihandle* ih) +{ + /* Used by pre-defined popup native dialogs */ + int x = iupAttribGetInt(ih, "_IUPDLG_X"); + int y = iupAttribGetInt(ih, "_IUPDLG_Y"); + iupdrvDialogUpdateSize(ih); + /* handle always as visible for the first time */ + ih->data->first_show = 0; + iupDialogAdjustPos(ih, &x, &y); + iupdrvDialogSetPosition(ih, x, y); +} + +void iupDialogGetDecorSize(Ihandle* ih, int *decorwidth, int *decorheight) +{ + int border, caption, menu; + iupdrvDialogGetDecoration(ih, &border, &caption, &menu); + + *decorwidth = 2*border; + *decorheight = 2*border + caption + menu; +} + +static int iDialogSetHideTaskbarAttrib(Ihandle *ih, const char *value) +{ + iupdrvDialogSetVisible(ih, !iupStrBoolean(value)); + return 0; +} + +static int iDialogSetMenuAttrib(Ihandle* ih, const char* value) +{ + if (!ih->handle) + { + Ihandle* menu = IupGetHandle(value); + ih->data->menu = menu; + return 1; + } + + if (!value) + { + if (ih->data->menu && ih->data->menu->handle) + { + ih->data->ignore_resize = 1; + IupUnmap(ih->data->menu); /* this will remove the menu from the dialog */ + ih->data->ignore_resize = 0; + + ih->data->menu = NULL; + } + } + else + { + Ihandle* menu = IupGetHandle(value); + if (!menu || menu->iclass->nativetype != IUP_TYPEMENU || menu->parent) + return 0; + + /* already the current menu and it is mapped */ + if (ih->data->menu && ih->data->menu==menu && menu->handle) + return 1; + + /* the current menu is mapped, so unmap it */ + if (ih->data->menu && ih->data->menu->handle && ih->data->menu!=menu) + { + ih->data->ignore_resize = 1; + IupUnmap(ih->data->menu); /* this will remove the menu from the dialog */ + ih->data->ignore_resize = 0; + } + + ih->data->menu = menu; + + menu->parent = ih; /* use this to create a menu bar instead of a popup menu */ + + ih->data->ignore_resize = 1; + IupMap(menu); /* this will automatically add the menu to the dialog */ + ih->data->ignore_resize = 0; + } + return 1; +} + + +/****************************************************************/ + + +Ihandle* IupDialog(Ihandle* child) +{ + void *params[2]; + params[0] = child; + params[1] = NULL; + return IupCreatev("dialog", params); +} + +Iclass* iupDialogGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "dialog"; + ic->format = "H"; /* one optional ihandle */ + ic->nativetype = IUP_TYPEDIALOG; + ic->childtype = IUP_CHILD_ONE; + ic->is_interactive = 1; + + /* Class functions */ + ic->Create = iDialogCreateMethod; + ic->Destroy = iDialogDestroyMethod; + ic->ComputeNaturalSize = iDialogComputeNaturalSizeMethod; + ic->SetChildrenCurrentSize = iDialogSetChildrenCurrentSizeMethod; + ic->SetChildrenPosition = iDialogSetChildrenPositionMethod; + + /* Callbacks */ + iupClassRegisterCallback(ic, "SHOW_CB", "i"); + iupClassRegisterCallback(ic, "DROPFILES_CB", "siii"); + iupClassRegisterCallback(ic, "RESIZE_CB", "ii"); + iupClassRegisterCallback(ic, "CLOSE_CB", ""); + + /* Common Callbacks */ + iupBaseRegisterCommonCallbacks(ic); + + /* Attribute functions */ + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Overwrite Common */ + iupClassRegisterAttribute(ic, "SIZE", iupBaseGetSizeAttrib, iDialogSetSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "RASTERSIZE", iupBaseGetRasterSizeAttrib, iDialogSetRasterSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "POSITION", NULL, NULL, NULL, NULL, IUPAF_WRITEONLY|IUPAF_READONLY|IUPAF_NO_INHERIT); /* forbidden in dialog */ + + /* Base Container */ + iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* Visual */ + iupBaseRegisterVisualAttrib(ic); + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, iDialogSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "NO", IUPAF_NO_INHERIT); /* the only case where VISIBLE default is NO */ + + /* IupDialog only */ + iupClassRegisterAttribute(ic, "MENU", NULL, iDialogSetMenuAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CURSOR", NULL, iupdrvBaseSetCursorAttrib, IUPAF_SAMEASSYSTEM, "ARROW", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "HIDETASKBAR", NULL, iDialogSetHideTaskbarAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MAXBOX", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MENUBOX", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MINBOX", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "RESIZE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "BORDER", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "DEFAULTENTER", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DEFAULTESC", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DIALOGFRAME", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PARENTDIALOG", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHRINK", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "STARTFOCUS", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MODAL", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PLACEMENT", NULL, NULL, "NORMAL", NULL, IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "NATIVEPARENT", NULL, NULL, NULL, NULL, IUPAF_NO_STRING); + + iupdrvDialogInitClass(ic); + + return ic; +} diff --git a/iup/src/iup_dialog.h b/iup/src/iup_dialog.h new file mode 100755 index 0000000..a127111 --- /dev/null +++ b/iup/src/iup_dialog.h @@ -0,0 +1,89 @@ +/** \file + * \brief Dialog Public and Private Declarations + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_DIALOG_H +#define __IUP_DIALOG_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* PUBLIC */ + +/* Shows the dialog in the given position and disable interaction with other dialogs. + * The element must be already mapped. + * Must return IUP_ERROR or IUP_NOERROR. + * Called only from IupPopup. */ +int iupDialogPopup(Ihandle* ih, int x, int y); + +/* Shows the dialog in the given position. + * The dialog must be already mapped. + * Must return IUP_ERROR or IUP_NOERROR. + * Called only from IupShow and IupShowXY. */ +int iupDialogShowXY(Ihandle* ih, int x, int y); + +/* Hides the dialog. + * Called only from IupHide. */ +void iupDialogHide(Ihandle* ih); + +/* Returns a unique number to be as child id. */ +int iupDialogGetChildId(Ihandle* ih); +char* iupDialogGetChildIdStr(Ihandle* ih); + +/* Returns the size of the decoration */ +void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu); + +/* Returns the native parent. Can be PARENTDIALOG or NATIVEPARENT attributes. Parent must be mapped. */ +InativeHandle* iupDialogGetNativeParent(Ihandle* ih); + +/* Updates the dialog initial position from internal attributes. + Used mostly by the native pre-defined dialogs. */ +void iupDialogUpdatePosition(Ihandle* ih); + + +/*********************************************************************/ + /* PRIVATE */ +/*********************************************************************/ + +#ifdef _IUPDLG_PRIVATE + +/* retrieve the decorations size that offsets the window size of the client size. */ +void iupDialogGetDecorSize(Ihandle* ih, int *decorwidth, int *decorheight); + +struct _IcontrolData +{ + int show_state, /* save the state to be used used in SHOW_CB */ + first_show, /* boolean flag to indicate that the dialog was shown for the first time */ + ignore_resize, /* flag to ignore the next resize */ + popup_level, /* popup level of the dialog if IupPopup used */ + child_id, /* serial number used by child controls */ + cmd_show; /* parameters for ShowWindow in Windows driver */ + Ihandle* menu; +}; + + +/******************************/ +/* Driver dependent functions */ +/******************************/ + +void iupdrvDialogInitClass(Iclass* iclass); + +void iupdrvDialogGetPosition(InativeHandle* handle, int *x, int *y); +void iupdrvDialogSetVisible(Ihandle* ih, int visible); +int iupdrvDialogSetPlacement(Ihandle* ih); +void iupdrvDialogSetPosition(Ihandle *ih, int x, int y); +void iupdrvDialogUpdateSize(Ihandle* ih); +void iupdrvDialogGetSize(InativeHandle* handle, int *w, int *h); +int iupdrvDialogIsVisible(Ihandle* ih); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_dlglist.c b/iup/src/iup_dlglist.c new file mode 100755 index 0000000..c385b50 --- /dev/null +++ b/iup/src/iup_dlglist.c @@ -0,0 +1,130 @@ +/** \file + * \brief list of all created dialogs + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> + +#include "iup.h" + +#include "iup_dlglist.h" +#include "iup_object.h" +#include "iup_assert.h" + + +typedef struct Idiallst_ +{ + Ihandle *ih; + struct Idiallst_ *next; +} Idiallst; + +static Idiallst *idlglist = NULL; /* list of all created dialogs */ +static int idlg_count = 0; + +void iupDlgListAdd(Ihandle *ih) +{ + if (ih) + { + Idiallst *p=(Idiallst *)malloc(sizeof(Idiallst)); + if (!p) + return; + p->ih = ih; + p->next = idlglist; + idlglist = p; + idlg_count++; + } +} + +void iupDlgListRemove(Ihandle *ih) +{ + if (!idlglist || !ih) + return; + + if (idlglist->ih == ih) /* ih is header */ + { + Idiallst *p = idlglist->next; + free(idlglist); + idlglist = p; + idlg_count--; + } + else + { + Idiallst *p; /* current pointer */ + Idiallst *b; /* before pointer */ + for (b = idlglist, p = idlglist->next; p; b = p, p = p->next) + { + if (p->ih == ih) + { + b->next = p->next; + free (p); + idlg_count--; + return; + } + } + } +} + +static Idiallst *idlg_first = NULL; + +Ihandle *iupDlgListFirst (void) +{ + idlg_first = idlglist; + return iupDlgListNext(); +} + +Ihandle *iupDlgListNext (void) +{ + Ihandle *ih = NULL; + if (idlg_first) + { + ih = idlg_first->ih; + idlg_first = idlg_first->next; + } + return ih; +} + +static int idlg_nvisiblewin = 0; + +void iupDlgListVisibleInc(void) +{ + iupASSERT(idlg_nvisiblewin < idlg_count); + if (idlg_nvisiblewin == idlg_count) + return; + idlg_nvisiblewin++; +} + +void iupDlgListVisibleDec(void) +{ + iupASSERT(idlg_nvisiblewin > 0); + idlg_nvisiblewin--; +} + +int iupDlgListVisibleCount(void) +{ + return idlg_nvisiblewin; +} + +void iupDlgListDestroyAll(void) +{ + int i = 0, count; + Ihandle** ih_array = (Ihandle**)malloc(idlg_count * sizeof(Ihandle*)); + Idiallst *list; + for (list = idlglist; list; list = list->next) + { + if (iupObjectCheck(list->ih)) + { + ih_array[i] = list->ih; + i++; + } + } + + count = i; + for (i = 0; i < count; i++) + { + if (iupObjectCheck(ih_array[i])) + IupDestroy(ih_array[i]); /* this will also destroy the list */ + } + + free(ih_array); +} diff --git a/iup/src/iup_dlglist.h b/iup/src/iup_dlglist.h new file mode 100755 index 0000000..99d3184 --- /dev/null +++ b/iup/src/iup_dlglist.h @@ -0,0 +1,58 @@ +/** \file + * \brief list of all created dialogs + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_DLGLIST_H +#define __IUP_DLGLIST_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup dlglist List of Dialogs + * \par + * See \ref iup_dlglist.h + * \ingroup cpi */ + + +/** Adds a dialog to the list. Used only in IupDialog. + * \ingroup dlglist */ +void iupDlgListAdd(Ihandle *ih); + +/** Removes a dialog from the list. Used only in IupDestroy. + * \ingroup dlglist */ +void iupDlgListRemove(Ihandle *ih); + +/** Starts a loop for all the created dialogs. + * \ingroup dlglist */ +Ihandle* iupDlgListFirst(void); + +/** Retrieve the next dialog on the list. Must call iupDlgListFirst first. + * \ingroup dlglist */ +Ihandle* iupDlgListNext(void); + +/** Increments the number of visible dialogs. + * \ingroup dlglist */ +void iupDlgListVisibleInc(void); + +/** Decrements the number of visible dialogs. + * \ingroup dlglist */ +void iupDlgListVisibleDec(void); + +/** Returns the number of visible dialogs. + * \ingroup dlglist */ +int iupDlgListVisibleCount(void); + +/* Destroy all dialogs and the list. + Called only from IupClose. */ +void iupDlgListDestroyAll(void); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_dll.rc b/iup/src/iup_dll.rc new file mode 100755 index 0000000..a1c78d8 --- /dev/null +++ b/iup/src/iup_dll.rc @@ -0,0 +1,41 @@ +TECGRAF_ICON ICON "..\\etc\\tecgraf.ico" + +1 VERSIONINFO + FILEVERSION 3,0,0,0 + PRODUCTVERSION 3,0,0,0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "www.tecgraf.puc-rio.br/iup\0" + VALUE "CompanyName", "Tecgraf/PUC-Rio\0" + VALUE "FileDescription", "IUP - Portable User Interface\0" + VALUE "FileVersion", "3.0.0\0" + VALUE "LegalCopyright", "Copyright © 1994-2009 Tecgraf, PUC-Rio.\0" + VALUE "OriginalFilename", "iup.dll\0" + VALUE "ProductName", "IUP for Windows\0" + VALUE "ProductVersion", "3.0.0\0" + END + END +END + +CURSOR_PEN CURSOR "..\\etc\\pen.cur" + +/* To avoid the inclusion of <winuser.h> */ +#define WS_CHILD 0x40000000L +#define WS_VISIBLE 0x10000000L +#define WS_CLIPSIBLINGS 0x04000000L +#define DS_3DLOOK 0x0004L +#define DS_CONTROL 0x0400L +#define SS_OWNERDRAW 0x0000000DL +#define WS_EX_STATICEDGE 0x00020000L + +#define IUP_PREVIEWCANVAS 3000 + +iupPreviewDlg DIALOG DISCARDABLE 0, 0, 250, 95 +STYLE WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | DS_3DLOOK | DS_CONTROL +FONT 8, "MS Shell Dlg" +BEGIN + CONTROL "", IUP_PREVIEWCANVAS, "STATIC", SS_OWNERDRAW, 70, 0, 120, 90, WS_EX_STATICEDGE +END diff --git a/iup/src/iup_drv.h b/iup/src/iup_drv.h new file mode 100755 index 0000000..5cdb8e7 --- /dev/null +++ b/iup/src/iup_drv.h @@ -0,0 +1,99 @@ +/** \file + * \brief Driver Interface. Each driver must export the symbols defined here. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_DRV_H +#define __IUP_DRV_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup drv Driver Interface + * \par + * Each driver must export the symbols defined here. + * \par + * See \ref iup_drv.h + */ + + +/** Sets a global environment attribute. Called from IupSetGlobal and IupStoreGlobal. + * Must return 1 is process the atribute, or 0 is not. + * \ingroup drv */ +int iupdrvSetGlobal(const char* name, const char* value); + +/** Returns a global environment attribute. Called from IupGetGlobal. + * \ingroup drv */ +char* iupdrvGetGlobal(const char* name); + +/** Changes the idle callback. Called from IupSetFunction. + * \ingroup drv */ +void iupdrvSetIdleFunction(Icallback func); + +/** Convert the coordinates from screen relative to client area releative. + * \ingroup drv */ +void iupdrvScreenToClient(Ihandle* ih, int *x, int *y); + +/** Returns true if the element is visible. + * \ingroup drv */ +int iupdrvIsVisible(Ihandle* ih); + +/** Returns true if the element is active. + * \ingroup drv */ +int iupdrvIsActive(Ihandle* ih); + +/** Actually changes the focus to the given element. + * \ingroup drv */ +void iupdrvSetFocus(Ihandle* ih); + +/** Changes the visible state of an element. + * Not used for dialogs. + * \ingroup drv */ +void iupdrvSetVisible(Ihandle* ih, int enable); + +/** Changes the active state of an element. + * \ingroup drv */ +void iupdrvSetActive(Ihandle* ih, int enable); + +/** Post a redraw of a control. + * \ingroup drv */ +void iupdrvDisplayUpdate(Ihandle *ih); + +/** Force a redraw of a control. + * \ingroup drv */ +void iupdrvDisplayRedraw(Ihandle *ih); + +/** Reparent the native control. + * \ingroup drv */ +void iupdrvReparent(Ihandle* ih); + +/** Draws a focus rectangle + * \ingroup drv */ +void iupdrvDrawFocusRect(Ihandle* ih, void* gc, int x, int y, int w, int h); + +/** Size of the scroolbar. + * \ingroup drv */ +int iupdrvGetScrollbarSize(void); + +/** Activates a control. + * \ingroup drv */ +void iupdrvActivate(Ihandle* ih); + +/** Returns the height of a menu bar. + * \ingroup drv */ +int iupdrvMenuGetMenuBarSize(Ihandle* ih); + + +/* Called only from IupOpen/IupClose. */ +int iupdrvOpen(int *argc, char ***argv); +void iupdrvClose(void); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_drvfont.h b/iup/src/iup_drvfont.h new file mode 100755 index 0000000..d6fb137 --- /dev/null +++ b/iup/src/iup_drvfont.h @@ -0,0 +1,116 @@ +/** \file + * \brief Driver Font Management + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_DRVFONT_H +#define __IUP_DRVFONT_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup drvfont Driver Font Interface + * \par + * Each driver must export the symbols defined here. + * \par + * See \ref iup_drvfont.h + * \ingroup drv */ + +/* Called only from IupOpen/IupClose. */ +void iupdrvFontInit(void); +void iupdrvFontFinish(void); + +/** Retrieve the character size for the selected font. + * Should be used only to calculate the SIZE attribute. + * \ingroup drvfont */ +void iupdrvFontGetCharSize(Ihandle* ih, int *charwidth, int *charheight); + +/** Retrieve the string width for the selected font. + * \ingroup drvfont */ +int iupdrvFontGetStringWidth(Ihandle* ih, const char* str); + +/** Retrieve the multi-lined string size for the selected font. \n + * Width is the maximum line width. \n + * Height is charheight*number_of_lines (this will avoid line size variations). + * \ingroup drvfont */ +void iupdrvFontGetMultiLineStringSize(Ihandle* ih, const char* str, int *w, int *h); + +/** Returns the System default font. + * \ingroup drvfont */ +char* iupdrvGetSystemFont(void); + +/** STANDARDFONT attribute set function. + * \ingroup drvfont */ +int iupdrvSetStandardFontAttrib(Ihandle* ih, const char* value); + + + +/** FONT attribute get function. + * \ingroup drvfont */ +char* iupGetFontAttrib(Ihandle* ih); + +/** FONT attribute set function. + * \ingroup drvfont */ +int iupSetFontAttrib(Ihandle* ih, const char* value); + +/** Parse the common font format description. + * Returns a non zero value if successful. + * \ingroup drvfont */ +int iupFontParsePango(const char *value, char *typeface, int *size, int *bold, int *italic, int *underline, int *strikeout); + +/** Parse the old IUP Windows font format description. + * Returns a non zero value if successful. + * \ingroup drvfont */ +int iupFontParseWin(const char *value, char *fontname, int *height, int *bold, int *italic, int *underline, int *strikeout); + +/** Parse the X-Windows font format description. + * Returns a non zero value if successful. + * \ingroup drvfont */ +int iupFontParseX(const char *value, char *fontname, int *height, int *bold, int *italic, int *underline, int *strikeout); + + +/** Changes the FONT style only. + * \ingroup attribfunc */ +int iupSetFontStyleAttrib(Ihandle* ih, const char* value); + +/** Changes the FONT size only. + * \ingroup attribfunc */ +int iupSetFontSizeAttrib(Ihandle* ih, const char* value); + +/** Returns the FONT style. + * \ingroup attribfunc */ +char* iupGetFontStyleAttrib(Ihandle* ih); + +/** Returns the FONT size. + * \ingroup attribfunc */ +char* iupGetFontSizeAttrib(Ihandle* ih); + +/** Returns the FONT face. + * \ingroup attribfunc */ +char* iupGetFontFaceAttrib(Ihandle* ih); + +/* Used in GLobal Attributes */ +void iupSetDefaultFontSizeGlobalAttrib(const char* value); +char* iupGetDefaultFontSizeGlobalAttrib(void); + + +/* Updates the STANDARDFONT attrib. + * Called only from IupMap. + */ +void iupUpdateStandardFontAttrib(Ihandle* ih); + +/* Used to map foreign names into native names */ +const char* iupFontGetWinName(const char* name); +const char* iupFontGetXName(const char* name); +const char* iupFontGetPangoName(const char* name); + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_drvinfo.h b/iup/src/iup_drvinfo.h new file mode 100755 index 0000000..7ff303f --- /dev/null +++ b/iup/src/iup_drvinfo.h @@ -0,0 +1,103 @@ +/** \file + * \brief Driver Information Functions + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_DRVINFO_H +#define __IUP_DRVINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup drvinfo Driver Information Interface + * \par + * Each driver must export the symbols defined here. + * But in this case the functions are shared by different drivers in the same system. + * \par + * For example, the GTK driver and the Windows driver share the same implementation + * of these functions when the GTK driver is compiled in Windows. + * The GTK driver and the Motif driver share the same implementation + * of these functions when the GTK driver is compiled in UNIX. + * \par + * See \ref iup_drvinfo.h + * \ingroup drv */ + + +/** Retrieve the main desktop full size. + * \ingroup drvinfo */ +void iupdrvGetFullSize(int *width, int *height); + +/** Retrieve the main desktop available size. + * \ingroup drvinfo */ +void iupdrvGetScreenSize(int *width, int *height); + +/** Retrieve the default desktop bits per pixel. + * \ingroup drvinfo */ +int iupdrvGetScreenDepth(void); + +/** Returns a string with the system version number. + * \ingroup drvinfo */ +char *iupdrvGetSystemVersion(void); + +/** Returns a string with the system name. + * \ingroup drvinfo */ +char* iupdrvGetSystemName(void); + +/** Returns a string with the computer name. + * \ingroup drvinfo */ +char* iupdrvGetComputerName(void); + +/** Returns a string with the user name. + * \ingroup drvinfo */ +char* iupdrvGetUserName(void); + +/** Returns the key state for Shift, Ctrl, Alt and sYs, in this order. + * Left and right keys are considered. + * Should declare "char key[5]". + * Values could be space (" ") or "SCAY". + * \ingroup drvinfo */ +void iupdrvGetKeyState(char* key); + +/** Returns the current position of the mouse cursor. + * \ingroup drvinfo */ +void iupdrvGetCursorPos(int *x, int *y); + +/** Returns the driver "Display" in UNIX and NULL in Windows. + * Must be implemented somewhere else. + * \ingroup drvinfo */ +void* iupdrvGetDisplay(void); + +/** Returns the decoration size of the native window. + * In Windows will also includes the menu if any. + * Used in DialogGetDecoration. + * \ingroup drvinfo */ +int iupdrvGetWindowDecor(void* wnd, int *border, int *caption); + +/** Returns the current directory. + * \ingroup drvinfo */ +char* iupdrvGetCurrentDirectory(void); + +/** Changes the current directory. + * \ingroup drvinfo */ +int iupdrvSetCurrentDirectory(const char* dir); + +/** Returns true if the given name is an existant file. + * \ingroup drvinfo */ +int iupdrvIsFile(const char* name); + +/** Returns true if the given name is an existant directory. + * \ingroup drvinfo */ +int iupdrvIsDirectory(const char* name); + +/** Creates a new direcotry. + * \ingroup drvinfo */ +int iupdrvMakeDirectory(const char* name); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_filedlg.c b/iup/src/iup_filedlg.c new file mode 100755 index 0000000..e764143 --- /dev/null +++ b/iup/src/iup_filedlg.c @@ -0,0 +1,67 @@ +/** \file + * \brief IupFileDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_stdcontrols.h" + + +Ihandle* IupFileDlg(void) +{ + return IupCreate("filedlg"); +} + +Iclass* iupFileDlgGetClass(void) +{ + Iclass* ic = iupClassNew(iupDialogGetClass()); + + ic->name = "filedlg"; + ic->nativetype = IUP_TYPEDIALOG; + ic->is_interactive = 1; + + iupClassRegisterCallback(ic, "FILE_CB", "ss"); + + /* reset not used native dialog methods */ + ic->parent->LayoutUpdate = NULL; + ic->parent->SetChildrenPosition = NULL; + ic->parent->Map = NULL; + ic->parent->UnMap = NULL; + + iupdrvFileDlgInitClass(ic); + + /* only the default value */ + iupClassRegisterAttribute(ic, "NOCHANGEDIR", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DIALOGTYPE", NULL, NULL, IUPAF_SAMEASSYSTEM, "OPEN", IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "PREVIEWDC", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_READONLY|IUPAF_NO_STRING); + + iupClassRegisterAttribute(ic, "PREVIEWWIDTH", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_READONLY|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "PREVIEWHEIGHT", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_READONLY|IUPAF_NO_STRING); + + iupClassRegisterAttribute(ic, "ALLOWNEW", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DIRECTORY", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FILE", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FILTER", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NOOVERWRITEPROMPT", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWHIDDEN", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWPREVIEW", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "FILEEXIST", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_READONLY); + iupClassRegisterAttribute(ic, "STATUS", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_READONLY); + iupClassRegisterAttribute(ic, "VALUE", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_READONLY); + + return ic; +} diff --git a/iup/src/iup_fill.c b/iup/src/iup_fill.c new file mode 100755 index 0000000..4cad3c0 --- /dev/null +++ b/iup/src/iup_fill.c @@ -0,0 +1,242 @@ +/** \file + * \brief Fill Control. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" + + +enum {IUP_FILL_NONE, IUP_FILL_HORIZ, IUP_FILL_VERT}; + +struct _IcontrolData +{ + int dir; +}; + +static int iFillGetDir(Ihandle* ih) +{ + if (!ih->parent) + return IUP_FILL_NONE; + + if (ih->data->dir != IUP_FILL_NONE) + return ih->data->dir; + + /* Its parent must be an IupHbox or an IupVbox. */ + if (ih->parent->iclass->nativetype == IUP_TYPEVOID) + { + if (iupStrEqual(ih->parent->iclass->name, "hbox")) + ih->data->dir = IUP_FILL_HORIZ; + else if (iupStrEqual(ih->parent->iclass->name, "vbox")) + ih->data->dir = IUP_FILL_VERT; + } + + return ih->data->dir; +} + +static int iFillMapMethod(Ihandle* ih) +{ + iFillGetDir(ih); + return iupBaseTypeVoidMapMethod(ih); +} + +static void iFillUnMapMethod(Ihandle* ih) +{ + ih->data->dir = IUP_FILL_NONE; +} + +static int iFillSetRasterSizeAttrib(Ihandle* ih, const char* value) +{ + if (!value) + { + ih->userwidth = 0; + ih->userheight = 0; + } + else + { + int s = 0; + if (iFillGetDir(ih) == IUP_FILL_NONE) /* if Fill is not yet a child of a Vbox or Hbox */ + { + iupAttribSetStr(ih, "SIZE", NULL); + return 1; + } + + iupStrToInt(value, &s); + if (s > 0) + { + if (iFillGetDir(ih) == IUP_FILL_HORIZ) + { + ih->userwidth = s; /* inside HBOX */ + ih->userheight = 0; + } + else + { + ih->userheight = s; /* inside VBOX */ + ih->userwidth = 0; + } + } + } + iupAttribSetStr(ih, "SIZE", NULL); + return 0; +} + +static int iFillSetSizeAttrib(Ihandle* ih, const char* value) +{ + if (!value) + { + ih->userwidth = 0; + ih->userheight = 0; + } + else + { + int s = 0; + if (iFillGetDir(ih) == IUP_FILL_NONE) /* if Fill is not yet a child of a Vbox or Hbox */ + { + iupAttribSetStr(ih, "RASTERSIZE", NULL); + return 1; + } + + iupStrToInt(value, &s); + if (s > 0) + { + int charwidth, charheight; + iupdrvFontGetCharSize(ih, &charwidth, &charheight); + if (iFillGetDir(ih) == IUP_FILL_HORIZ) + { + ih->userwidth = iupWIDTH2RASTER(s, charwidth); /* inside HBOX */ + ih->userheight = 0; + } + else + { + ih->userheight = iupHEIGHT2RASTER(s, charheight); /* inside VBOX */ + ih->userwidth = 0; + } + } + } + iupAttribSetStr(ih, "RASTERSIZE", NULL); + return 1; +} + +static char* iFillGetExpandAttrib(Ihandle* ih) +{ + if (iFillGetDir(ih) == IUP_FILL_NONE) /* if Fill is not yet a child of a Vbox or Hbox */ + return "NO"; + + /* if size is not defined, then expansion on that direction is permited */ + if (iFillGetDir(ih) == IUP_FILL_HORIZ) + { + if (ih->userwidth <= 0) + return "HORIZONTAL"; + } + else + { + if (ih->userheight <= 0) + return "VERTICAL"; + } + + return "NO"; +} + +static void iFillUpdateSize(Ihandle* ih) +{ + char* value = iupAttribGet(ih, "SIZE"); + if (value) + { + iFillSetSizeAttrib(ih, value); + iupAttribSetStr(ih, "SIZE", NULL); + } + value = iupAttribGet(ih, "RASTERSIZE"); + if (value) + { + iFillSetRasterSizeAttrib(ih, value); + iupAttribSetStr(ih, "RASTERSIZE", NULL); + } +} + +static void iFillComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + (void)expand; /* unset if not a container */ + + /* EXPAND is initialized as none for FILL */ + ih->expand = IUP_EXPAND_NONE; + + iFillUpdateSize(ih); + + /* always initialize the natural size using the user size, + must do this again because of iFillUpdateSize */ + ih->naturalwidth = ih->userwidth; + ih->naturalheight = ih->userheight; + + if (iFillGetDir(ih) == IUP_FILL_NONE) /* if Fill is not a child of a Vbox or Hbox */ + return; + + /* if size is NOT defined, then expansion on that direction is permited */ + if (iFillGetDir(ih) == IUP_FILL_HORIZ) + { + if (ih->naturalwidth <= 0) + ih->expand = IUP_EXPAND_W0; + } + else + { + if (ih->naturalheight <= 0) + ih->expand = IUP_EXPAND_H0; + } + + *w = ih->naturalwidth; + *h = ih->naturalheight; +} + +static int iFillCreateMethod(Ihandle* ih, void** params) +{ + (void)params; + ih->data = iupALLOCCTRLDATA(); + return IUP_NOERROR; +} + +/******************************************************************************/ + +Ihandle* IupFill(void) +{ + return IupCreate("fill"); +} + +Iclass* iupFillGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "fill"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPEVOID; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 0; + + /* Class functions */ + ic->Create = iFillCreateMethod; + ic->Map = iFillMapMethod; + ic->UnMap = iFillUnMapMethod; + ic->ComputeNaturalSize = iFillComputeNaturalSizeMethod; + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Overwrite Common */ + iupClassRegisterAttribute(ic, "SIZE", iupBaseGetSizeAttrib, iFillSetSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "RASTERSIZE", iupBaseGetRasterSizeAttrib, iFillSetRasterSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* Base */ + iupClassRegisterAttribute(ic, "EXPAND", iFillGetExpandAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} diff --git a/iup/src/iup_focus.c b/iup/src/iup_focus.c new file mode 100755 index 0000000..be54b75 --- /dev/null +++ b/iup/src/iup_focus.c @@ -0,0 +1,281 @@ +/** \file + * \brief Keyboard Focus navigation + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_focus.h" +#include "iup_class.h" +#include "iup_assert.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" + + +Ihandle* iupFocusNextInteractive(Ihandle *ih) +{ + Ihandle *c; + + if (!ih) + return NULL; + + for (c = ih->brother; c; c = c->brother) + { + if (c->iclass->is_interactive) + return c; + } + + return NULL; +} + +int iupFocusCanAccept(Ihandle *ih) +{ + if (ih->iclass->is_interactive && /* interactive */ + iupAttribGetBoolean(ih, "CANFOCUS") && /* can receive focus */ + ih->handle && /* mapped */ + IupGetInt(ih, "ACTIVE") && /* active */ + IupGetInt(ih, "VISIBLE")) /* visible */ + return 1; + else + return 0; +} + +static int iFocusCheckActiveRadio(Ihandle *ih) +{ + if (iupStrEqual(ih->iclass->name, "toggle") && + IupGetInt(ih, "RADIO") && + !IupGetInt(ih, "VALUE")) + return 0; + else + return 1; +} + +static Ihandle* iFocusFindAtBrothers(Ihandle *start, int checkradio) +{ + Ihandle *c; + Ihandle *nf; + + for (c = start; c; c = c->brother) + { + /* check itself */ + if (iupFocusCanAccept(c) && (!checkradio || iFocusCheckActiveRadio(c))) + return c; + + /* then check its children */ + nf = iFocusFindAtBrothers(c->firstchild, checkradio); + if (nf) + return nf; + } + + return NULL; +} + +static Ihandle* iFocusFindNext(Ihandle *ih, int checkradio) +{ + Ihandle *nf, *p; + + if (!ih) + return NULL; + + /* look down in the child tree */ + if (ih->firstchild) + { + nf = iFocusFindAtBrothers(ih->firstchild, checkradio); + if (nf) return nf; + } + + /* look in the same level */ + if (ih->brother) + { + nf = iFocusFindAtBrothers(ih->brother, checkradio); + if (nf) return nf; + } + + /* look up in the brothers of the parent level */ + if (ih->parent) + { + for (p = ih->parent; p; p = p->parent) + { + if (p->brother) + { + nf = iFocusFindAtBrothers(p->brother, checkradio); + if (nf) return nf; + } + } + } + + return NULL; +} + +Ihandle* IupNextField(Ihandle *ih) +{ + Ihandle *ih_next; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + ih_next = iFocusFindNext(ih, 1); + if (!ih_next) + { + /* not found after the element, then start over from the begining, + at the dialog. */ + ih_next = iFocusFindNext(IupGetDialog(ih), 1); + if (ih_next == ih) + return NULL; + } + + if (ih_next) + { + iupdrvSetFocus(ih_next); + return ih_next; + } + + return NULL; +} + +void iupFocusNext(Ihandle *ih) +{ + Ihandle *ih_next = iFocusFindNext(ih, 0); + if (!ih_next) + { + /* not found after the element, then start over from the begining, + at the dialog. */ + ih_next = iFocusFindNext(IupGetDialog(ih), 0); + if (ih_next == ih) + return; + } + if (ih_next) + iupdrvSetFocus(ih_next); +} + +static int iFocusFindPrevious(Ihandle *parent, Ihandle **previous, Ihandle *ih, int checkradio) +{ + Ihandle *c; + + if (!parent) + return 0; + + for (c = parent->firstchild; c; c = c->brother) + { + if (c == ih) + { + /* if found child, returns the current previous. + but if previous is NULL, then keep searching until the last element. */ + if (*previous) + return 1; + } + else + { + /* save the possible previous */ + if (iupFocusCanAccept(c) && (!checkradio || iFocusCheckActiveRadio(c))) + *previous = c; + } + + /* then check its children */ + if (iFocusFindPrevious(c, previous, ih, checkradio)) + return 1; + } + + return 0; +} + +Ihandle* IupPreviousField(Ihandle *ih) +{ + Ihandle *previous = NULL; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + + /* search from the dialog down to the element */ + iFocusFindPrevious(IupGetDialog(ih), &previous, ih, 1); + + if (previous) + { + iupdrvSetFocus(previous); + return previous; + } + + return NULL; +} + +void iupFocusPrevious(Ihandle *ih) +{ + Ihandle *previous = NULL; + + /* search from the dialog down to the element */ + iFocusFindPrevious(IupGetDialog(ih), &previous, ih, 0); + + if (previous) + iupdrvSetFocus(previous); +} + +/* local variables */ +static Ihandle* iup_current_focus = NULL; + +Ihandle *IupSetFocus(Ihandle *ih) +{ + Ihandle* old_focus = iup_current_focus; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return old_focus; + + /* iup_current_focus is NOT set here, + only in the iupCallGetFocusCb */ + + if (iupFocusCanAccept(ih)) + iupdrvSetFocus(ih); + + return old_focus; +} + +Ihandle *IupGetFocus(void) +{ + return iup_current_focus; +} + +void iupCallGetFocusCb(Ihandle *ih) +{ + Icallback cb; + + if (ih == iup_current_focus) /* avoid duplicate messages */ + return; + + cb = (Icallback)IupGetCallback(ih, "GETFOCUS_CB"); + if (cb) cb(ih); + + if (ih->iclass->nativetype == IUP_TYPECANVAS) + { + IFni cb2 = (IFni)IupGetCallback(ih, "FOCUS_CB"); + if (cb2) cb2(ih, 1); + } + + iup_current_focus = ih; +} + +void iupCallKillFocusCb(Ihandle *ih) +{ + Icallback cb; + + if (ih != iup_current_focus) /* avoid duplicate messages */ + return; + + cb = IupGetCallback(ih, "KILLFOCUS_CB"); + if (cb) cb(ih); + + if (ih->iclass->nativetype == IUP_TYPECANVAS) + { + IFni cb2 = (IFni)IupGetCallback(ih, "FOCUS_CB"); + if (cb2) cb2(ih, 0); + } + + iup_current_focus = NULL; +} diff --git a/iup/src/iup_focus.h b/iup/src/iup_focus.h new file mode 100755 index 0000000..239e233 --- /dev/null +++ b/iup/src/iup_focus.h @@ -0,0 +1,53 @@ +/** \file + * \brief Keyboard Focus navigation + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_FOCUS_H +#define __IUP_FOCUS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup focus Keyboard Focus + * \par + * See \ref iup_focus.h + * \ingroup cpi */ + + +/** Utility to check if a control can have the keyboard input focus. + * To receive the focus must be interactive, has CANFOCUS=YES, is mapped, is visible and is active. + * \ingroup focus */ +int iupFocusCanAccept(Ihandle *ih); + +/** Call GETFOCUS_CB and FOCUS_CB. + * \ingroup focus */ +void iupCallGetFocusCb(Ihandle *ih); + +/** Call KILLFOCUS_CB and FOCUS_CB. + * \ingroup focus */ +void iupCallKillFocusCb(Ihandle *ih); + +/** Returns the next interactive brother. Independs if it can receive the focus. + * \ingroup focus */ +Ihandle* iupFocusNextInteractive(Ihandle *ih); + +/* Used only in iupKeyProcessNavigation */ +void iupFocusNext(Ihandle *ih); +void iupFocusPrevious(Ihandle *ih); + + +/* Other functions declared in <iup.h> and implemented here. +IupPreviousField +IupNextField +*/ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_font.c b/iup/src/iup_font.c new file mode 100755 index 0000000..869bd2a --- /dev/null +++ b/iup/src/iup_font.c @@ -0,0 +1,714 @@ +/** \file + * \brief Font mapping + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "iup.h" + +#include "iup_str.h" +#include "iup_drvfont.h" +#include "iup_assert.h" +#include "iup_attrib.h" +#include "iup_class.h" + +typedef struct _IfontNameMap { + const char* pango; + const char* x; + const char* win; +} IfontNameMap; + +#define IFONT_NAME_MAP_SIZE 7 + +static IfontNameMap ifont_name_map[IFONT_NAME_MAP_SIZE] = { + {"sans", "helvetica", "arial"}, + {NULL, "new century schoolbook", "century schoolbook"}, + {"monospace", "courier", "courier new"}, + {NULL, "lucida", "lucida sans unicode"}, + {NULL, "lucidabright", "lucida bright"}, + {NULL, "lucidatypewriter", "lucida console"}, + {"serif", "times", "times new roman"} +}; + +const char* iupFontGetPangoName(const char* name) +{ + int i; + if (!name) + return NULL; + for (i=0; i<IFONT_NAME_MAP_SIZE; i++) + { + if (iupStrEqualNoCase(ifont_name_map[i].win, name)) + return ifont_name_map[i].pango; + if (iupStrEqualNoCase(ifont_name_map[i].x, name)) + return ifont_name_map[i].pango; + } + + return NULL; +} + +const char* iupFontGetWinName(const char* name) +{ + int i; + if (!name) + return NULL; + for (i=0; i<IFONT_NAME_MAP_SIZE; i++) + { + if (iupStrEqualNoCase(ifont_name_map[i].pango, name)) + return ifont_name_map[i].win; + if (iupStrEqualNoCase(ifont_name_map[i].x, name)) + return ifont_name_map[i].win; + } + + return NULL; +} + +const char* iupFontGetXName(const char* name) +{ + int i; + if (!name) + return NULL; + for (i=0; i<IFONT_NAME_MAP_SIZE; i++) + { + if (iupStrEqualNoCase(ifont_name_map[i].win, name)) + return ifont_name_map[i].x; + if (iupStrEqualNoCase(ifont_name_map[i].pango, name)) + return ifont_name_map[i].x; + } + + return NULL; +} + +char *IupUnMapFont(const char *standardfont) +{ + int size = 0; + int is_bold = 0, + is_italic = 0, + is_underline = 0, + is_strikeout = 0; + char typeface[1024]; + char *str, *iup_typeface, *iup_style; + + iupASSERT(standardfont!=NULL); + if (!standardfont) + return NULL; + + if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + return NULL; + + if (strstr(typeface, "Helvetica")) + iup_typeface = "HELVETICA_"; + else if (strstr(typeface, "Courier")) + iup_typeface = "COURIER_"; + else if (strstr(typeface, "Times")) + iup_typeface = "TIMES_"; + else + return NULL; + + if (!is_bold && !is_italic) + iup_style = "NORMAL_"; + else if (!is_bold && is_italic) + iup_style = "ITALIC_"; + else if (is_bold && !is_italic) + iup_style = "BOLD_"; + else + return NULL; + + str = iupStrGetMemory(1024); + sprintf(str, "%s%s%d", iup_typeface, iup_style, size); + return str; +} + +static char* iFontGetStyle(const char* iupfont, int *size) +{ + char* style = NULL; + + if (strstr(iupfont, "NORMAL_")) + { + style = ""; + iupfont += strlen("NORMAL_"); + } + else if (strstr(iupfont, "ITALIC_")) + { + style = "Italic"; + iupfont += strlen("ITALIC_"); + } + else if (strstr(iupfont, "BOLD_")) + { + style = "Bold"; + iupfont += strlen("BOLD_"); + } + else + return NULL; + + *size = atoi(iupfont); + return style; +} + +char *IupMapFont(const char *iupfont) +{ + int size = 0; + char *str, *typeface, *style; + + iupASSERT(iupfont!=NULL); + if (!iupfont) + return NULL; + + if (strstr(iupfont, "HELVETICA_")) + { + typeface = "Helvetica"; + style = iFontGetStyle(iupfont+strlen("HELVETICA_"), &size); + if (!style || size==0) + return NULL; + } + else if (strstr(iupfont, "COURIER_")) + { + typeface = "Courier"; + style = iFontGetStyle(iupfont+strlen("COURIER_"), &size); + if (!style || size==0) + return NULL; + } + else if (strstr(iupfont, "TIMES_")) + { + typeface = "Times"; + style = iFontGetStyle(iupfont+strlen("TIMES_"), &size); + if (!style || size==0) + return NULL; + } + else + return NULL; + + str = iupStrGetMemory(1024); + sprintf(str, "%s, %s %d", typeface, style, size); + return str; +} + +int iupSetFontAttrib(Ihandle* ih, const char* value) +{ + /* when set FONT can be an OLD IUP Font or a Native font */ + const char* standardfont = IupMapFont(value); + if (!standardfont) + standardfont = value; + + IupStoreAttribute(ih, "STANDARDFONT", standardfont); + return 0; +} + +char* iupGetFontAttrib(Ihandle* ih) +{ + return iupAttribGetStr(ih, "STANDARDFONT"); +} + +void iupUpdateStandardFontAttrib(Ihandle* ih) +{ + int inherit; + iupClassObjectSetAttribute(ih, "STANDARDFONT", iupGetFontAttrib(ih), &inherit); +} + +char* iupGetFontFaceAttrib(Ihandle* ih) +{ + int size = 0; + int is_bold = 0, + is_italic = 0, + is_underline = 0, + is_strikeout = 0; + char typeface[1024]; + char *str; + char* standardfont; + + standardfont = iupGetFontAttrib(ih); + + /* parse the old Windows format first */ + if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + return NULL; + } + } + + str = iupStrGetMemory(50); + sprintf(str, "%s", typeface); + return str; +} + +char* iupGetFontSizeAttrib(Ihandle* ih) +{ + int size = 0; + int is_bold = 0, + is_italic = 0, + is_underline = 0, + is_strikeout = 0; + char typeface[1024]; + char *str; + char* standardfont; + + standardfont = iupGetFontAttrib(ih); + + /* parse the old Windows format first */ + if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + return NULL; + } + } + + str = iupStrGetMemory(50); + sprintf(str, "%d", size); + return str; +} + +int iupSetFontSizeAttrib(Ihandle* ih, const char* value) +{ + int size = 0; + int is_bold = 0, + is_italic = 0, + is_underline = 0, + is_strikeout = 0; + char typeface[1024]; + char new_standardfont[1024]; + char* standardfont; + + if (!value) + return 0; + + standardfont = iupGetFontAttrib(ih); + + /* parse the old Windows format first */ + if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + return 0; + } + } + + sprintf(new_standardfont, "%s, %s%s%s%s%s", typeface, is_bold?"Bold ":"", is_italic?"Italic ":"", is_underline?"Underline ":"", is_strikeout?"Strikeout ":"", value); + IupStoreAttribute(ih, "STANDARDFONT", new_standardfont); + + return 0; +} + +void iupSetDefaultFontSizeGlobalAttrib(const char* value) +{ + int size = 0; + int is_bold = 0, + is_italic = 0, + is_underline = 0, + is_strikeout = 0; + char typeface[1024]; + char new_standardfont[1024]; + char* standardfont; + + if (!value) + return; + + standardfont = IupGetGlobal("DEFAULTFONT"); + + /* parse the old Windows format first */ + if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + return; + } + } + + sprintf(new_standardfont, "%s, %s%s%s%s%s", typeface, is_bold?"Bold ":"", is_italic?"Italic ":"", is_underline?"Underline ":"", is_strikeout?"Strikeout ":"", value); + IupStoreGlobal("DEFAULTFONT", new_standardfont); + + return; +} + +char* iupGetDefaultFontSizeGlobalAttrib(void) +{ + int size = 0; + int is_bold = 0, + is_italic = 0, + is_underline = 0, + is_strikeout = 0; + char typeface[1024]; + char *str; + char* standardfont; + + standardfont = IupGetGlobal("DEFAULTFONT"); + + /* parse the old Windows format first */ + if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + return NULL; + } + } + + str = iupStrGetMemory(50); + sprintf(str, "%d", size); + return str; +} + +char* iupGetFontStyleAttrib(Ihandle* ih) +{ + int size = 0; + int is_bold = 0, + is_italic = 0, + is_underline = 0, + is_strikeout = 0; + char typeface[1024]; + char *str; + char* standardfont; + + standardfont = iupGetFontAttrib(ih); + + /* parse the old Windows format first */ + if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + return NULL; + } + } + + str = iupStrGetMemory(200); + sprintf(str, "%s%s%s%s", is_bold?"Bold ":"", is_italic?"Italic ":"", is_underline?"Underline ":"", is_strikeout?"Strikeout ":""); + return str; +} + +int iupSetFontStyleAttrib(Ihandle* ih, const char* value) +{ + int size = 0; + int is_bold = 0, + is_italic = 0, + is_underline = 0, + is_strikeout = 0; + char typeface[1024]; + char new_standardfont[1024]; + char* standardfont; + + if (!value) + return 0; + + standardfont = iupGetFontAttrib(ih); + + /* parse the old Windows format first */ + if (!iupFontParseWin(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParseX(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + return 0; + } + } + + sprintf(new_standardfont, "%s, %s %d", typeface, value, size); + IupStoreAttribute(ih, "STANDARDFONT", new_standardfont); + + return 0; +} + +/**************************************************************/ +/* Native Font Format, compatible with Pango Font Description */ +/**************************************************************/ + +/* +The string contains the font name, the style and the size. +Style can be a free combination of some names separated by spaces. +Font name can be a list of font family names separated by comma. +*/ + +#define isspace(_x) (_x == ' ') + +enum { /* style */ + FONT_PLAIN = 0, + FONT_BOLD = 1, + FONT_ITALIC = 2, + FONT_UNDERLINE = 4, + FONT_STRIKEOUT = 8 +}; + +static int iFontFindStyleName(const char *name, int len, int *style) +{ +#define STYLE_NUM_NAMES 21 + static struct { const char* name; int style; } cd_style_names[STYLE_NUM_NAMES] = { + {"Normal", 0}, + {"Oblique", FONT_ITALIC}, + {"Italic", FONT_ITALIC}, + {"Small-Caps", 0}, + {"Ultra-Light", 0}, + {"Light", 0}, + {"Medium", 0}, + {"Semi-Bold", FONT_BOLD}, + {"Bold", FONT_BOLD}, + {"Ultra-Bold", FONT_BOLD}, + {"Heavy", 0}, + {"Ultra-Condensed",0}, + {"Extra-Condensed",0}, + {"Condensed", 0}, + {"Semi-Condensed", 0}, + {"Semi-Expanded", 0}, + {"Expanded", 0}, + {"Extra-Expanded", 0}, + {"Ultra-Expanded", 0}, + {"Underline", FONT_UNDERLINE}, + {"Strikeout", FONT_STRIKEOUT} + }; + + int i; + for (i = 0; i < STYLE_NUM_NAMES; i++) + { + if (strncmp(cd_style_names[i].name, name, len)==0) + { + *style = cd_style_names[i].style; + return 1; + } + } + + return 0; +} + +static const char * iFontGetWord(const char *str, const char *last, int *wordlen) +{ + const char *result; + + while (last > str && isspace(*(last - 1))) + last--; + + result = last; + while (result > str && !isspace(*(result - 1))) + result--; + + *wordlen = last - result; + + return result; +} + +int iupFontParsePango(const char *standardfont, char *typeface, int *size, int *bold, int *italic, int *underline, int *strikeout) +{ + const char *p, *last; + int len, wordlen, style = 0; + + if (standardfont[0] == '-') /* X font, abort */ + return 0; + + len = (int)strlen(standardfont); + last = standardfont + len; + p = iFontGetWord(standardfont, last, &wordlen); + + /* Look for a size at the end of the string */ + if (wordlen != 0) + { + int new_size = atoi(p); + if (new_size != 0) + { + *size = new_size; + last = p; + } + } + + /* Now parse style words */ + p = iFontGetWord(standardfont, last, &wordlen); + while (wordlen != 0) + { + int new_style = 0; + + if (!iFontFindStyleName(p, wordlen, &new_style)) + break; + else + { + style |= new_style; + + last = p; + p = iFontGetWord(standardfont, last, &wordlen); + } + } + + *bold = 0; + *italic = 0; + *underline = 0; + *strikeout = 0; + + if (style&FONT_BOLD) + *bold = 1; + if (style&FONT_ITALIC) + *italic = 1; + if (style&FONT_UNDERLINE) + *underline = 1; + if (style&FONT_STRIKEOUT) + *strikeout = 1; + + /* Remainder is font family list. */ + + /* Trim off trailing white space */ + while (last > standardfont && isspace(*(last - 1))) + last--; + + /* Trim off trailing commas */ + if (last > standardfont && *(last - 1) == ',') + last--; + + /* Again, trim off trailing white space */ + while (last > standardfont && isspace(*(last - 1))) + last--; + + /* Trim off leading white space */ + while (last > standardfont && isspace(*standardfont)) + standardfont++; + + if (standardfont != last) + { + len = (last - standardfont); + strncpy(typeface, standardfont, len); + typeface[len] = 0; + return 1; + } + else + return 0; +} + +int iupFontParseWin(const char *value, char *fontname, int *height, int *bold, int *italic, int *underline, int *strikeout) +{ + int c; + + if (value[0] == '-') /* X font, abort */ + return 0; + + if (strstr(value, ":") == NULL) + return 0; + + if (value[0] == ':') /* check if it has the typeface */ + value++; /* jump separator */ + else + { + c = (int)strcspn(value, ":"); /* extract typeface */ + if (c == 0) return 0; + strncpy(fontname, value, c); + fontname[c]='\0'; + value += c+1; /* jump typeface and separator */ + } + + *bold = 0; + *italic = 0; + *underline = 0; + *strikeout = 0; + + if (value[0] == ':') /* check if it has attributes */ + value++; /* jump separator */ + else + { + do /* extract style (bold/italic etc) */ + { + char style[30]; + + c = (int)strcspn(value, ":,"); + if (c == 0) + break; + + strncpy(style, value, c); + style[c] = '\0'; + + if(iupStrEqual(style, "BOLD")) + *bold = 1; + else if(iupStrEqual(style,"ITALIC")) + *italic = 1; + else if(iupStrEqual(style,"UNDERLINE")) + *underline = 1; + else if(iupStrEqual(style,"STRIKEOUT")) + *strikeout = 1; + + value += c; /* jump only the attribute */ + + if(value[0] == ':') /* end of attribute list */ + { + value++; + break; + } + + value++; /* jump separator */ + } while (value[0]); + } + + /* extract size in points */ + if (!iupStrToInt(value, height)) + return 0; + + if (height == 0) + return 0; + + return 1; +} + +int iupFontParseX(const char *standardfont, char *typeface, int *size, int *bold, int *italic, int *underline, int *strikeout) +{ + char style1[30], style2[30]; + char* token; + char font[1024]; + + if (standardfont[0] != '-') + return 0; + + strcpy(font, standardfont+1); /* skip first '-' */ + + *bold = 0; + *italic = 0; + *underline = 0; + *strikeout = 0; + + /* fndry */ + token = strtok(font, "-"); + if (!token) return 0; + + /* fmly */ + token = strtok(NULL, "-"); + if (!token) return 0; + strcpy(typeface, token); + + /* wght */ + token = strtok(NULL, "-"); + if (!token) return 0; + strcpy(style1, token); + if (strstr("bold", style1)) + *bold = 1; + + /* slant */ + token = strtok(NULL, "-"); + if (!token) return 0; + strcpy(style2, token); + if (*style2 == 'i' || *style2 == 'o') + *italic = 1; + + /* sWdth */ + token = strtok(NULL, "-"); + if (!token) return 0; + /* adstyl */ + token = strtok(NULL, "-"); + if (!token) return 0; + + /* pxlsz */ + token = strtok(NULL, "-"); + if (!token) return 0; + *size = -atoi(token); /* size in pixels */ + + if (*size < 0) + return 1; + + /* ptSz */ + token = strtok(NULL, "-"); + if (!token) return 0; + *size = atoi(token)/10; /* size in deci-points */ + + if (*size > 0) + return 1; + + return 0; +} + diff --git a/iup/src/iup_fontdlg.c b/iup/src/iup_fontdlg.c new file mode 100755 index 0000000..9e0f05c --- /dev/null +++ b/iup/src/iup_fontdlg.c @@ -0,0 +1,48 @@ +/** \file + * \brief IupFontDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_stdcontrols.h" + + +Ihandle* IupFontDlg(void) +{ + return IupCreate("fontdlg"); +} + +Iclass* iupFontDlgGetClass(void) +{ + Iclass* ic = iupClassNew(iupDialogGetClass()); + + ic->name = "fontdlg"; + ic->nativetype = IUP_TYPEDIALOG; + ic->is_interactive = 1; + + /* reset not used native dialog methods */ + ic->parent->LayoutUpdate = NULL; + ic->parent->SetChildrenPosition = NULL; + ic->parent->Map = NULL; + ic->parent->UnMap = NULL; + + /* IupFontDialog only */ + iupClassRegisterAttribute(ic, "STATUS", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_READONLY); + iupClassRegisterAttribute(ic, "VALUE", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + + iupdrvFontDlgInitClass(ic); + + return ic; +} diff --git a/iup/src/iup_frame.c b/iup/src/iup_frame.c new file mode 100755 index 0000000..e1d0a13 --- /dev/null +++ b/iup/src/iup_frame.c @@ -0,0 +1,165 @@ +/** \file + * \brief Frame Control. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" +#include "iup_frame.h" + + +int iupFrameGetTitleHeight(Ihandle* ih) +{ + int charheight; + iupdrvFontGetCharSize(ih, NULL, &charheight); + return charheight; +} + +static void iFrameGetDecorSize(Ihandle* ih, int *width, int *height) +{ + *width = 5; + *height = 5; + + if (iupAttribGet(ih, "_IUPFRAME_HAS_TITLE") || iupAttribGet(ih, "TITLE")) + { + (*height) += iupFrameGetTitleHeight(ih); + } +} + +static char* iFrameGetClientSizeAttrib(Ihandle* ih) +{ + int width, height, decorwidth, decorheight; + char* str = iupStrGetMemory(20); + width = ih->currentwidth; + height = ih->currentheight; + iFrameGetDecorSize(ih, &decorwidth, &decorheight); + width -= decorwidth; + height -= decorheight; + if (width < 0) width = 0; + if (height < 0) height = 0; + sprintf(str, "%dx%d", width, height); + return str; +} + +static int iFrameCreateMethod(Ihandle* ih, void** params) +{ + if (params) + { + Ihandle** iparams = (Ihandle**)params; + if (*iparams) + IupAppend(ih, *iparams); + } + + return IUP_NOERROR; +} + +static void iFrameComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + int decorwidth, decorheight; + Ihandle* child = ih->firstchild; + + iFrameGetDecorSize(ih, &decorwidth, &decorheight); + *w = decorwidth; + *h = decorheight; + + if (child) + { + /* update child natural size first */ + iupBaseComputeNaturalSize(child); + + *expand = child->expand; + *w += child->naturalwidth; + *h += child->naturalheight; + } +} + +static void iFrameSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink) +{ + int width, height, decorwidth, decorheight; + + iFrameGetDecorSize(ih, &decorwidth, &decorheight); + + width = ih->currentwidth-decorwidth; + height = ih->currentheight-decorheight; + if (width < 0) width = 0; + if (height < 0) height = 0; + + iupBaseSetCurrentSize(ih->firstchild, width, height, shrink); +} + +static void iFrameSetChildrenPositionMethod(Ihandle* ih, int x, int y) +{ + /* IupFrame is the native parent of its children, + so the position is restarted at (0,0) */ + + iupdrvFrameGetDecorOffset(ih, &x, &y); + + /* Child coordinates are relative to client left-top corner. */ + iupBaseSetPosition(ih->firstchild, x, y); +} + + +/******************************************************************************/ + + +Ihandle* IupFrame(Ihandle* child) +{ + void *params[2]; + params[0] = (void*)child; + params[1] = NULL; + return IupCreatev("frame", params); +} + +Iclass* iupFrameGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "frame"; + ic->format = "H"; /* one optional ihandle */ + ic->nativetype = IUP_TYPECONTROL; + ic->childtype = IUP_CHILD_ONE; + ic->is_interactive = 0; + + /* Class functions */ + ic->Create = iFrameCreateMethod; + + ic->ComputeNaturalSize = iFrameComputeNaturalSizeMethod; + ic->SetChildrenCurrentSize = iFrameSetChildrenCurrentSizeMethod; + ic->SetChildrenPosition = iFrameSetChildrenPositionMethod; + + ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Common Callbacks */ + iupClassRegisterCallback(ic, "MAP_CB", ""); + iupClassRegisterCallback(ic, "UNMAP_CB", ""); + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Visual */ + iupBaseRegisterVisualAttrib(ic); + + /* Base Container */ + iupClassRegisterAttribute(ic, "CLIENTSIZE", iFrameGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* IupFrame only */ + iupClassRegisterAttribute(ic, "SUNKEN", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + + iupdrvFrameInitClass(ic); + + return ic; +} diff --git a/iup/src/iup_frame.h b/iup/src/iup_frame.h new file mode 100755 index 0000000..a7fd520 --- /dev/null +++ b/iup/src/iup_frame.h @@ -0,0 +1,22 @@ +/** \file + * \brief Frame Control Private Declarations + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_FRAME_H +#define __IUP_FRAME_H + +#ifdef __cplusplus +extern "C" { +#endif + +void iupdrvFrameInitClass(Iclass* ic); +void iupdrvFrameGetDecorOffset(Ihandle* ih, int *x, int *y); +int iupFrameGetTitleHeight(Ihandle* ih); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_func.c b/iup/src/iup_func.c new file mode 100755 index 0000000..76683c7 --- /dev/null +++ b/iup/src/iup_func.c @@ -0,0 +1,78 @@ +/** \file + * \brief function table manager + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> + +#include "iup.h" + +#include "iup_str.h" +#include "iup_table.h" +#include "iup_func.h" +#include "iup_drv.h" +#include "iup_assert.h" + + +static Itable *ifunc_table = NULL; /* the function hast table indexed by the name string */ +static const char *ifunc_action_name = NULL; /* name of the action being retrieved in IupGetFunction */ + +void iupFuncInit(void) +{ + ifunc_table = iupTableCreate(IUPTABLE_STRINGINDEXED); +} + +void iupFuncFinish(void) +{ + iupTableDestroy(ifunc_table); + ifunc_table = NULL; +} + +const char *IupGetActionName(void) +{ + return ifunc_action_name; +} + +Icallback IupGetFunction(const char *name) +{ + void* value; + Icallback func; + + iupASSERT(name!=NULL); + if (!name) + return NULL; + + ifunc_action_name = name; /* store the retrieved name */ + + func = (Icallback)iupTableGetFunc(ifunc_table, name, &value); + + /* if not defined and not the idle, then check for the DEFAULT_ACTION */ + if (!func && !iupStrEqual(name, "IDLE_ACTION")) + func = (Icallback)iupTableGetFunc(ifunc_table, "DEFAULT_ACTION", &value); + + return func; +} + +Icallback IupSetFunction(const char *name, Icallback func) +{ + void* value; + Icallback old_func; + + iupASSERT(name!=NULL); + if (!name) + return NULL; + + old_func = (Icallback)iupTableGetFunc(ifunc_table, name, &value); + + if (!func) + iupTableRemove(ifunc_table, name); + else + iupTableSetFunc(ifunc_table, name, (Ifunc)func); + + /* notifies the driver if changing the Idle */ + if (iupStrEqual(name, "IDLE_ACTION")) + iupdrvSetIdleFunction(func); + + return old_func; +} diff --git a/iup/src/iup_func.h b/iup/src/iup_func.h new file mode 100755 index 0000000..8372163 --- /dev/null +++ b/iup/src/iup_func.h @@ -0,0 +1,28 @@ +/** \file + * \brief Global Function table. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_FUNC_H +#define __IUP_FUNC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* called only in IupOpen and IupClose */ +void iupFuncInit(void); +void iupFuncFinish(void); + +/* Other functions declared in <iup.h> and implemented here. +IupGetActionName +IupGetFunction +IupSetFunction +*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_getparam.c b/iup/src/iup_getparam.c new file mode 100755 index 0000000..1418aa5 --- /dev/null +++ b/iup/src/iup_getparam.c @@ -0,0 +1,1254 @@ +/** \file + * \brief IupGetParam + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <assert.h> + +#include "iup.h" + +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_strmessage.h" +#include "iup_drvfont.h" + + +#define RAD2DEG 57.296f /* radians to degrees */ + + +/******************************************************************************************* + Internal Callbacks +*******************************************************************************************/ + +static int iParamButtonOK_CB(Ihandle* self) +{ + Ihandle* dlg = IupGetDialog(self); + Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB"); + iupAttribSetStr(dlg, "STATUS", "1"); + if (cb && !cb(dlg, -1, (void*)iupAttribGet(dlg, "USER_DATA"))) + return IUP_DEFAULT; + else + return IUP_CLOSE; +} + +static int iParamButtonCancel_CB(Ihandle* self) +{ + Ihandle* dlg = IupGetDialog(self); + Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB"); + iupAttribSetStr(dlg, "STATUS", "0"); + if (cb) cb(dlg, -3, (void*)iupAttribGet(dlg, "USER_DATA")); + return IUP_CLOSE; +} + +static int iParamToggleAction_CB(Ihandle *self, int v) +{ + Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM"); + Ihandle* dlg = IupGetDialog(self); + Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB"); + int old_v = iupAttribGetInt(param, "VALUE"); + + if (v == 1) + iupAttribSetStr(param, "VALUE", "1"); + else + iupAttribSetStr(param, "VALUE", "0"); + + if (cb && !cb(dlg, iupAttribGetInt(param, "INDEX"), (void*)iupAttribGet(dlg, "USER_DATA"))) + { + /* Undo */ + if (old_v == 1) + { + iupAttribSetStr(param, "VALUE", "1"); + IupSetAttribute(self, "VALUE", "1"); + } + else + { + iupAttribSetStr(param, "VALUE", "0"); + IupSetAttribute(self, "VALUE", "0"); + } + + /* there is no IUP_IGNORE for IupToggle */ + return IUP_DEFAULT; + } + + /* update the interface */ + if (v == 1) + IupStoreAttribute(self, "TITLE", iupAttribGet(param, "_IUPGP_TRUE")); + else + IupStoreAttribute(self, "TITLE", iupAttribGet(param, "_IUPGP_FALSE")); + + return IUP_DEFAULT; +} + +static int iParamTextAction_CB(Ihandle *self, int c, char *after) +{ + Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM"); + Ihandle* dlg = IupGetDialog(self); + Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB"); + Ihandle* aux = (Ihandle*)iupAttribGet(param, "AUXCONTROL"); + (void)c; + + iupAttribStoreStr(param, "VALUE", after); + + if (cb && !cb(dlg, iupAttribGetInt(param, "INDEX"), (void*)iupAttribGet(dlg, "USER_DATA"))) + { + /* Undo */ + iupAttribStoreStr(param, "VALUE", IupGetAttribute(self, "VALUE")); + return IUP_IGNORE; + } + + if (aux) + { + if (iupStrEqual(iupAttribGet(param, "TYPE"), "COLOR")) + IupStoreAttribute(aux, "BGCOLOR", after); + else + IupStoreAttribute(aux, "VALUE", after); + } + + if (IupGetInt(self, "SPIN")) + { + if (iupAttribGet(self, "_IUPGP_SPINREAL")) + { + float min = iupAttribGetFloat(param, "MIN"); + float step = iupAttribGetFloat(self, "_IUPGP_INCSTEP"); + float val; + if (iupStrToFloat(after, &val)) + IupSetfAttribute(self, "SPINVALUE", "%d", (int)((val-min)/step + 0.5)); + } + else + { + int val; + if (iupStrToInt(after, &val)) + IupSetfAttribute(self, "SPINVALUE", "%d", val); + } + } + + return IUP_DEFAULT; +} + +static int iParamValAction_CB(Ihandle *self) +{ + Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM"); + Ihandle* text = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_TEXT"); + Ihandle* dlg = IupGetDialog(self); + Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB"); + float old_value = iupAttribGetFloat(param, "VALUE"); + float val = IupGetFloat(self, "VALUE"); + + char* type = iupAttribGet(param, "TYPE"); + if (iupStrEqual(type, "INTEGER")) + { + iupAttribSetStrf(param, "VALUE", "%d", (int)val); + } + else + { + if (iupAttribGetInt(param, "ANGLE")) + { + float old_angle; + + if (val == 0) + { + old_angle = iupAttribGetFloat(param, "VALUE"); + iupAttribSetStrf(param, "_IUPGP_OLD_ANGLE", "%g", old_angle); + } + else + old_angle = iupAttribGetFloat(param, "_IUPGP_OLD_ANGLE"); + + val = old_angle + val*RAD2DEG; + + if (iupAttribGetInt(param, "INTERVAL")) + { + float min = iupAttribGetFloat(param, "MIN"); + float max = iupAttribGetFloat(param, "MAX"); + if (val < min) + val = min; + if (val > max) + val = max; + } + else if (iupAttribGetInt(param, "PARTIAL")) + { + float min = iupAttribGetFloat(param, "MIN"); + if (val < min) + val = min; + } + } + + iupAttribSetStrf(param, "VALUE", "%g", val); + } + + if (cb && !cb(dlg, iupAttribGetInt(param, "INDEX"), (void*)iupAttribGet(dlg, "USER_DATA"))) + { + /* Undo */ + iupAttribSetStrf(param, "VALUE", "%g", old_value); + + if (!iupAttribGetInt(param, "ANGLE")) + IupSetfAttribute(self, "VALUE", "%g", old_value); + + /* there is no IUP_IGNORE for IupVal */ + return IUP_DEFAULT; + } + + type = iupAttribGet(param, "TYPE"); + if (iupStrEqual(type, "INTEGER")) + IupSetfAttribute(text, "VALUE", "%d", (int)val); + else + IupSetfAttribute(text, "VALUE", "%g", val); + + if (IupGetInt(text, "SPIN")) + { + if (iupAttribGet(text, "_IUPGP_SPINREAL")) + { + float min = iupAttribGetFloat(param, "MIN"); + float step = iupAttribGetFloat(text, "_IUPGP_INCSTEP"); + float val = IupGetFloat(text, "VALUE"); + IupSetfAttribute(text, "SPINVALUE", "%d", (int)((val-min)/step + 0.5)); + } + else + { + int val = IupGetInt(text, "VALUE"); + IupSetfAttribute(text, "SPINVALUE", "%d", val); + } + } + + return IUP_DEFAULT; +} + +static int iParamListAction_CB(Ihandle *self, char *t, int i, int v) +{ + (void)t; + if (v == 1) + { + Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM"); + Ihandle* dlg = IupGetDialog(self); + Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB"); + int old_i = iupAttribGetInt(param, "VALUE"); + + iupAttribSetStrf(param, "VALUE", "%d", i-1); + + if (cb && !cb(dlg, iupAttribGetInt(param, "INDEX"), (void*)iupAttribGet(dlg, "USER_DATA"))) + { + /* Undo */ + iupAttribSetStrf(param, "VALUE", "%d", old_i); + IupSetfAttribute(self, "VALUE", "%d", old_i+1); + + /* there is no IUP_IGNORE for IupList */ + return IUP_DEFAULT; + } + } + + return IUP_DEFAULT; +} + +static int iParamFileButton_CB(Ihandle *self) +{ + Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM"); + Ihandle* textbox = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_TEXT"); + + Ihandle* dlg = IupFileDlg(); + + IupSetAttributeHandle(dlg, "PARENTDIALOG", IupGetDialog(self)); + IupSetAttribute(dlg, "TITLE", iupAttribGet(param, "TITLE")); + IupSetAttribute(dlg, "VALUE", iupAttribGet(param, "VALUE")); + + IupSetAttribute(dlg, "DIALOGTYPE", iupAttribGet(param, "_IUPGP_DIALOGTYPE")); + IupSetAttribute(dlg, "FILTER", iupAttribGet(param, "_IUPGP_FILTER")); + IupSetAttribute(dlg, "DIRECTORY", iupAttribGet(param, "_IUPGP_DIRECTORY")); + IupSetAttribute(dlg, "NOCHANGEDIR", iupAttribGet(param, "_IUPGP_NOCHANGEDIR")); + IupSetAttribute(dlg, "NOOVERWRITEPROMPT", iupAttribGet(param, "_IUPGP_NOOVERWRITEPROMPT")); + + IupPopup(dlg, IUP_CENTER, IUP_CENTER); + + if (IupGetInt(dlg, "STATUS") != -1) + { + IupSetAttribute(textbox, "VALUE", iupAttribGet(dlg, "VALUE")); + iupAttribStoreStr(param, "VALUE", iupAttribGet(dlg, "VALUE")); + } + + IupDestroy(dlg); + + return IUP_DEFAULT; +} + +static int iParamColorButton_CB(Ihandle *self, int button, int pressed) +{ + if (button==IUP_BUTTON1 && pressed) + { + Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM"); + Ihandle* textbox = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_TEXT"); + + Ihandle* dlg = IupColorDlg(); + + IupSetAttributeHandle(dlg, "PARENTDIALOG", IupGetDialog(self)); + IupSetAttribute(dlg, "TITLE", iupAttribGet(param, "TITLE")); + IupSetAttribute(dlg, "VALUE", iupAttribGet(param, "VALUE")); + + IupPopup(dlg, IUP_CENTER, IUP_CENTER); + + if (IupGetInt(dlg, "STATUS") != -1) + { + char* value = IupGetAttribute(dlg, "VALUE"); + IupSetAttribute(textbox, "VALUE", value); + iupAttribStoreStr(param, "VALUE", value); + IupStoreAttribute(self, "BGCOLOR", value); + } + + IupDestroy(dlg); + } + + return IUP_DEFAULT; +} + +static int iParamSpinReal_CB(Ihandle *self, int pos) +{ + Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM"); + Ihandle* dlg = IupGetDialog(self); + Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB"); + Ihandle* text = (Ihandle*)iupAttribGet(param, "CONTROL"); + float min = iupAttribGetFloat(param, "MIN"); + float max = iupAttribGetFloat(param, "MAX"); + float val, step = iupAttribGetFloat(text, "_IUPGP_INCSTEP"); + + /* here spin is always [0-spinmax] converted to [min-max] */ + val = (float)pos*step + min; + if (val < min) + val = min; + if (val > max) + val = max; + + iupAttribSetStrf(param, "VALUE", "%g", (double)val); + + if (cb) + { + int ret; + iupAttribSetStr(dlg, "SPINNING", "1"); + ret = cb(dlg, iupAttribGetInt(param, "INDEX"), (void*)iupAttribGet(dlg, "USER_DATA")); + iupAttribSetStr(dlg, "SPINNING", NULL); + if (!ret) + return IUP_IGNORE; + } + + IupSetfAttribute(text, "VALUE", "%g", (double)val); + + { + Ihandle* aux = (Ihandle*)iupAttribGet(param, "AUXCONTROL"); + if (aux) + IupSetfAttribute(aux, "VALUE", "%g", (double)val); + } + + return IUP_DEFAULT; +} + +static int iParamSpinInt_CB(Ihandle *self, int pos) +{ + Ihandle* param = (Ihandle*)iupAttribGetInherit(self, "_IUPGP_PARAM"); + Ihandle* dlg = IupGetDialog(self); + Iparamcb cb = (Iparamcb)IupGetCallback(dlg, "PARAM_CB"); + Ihandle* text = (Ihandle*)iupAttribGet(param, "CONTROL"); + + /* here spin is always [min-max] */ + + iupAttribSetInt(param, "VALUE", pos); + + if (cb) + { + int ret; + iupAttribSetStr(dlg, "SPINNING", "1"); + ret = cb(dlg, iupAttribGetInt(param, "INDEX"), (void*)iupAttribGet(dlg, "USER_DATA")); + iupAttribSetStr(dlg, "SPINNING", NULL); + if (!ret) + return IUP_IGNORE; + } + + IupSetfAttribute(text, "VALUE", "%g", (double)pos); + + { + Ihandle* aux = (Ihandle*)iupAttribGet(param, "AUXCONTROL"); + if (aux) + IupSetfAttribute(aux, "VALUE", "%g", (double)pos); + } + + return IUP_DEFAULT; +} + +/******************************************************************************************* + Creates One Parameter Box +*******************************************************************************************/ + +static Ihandle* iParamCreateBox(Ihandle* param) +{ + Ihandle *box, *ctrl = NULL, *label; + char *type; + + label = IupLabel(iupAttribGet(param, "TITLE")); + + type = iupAttribGet(param, "TYPE"); + if (iupStrEqual(type, "SEPARATOR")) + { + box = IupHbox(label, NULL); + IupSetAttribute(box,"ALIGNMENT","ACENTER"); + } + else + { + if (iupStrEqual(type, "STRING") && iupAttribGetInt(param, "MULTILINE")) + { + Ihandle* hbox1 = IupHbox(IupSetAttributes(IupFill(), "SIZE=5"), label, NULL); + IupSetAttribute(hbox1,"ALIGNMENT","ACENTER"); + + box = IupVbox(hbox1, NULL); + IupSetAttribute(box,"ALIGNMENT","ALEFT"); + } + else + { + box = IupHbox(IupSetAttributes(IupFill(), "SIZE=5"), label, NULL); + IupSetAttribute(box,"ALIGNMENT","ACENTER"); + } + } + + IupSetAttribute(box,"MARGIN","0x0"); + + type = iupAttribGet(param, "TYPE"); + if (iupStrEqual(type, "BOOLEAN")) + { + int value = iupAttribGetInt(param, "VALUE"); + if (value) + { + ctrl = IupToggle(iupAttribGet(param, "_IUPGP_TRUE"), NULL); + IupSetAttribute(ctrl, "VALUE", "ON"); + } + else + { + ctrl = IupToggle(iupAttribGet(param, "_IUPGP_FALSE"), NULL); + IupSetAttribute(ctrl, "VALUE", "OFF"); + } + IupSetCallback(ctrl, "ACTION", (Icallback)iParamToggleAction_CB); + + IupAppend(box, ctrl); + iupAttribSetStr(param, "DATA_TYPE", "1"); + } + else if (iupStrEqual(type, "SEPARATOR")) + { + ctrl = IupLabel(""); + IupSetAttribute(ctrl, "SEPARATOR", "HORIZONTAL"); + + IupAppend(box, ctrl); + iupAttribSetStr(param, "DATA_TYPE", "-1"); + } + else if (iupStrEqual(type, "LIST")) + { + char str[20] = "1"; + int i = 1; + ctrl = IupList(NULL); + IupSetCallback(ctrl, "ACTION", (Icallback)iParamListAction_CB); + IupSetAttribute(ctrl, "DROPDOWN", "YES"); + IupSetfAttribute(ctrl, "VALUE", "%d", iupAttribGetInt(param, "VALUE")+1); + + while (*iupAttribGet(param, str) != 0) + { + IupStoreAttribute(ctrl, str, iupAttribGet(param, str)); + i++; + sprintf(str, "%d", i); + } + IupStoreAttribute(ctrl, str, NULL); + + IupAppend(box, ctrl); + iupAttribSetStr(param, "DATA_TYPE", "1"); + } + else if (iupStrEqual(type, "STRING")) + { + if (iupAttribGetInt(param, "MULTILINE")) + { + Ihandle* hbox; + + ctrl = IupMultiLine(NULL); + IupSetAttribute(ctrl, "SIZE", "100x50"); + IupSetAttribute(ctrl, "EXPAND", "YES"); + + hbox = IupHbox(IupSetAttributes(IupFill(), "SIZE=5"), ctrl, NULL); + IupSetAttribute(hbox,"ALIGNMENT","ACENTER"); + + IupAppend(box, hbox); + } + else + { + ctrl = IupText(NULL); + IupSetAttribute(ctrl, "SIZE", "100x"); + IupSetAttribute(ctrl, "EXPAND", "HORIZONTAL"); + IupAppend(box, ctrl); + } + IupSetCallback(ctrl, "ACTION", (Icallback)iParamTextAction_CB); + IupStoreAttribute(ctrl, "VALUE", iupAttribGet(param, "VALUE")); + + { + char* mask = iupAttribGet(param, "MASK"); + if (mask) + IupStoreAttribute(ctrl, "MASK", mask); + } + + iupAttribSetStr(param, "DATA_TYPE", "0"); + iupAttribSetStr(param, "EXPAND", "1"); + } + else if (iupStrEqual(type, "FILE")) + { + Ihandle* aux; + + ctrl = IupText(NULL); + IupSetAttribute(ctrl, "SIZE", "100x"); + IupSetAttribute(ctrl, "EXPAND", "HORIZONTAL"); + IupAppend(box, ctrl); + + IupSetCallback(ctrl, "ACTION", (Icallback)iParamTextAction_CB); + IupStoreAttribute(ctrl, "VALUE", iupAttribGet(param, "VALUE")); + + iupAttribSetStr(param, "DATA_TYPE", "0"); + iupAttribSetStr(param, "EXPAND", "1"); + + + aux = IupButton("...", ""); + IupSetAttribute(aux, "EXPAND", "NO"); + + IupSetCallback(aux, "ACTION", (Icallback)iParamFileButton_CB); + iupAttribSetStr(aux, "_IUPGP_PARAM", (char*)param); + iupAttribSetStr(aux, "_IUPGP_TEXT", (char*)ctrl); + IupSetAttribute(aux, "EXPAND", "NO"); + + IupAppend(box, aux); + } + else if (iupStrEqual(type, "COLOR")) + { + Ihandle* aux; + + ctrl = IupText(NULL); + IupSetAttribute(ctrl, "SIZE", "100x"); + IupSetAttribute(ctrl, "EXPAND", "HORIZONTAL"); + IupAppend(box, ctrl); + + IupSetCallback(ctrl, "ACTION", (Icallback)iParamTextAction_CB); + IupSetAttribute(ctrl, "MASK", "(/d|/d/d|1/d/d|2(0|1|2|3|4)/d|25(0|1|2|3|4|5)) (/d|/d/d|1/d/d|2(0|1|2|3|4)/d|25(0|1|2|3|4|5)) (/d|/d/d|1/d/d|2(0|1|2|3|4)/d|25(0|1|2|3|4|5)) (/d|/d/d|1/d/d|2(0|1|2|3|4)/d|25(0|1|2|3|4|5))"); + IupStoreAttribute(ctrl, "VALUE", iupAttribGet(param, "VALUE")); + + iupAttribSetStr(param, "DATA_TYPE", "0"); + iupAttribSetStr(param, "EXPAND", "1"); + + + aux = IupCanvas(NULL); + IupSetAttribute(aux, "SIZE", "20x10"); + IupSetAttribute(aux, "EXPAND", "NO"); + IupStoreAttribute(aux, "BGCOLOR", iupAttribGet(param, "VALUE")); + + IupSetCallback(aux, "BUTTON_CB", (Icallback)iParamColorButton_CB); + iupAttribSetStr(param, "AUXCONTROL", (char*)aux); + iupAttribSetStr(aux, "_IUPGP_PARAM", (char*)param); + iupAttribSetStr(aux, "_IUPGP_TEXT", (char*)ctrl); + IupSetAttribute(aux, "EXPAND", "NO"); + + IupAppend(box, aux); + } + else /* INTEGER, REAL */ + { + ctrl = IupText(NULL); + IupSetCallback(ctrl, "ACTION", (Icallback)iParamTextAction_CB); + IupStoreAttribute(ctrl, "VALUE", iupAttribGet(param, "VALUE")); + + type = iupAttribGet(param, "TYPE"); + if (iupStrEqual(type, "REAL")) + { + if (iupAttribGetInt(param, "INTERVAL")) + { + float min = iupAttribGetFloat(param, "MIN"); + float max = iupAttribGetFloat(param, "MAX"); + float step = iupAttribGetFloat(param, "STEP"); + float val = iupAttribGetFloat(param, "VALUE"); + if (step == 0) step = (max-min)/20.0f; + IupSetfAttribute(ctrl, "MASKFLOAT", "%f:%f", (double)min, (double)max); + + /* here spin is always [0-spinmax] converted to [min-max] */ + + IupSetAttribute(ctrl, "SPIN", "YES"); /* spin only for intervals */ + IupSetAttribute(ctrl, "SPINAUTO", "NO"); + IupAppend(box, ctrl); + IupSetCallback(ctrl, "SPIN_CB", (Icallback)iParamSpinReal_CB); + /* SPINMIN=0 and SPININC=1 */ + IupSetfAttribute(ctrl, "SPINMAX", "%d", (int)((max-min)/step + 0.5)); + IupSetfAttribute(ctrl, "SPINVALUE", "%d", (int)((val-min)/step + 0.5)); + + iupAttribSetStrf(ctrl, "_IUPGP_INCSTEP", "%g", step); + iupAttribSetStr(ctrl, "_IUPGP_SPINREAL", "1"); + } + else if (iupAttribGetInt(param, "PARTIAL")) + { + float min = iupAttribGetFloat(param, "MIN"); + if (min == 0) + IupSetAttribute(ctrl, "MASK", IUP_MASK_UFLOAT); + else + IupSetfAttribute(ctrl, "MASKFLOAT", "%f:%f", (double)min, (double)1.0e10); + IupAppend(box, ctrl); + } + else + { + IupSetAttribute(ctrl, "MASK", IUP_MASK_FLOAT); + IupAppend(box, ctrl); + } + + iupAttribSetStr(param, "DATA_TYPE", "2"); + IupSetAttribute(ctrl, "SIZE", "50x"); + } + else /* INTEGER*/ + { + int val = iupAttribGetInt(param, "VALUE"); + IupSetAttribute(ctrl, "SPIN", "YES"); /* spin always */ + IupSetAttribute(ctrl, "SPINAUTO", "NO"); /* manually update spin so the callback can also updated it */ + IupAppend(box, ctrl); + IupSetCallback(ctrl, "SPIN_CB", (Icallback)iParamSpinInt_CB); + iupAttribSetStr(ctrl, "_IUPGP_INCSTEP", "1"); + IupSetfAttribute(ctrl, "SPINVALUE", "%d", val); + + /* here spin is always [min-max] */ + + if (iupAttribGetInt(param, "INTERVAL")) + { + int min = iupAttribGetInt(param, "MIN"); + int max = iupAttribGetInt(param, "MAX"); + int step = iupAttribGetInt(param, "STEP"); + if (step) + { + iupAttribSetStrf(ctrl, "_IUPGP_INCSTEP", "%d", step); + IupSetfAttribute(ctrl, "SPININC", "%d", step); + } + IupSetfAttribute(ctrl, "SPINMAX", "%d", max); + IupSetfAttribute(ctrl, "SPINMIN", "%d", min); + } + else if (iupAttribGetInt(param, "PARTIAL")) + { + int min = iupAttribGetInt(param, "MIN"); + if (min == 0) + IupSetAttribute(ctrl, "MASK", IUP_MASK_UINT); + else + IupSetfAttribute(ctrl, "MASKINT", "%d:2147483647", min); + IupSetfAttribute(ctrl, "SPINMIN", "%d", min); + IupSetAttribute(ctrl, "SPINMAX", "2147483647"); + } + else + { + IupSetAttribute(ctrl, "SPINMIN", "-2147483647"); + IupSetAttribute(ctrl, "SPINMAX", "2147483647"); + IupSetAttribute(ctrl, "MASK", IUP_MASK_INT); + } + + iupAttribSetStr(param, "DATA_TYPE", "1"); + IupSetAttribute(ctrl, "SIZE", "50x"); + } + + if (iupAttribGetInt(param, "INTERVAL") || iupAttribGetInt(param, "ANGLE")) + { + Ihandle* aux; + + if (iupAttribGetInt(param, "ANGLE")) + { + aux = IupCreatep("dial", "HORIZONTAL", NULL); + if (aux) + { + IupSetfAttribute(aux, "VALUE", "%g", (double)(iupAttribGetFloat(param, "VALUE")/RAD2DEG)); + IupSetAttribute(aux, "SIZE", "50x10"); + } + } + else + { + char* step; + aux = IupVal("HORIZONTAL"); + IupStoreAttribute(aux, "MIN", iupAttribGet(param, "MIN")); + IupStoreAttribute(aux, "MAX", iupAttribGet(param, "MAX")); + IupStoreAttribute(aux, "VALUE", iupAttribGet(param, "VALUE")); + IupSetAttribute(aux, "EXPAND", "HORIZONTAL"); + iupAttribSetStr(param, "AUXCONTROL", (char*)aux); + iupAttribSetStr(param, "EXPAND", "1"); + step = iupAttribGet(param, "STEP"); + if (step) + IupSetfAttribute(aux, "STEP", "%g", iupAttribGetFloat(param, "STEP")/(iupAttribGetFloat(param, "MAX")-iupAttribGetFloat(param, "MIN"))); + else if (iupStrEqual(type, "INTEGER")) + IupSetfAttribute(aux, "STEP", "%g", 1.0/(iupAttribGetFloat(param, "MAX")-iupAttribGetFloat(param, "MIN"))); + } + + if (aux) + { + IupSetCallback(aux, "VALUECHANGED_CB", (Icallback)iParamValAction_CB); + iupAttribSetStr(aux, "_IUPGP_PARAM", (char*)param); + iupAttribSetStr(aux, "_IUPGP_TEXT", (char*)ctrl); + + IupAppend(box, aux); + } + } + } + + if (ctrl) IupStoreAttribute(ctrl, "TIP", iupAttribGet(param, "TIP")); + iupAttribSetStr(box, "_IUPGP_PARAM", (char*)param); + iupAttribSetStr(param, "CONTROL", (char*)ctrl); + iupAttribSetStr(param, "LABEL", (char*)label); + return box; +} + +/******************************************************************************************* + Creates the Dialog and Normalize Sizes +*******************************************************************************************/ + +static Ihandle* IupParamDlgP(Ihandle** params) +{ + Ihandle *dlg, *button_ok, *button_cancel, + *dlg_box, *button_box, *param_box; + int i, lbl_width, p, expand; + + button_ok = IupButton("OK", NULL); + IupSetAttribute(button_ok, "PADDING", "20x0"); + IupSetCallback(button_ok, "ACTION", (Icallback)iParamButtonOK_CB); + + button_cancel = IupButton(iupStrMessageGet("IUP_CANCEL"), NULL); + IupSetAttribute(button_cancel, "PADDING", "20x0"); + IupSetCallback(button_cancel, "ACTION", (Icallback)iParamButtonCancel_CB); + + param_box = IupVbox(NULL); + + i = 0; expand = 0; + while (params[i] != NULL) + { + IupAppend(param_box, iParamCreateBox(params[i])); + + if (IupGetInt(params[i], "EXPAND")) + expand = 1; + + i++; + } + + button_box = IupHbox( + IupFill(), + button_ok, + button_cancel, + NULL); + IupSetAttribute(button_box,"MARGIN","0x0"); + IupSetAttribute(button_box, "NORMALIZESIZE", "HORIZONTAL"); + + dlg_box = IupVbox( + IupFrame(param_box), + button_box, + NULL); + IupSetAttribute(dlg_box, "MARGIN", "10x10"); + IupSetAttribute(dlg_box, "GAP", "5"); + + dlg = IupDialog(dlg_box); + + IupSetAttribute(dlg, "MINBOX", "NO"); + IupSetAttribute(dlg, "MAXBOX", "NO"); + if (!expand) + { + IupSetAttribute(dlg, "RESIZE", "NO"); + IupSetAttribute(dlg, "DIALOGFRAME", "YES"); + IupSetAttribute(dlg,"DIALOGHINT","YES"); + } + IupSetAttributeHandle(dlg, "DEFAULTENTER", button_ok); + IupSetAttributeHandle(dlg, "DEFAULTESC", button_cancel); + IupSetAttribute(dlg, "TITLE", "ParamDlg"); + IupSetAttribute(dlg, "PARENTDIALOG", IupGetGlobal("PARENTDIALOG")); + IupSetAttribute(dlg, "ICON", IupGetGlobal("ICON")); + iupAttribSetStr(dlg, "OK", (char*)button_ok); + iupAttribSetStr(dlg, "CANCEL", (char*)button_cancel); + + IupMap(dlg); + + /* get the largest label size and set INDEX */ + i = 0; lbl_width = 0, p = 0; + while (params[i] != NULL) + { + int w; + + char* type = iupAttribGet(params[i], "TYPE"); + if (!iupStrEqual(type, "SEPARATOR")) + { + char str[20]; + sprintf(str, "PARAM%d", p); + IupSetAttribute(dlg, str, (char*)params[i]); + iupAttribSetStrf(params[i], "INDEX", "%d", p); + p++; + } + + w = IupGetInt((Ihandle*)iupAttribGet(params[i], "LABEL"), "SIZE"); + if (w > lbl_width) + lbl_width = w; + + i++; + } + + i = 0; + while (params[i] != NULL) + { + char* type = iupAttribGet(params[i], "TYPE"); + if (!iupStrEqual(type, "SEPARATOR")) + { + if (iupStrEqual(type, "LIST")) + { + /* set a minimum size for lists */ + Ihandle* ctrl = (Ihandle*)iupAttribGet(params[i], "CONTROL"); + if (IupGetInt(ctrl, "SIZE") < 50) + IupSetAttribute(ctrl, "SIZE", "50x"); + } + else if (iupStrEqual(type, "BOOLEAN")) + { + /* reserve enough space for boolean strings */ + Ihandle* ctrl = (Ihandle*)iupAttribGet(params[i], "CONTROL"); + int wf = iupdrvFontGetStringWidth(ctrl, iupAttribGet(params[i], "_IUPGP_FALSE")); + int wt = iupdrvFontGetStringWidth(ctrl, iupAttribGet(params[i], "_IUPGP_TRUE")); + int w = IupGetInt(ctrl, "SIZE"); + int v = IupGetInt(ctrl, "VALUE"); + if (v) /* True */ + { + int box = w - wt; + wf += box; + if (wf > w) + IupSetfAttribute(ctrl, "SIZE", "%dx", wf+8); + } + else + { + int box = w - wf; + wt += box; + if (wt > w) + IupSetfAttribute(ctrl, "SIZE", "%dx", wt+8); + } + } + + IupSetfAttribute((Ihandle*)iupAttribGet(params[i], "LABEL"), "SIZE", "%dx", lbl_width); + } + + i++; + } + + IupSetAttribute(dlg, "SIZE", NULL); + + return dlg; +} + +/******************************************************************************************* + Parameter String Parsing +*******************************************************************************************/ + +static char* iParamGetNextStrItem(char* line, char sep, int *count) +{ + int i = 0; + + while (line[i] != '\n' && line[i] != 0) + { + if (line[i] == sep) + { + line[i] = 0; + *count = i+1; + return line; + } + + i++; + } + + /* last item may not have the separator */ + line[i] = 0; + *count = i; + return line; +} + +static void iParamSetBoolNames(char* extra, Ihandle* param) +{ + char *falsestr = NULL, *truestr = NULL; + int count; + + if (extra) + { + falsestr = iParamGetNextStrItem(extra, ',', &count); extra += count; + truestr = iParamGetNextStrItem(extra, ',', &count); + } + + if (falsestr && truestr) + { + iupAttribStoreStr(param, "_IUPGP_TRUE", truestr); + iupAttribStoreStr(param, "_IUPGP_FALSE", falsestr); + } + else + { +/* iupAttribStoreStr(param, "_IUPGP_TRUE", iupStrMessageGet("IUP_TRUE")); */ +/* iupAttribStoreStr(param, "_IUPGP_FALSE", iupStrMessageGet("IUP_FALSE")); */ + iupAttribStoreStr(param, "_IUPGP_TRUE", ""); + iupAttribStoreStr(param, "_IUPGP_FALSE", ""); + } +} + +static void iParamSetInterval(char* extra, Ihandle* param) +{ + char *min, *max, *step; + int count; + + if (!extra) + return; + + min = iParamGetNextStrItem(extra, ',', &count); extra += count; + max = iParamGetNextStrItem(extra, ',', &count); extra += count; + step = iParamGetNextStrItem(extra, ',', &count); + + if (max[0]) + { + iupAttribSetStr(param, "INTERVAL", "1"); + iupAttribStoreStr(param, "MIN", min); + iupAttribStoreStr(param, "MAX", max); + if (step[0]) + iupAttribStoreStr(param, "STEP", step); + } + else + { + iupAttribSetStr(param, "PARTIAL", "1"); + iupAttribStoreStr(param, "MIN", min); + } +} + +static void iParamSetFileOptions(char* extra, Ihandle* param) +{ + char *type, *filter, *directory, *nochangedir, *nooverwriteprompt; + int count; + + if (!extra) + return; + + type = iParamGetNextStrItem(extra, '|', &count); extra += count; + filter = iParamGetNextStrItem(extra, '|', &count); extra += count; + directory = iParamGetNextStrItem(extra, '|', &count); extra += count; + nochangedir = iParamGetNextStrItem(extra, '|', &count); extra += count; + nooverwriteprompt = iParamGetNextStrItem(extra, '|', &count); extra += count; + + iupAttribStoreStr(param, "_IUPGP_DIALOGTYPE", type); + iupAttribStoreStr(param, "_IUPGP_FILTER", filter); + iupAttribStoreStr(param, "_IUPGP_DIRECTORY", directory); + iupAttribStoreStr(param, "_IUPGP_NOCHANGEDIR", nochangedir); + iupAttribStoreStr(param, "_IUPGP_NOOVERWRITEPROMPT", nooverwriteprompt); +} + +static void iParamSetListItems(char* extra, Ihandle* param) +{ + int d = 1, count; + char str[20], *item; + + if (!extra) + return; + + item = iParamGetNextStrItem(extra, '|', &count); extra += count; + while (*item) + { + sprintf(str, "%d", d); + iupAttribStoreStr(param, str, item); + + item = iParamGetNextStrItem(extra, '|', &count); extra += count; + d++; + } + + sprintf(str, "%d", d); + iupAttribSetStr(param, str, ""); +} + +static char* iParamGetStrExtra(char* line, char start, char end, int *count) +{ + int i = 0, end_pos = -1; + + if (*line != start) + { + *count = 0; + return NULL; + } + line++; /* skip start */ + + while (line[i] != '\n' && line[i] != 0) + { + if (line[i] == end) + end_pos = i; + + i++; + } + + if (end_pos != -1) + { + line[end_pos] = 0; + *count = 1+end_pos+1; + return line; + } + else + { + *count = 0; + return NULL; + } +} + +static int iParamCopyStrLine(char* line, const char* format) +{ + int i = 0; + while (format[i] != '\n' && format[i] != 0) + { + line[i] = format[i]; + i++; + if (i > 4094) /* to avoid being bigger than the local array */ + break; + } + line[i] = '\n'; + line[i+1] = 0; + return i+1; +} + +char iupGetParamType(const char* format, int *line_size) +{ + char* type = strchr(format, '%'); + char* line_end = strchr(format, '\n'); + if (line_end) + *line_size = line_end-format+1; + if (type) + return *(type+1); + else + return 0; +} + +static Ihandle *IupParamf(const char* format, int *line_size) +{ + Ihandle* param; + char line[4096]; + char* line_ptr = &line[0], *title, type, *tip, *extra, *mask; + int count; + + *line_size = iParamCopyStrLine(line, format); + + title = iParamGetNextStrItem(line_ptr, '%', &count); line_ptr += count; + param = IupUser(); + iupAttribStoreStr(param, "TITLE", title); + + type = *line_ptr; + line_ptr++; + + switch(type) + { + case 'b': + iupAttribSetStr(param, "TYPE", "BOOLEAN"); + iupAttribSetStr(param, "DATA_TYPE", "1"); /* integer */ + extra = iParamGetStrExtra(line_ptr, '[', ']', &count); line_ptr += count; + iParamSetBoolNames(extra, param); + break; + case 'l': + iupAttribSetStr(param, "TYPE", "LIST"); + iupAttribSetStr(param, "DATA_TYPE", "1"); /* integer */ + extra = iParamGetStrExtra(line_ptr, '|', '|', &count); line_ptr += count; + iParamSetListItems(extra, param); + break; + case 'a': + iupAttribSetStr(param, "TYPE", "REAL"); + iupAttribSetStr(param, "DATA_TYPE", "2"); /* real */ + iupAttribSetStr(param, "ANGLE", "1"); + extra = iParamGetStrExtra(line_ptr, '[', ']', &count); line_ptr += count; + iParamSetInterval(extra, param); + break; + case 'm': + iupAttribSetStr(param, "MULTILINE", "1"); + /* continue */ + case 's': + iupAttribSetStr(param, "TYPE", "STRING"); + iupAttribSetStr(param, "DATA_TYPE", "0"); /* string */ + mask = iParamGetNextStrItem(line_ptr, '{', &count); + if (*mask) + iupAttribStoreStr(param, "MASK", mask); + line_ptr += count-1; /* ignore the fake separator */ + line_ptr[0] = '{'; /* restore possible separator */ + break; + case 'i': + iupAttribSetStr(param, "TYPE", "INTEGER"); + iupAttribSetStr(param, "DATA_TYPE", "1"); /* integer */ + extra = iParamGetStrExtra(line_ptr, '[', ']', &count); line_ptr += count; + iParamSetInterval(extra, param); + break; + case 'r': + iupAttribSetStr(param, "TYPE", "REAL"); + iupAttribSetStr(param, "DATA_TYPE", "2"); /* real */ + extra = iParamGetStrExtra(line_ptr, '[', ']', &count); line_ptr += count; + iParamSetInterval(extra, param); + break; + case 'f': + iupAttribSetStr(param, "TYPE", "FILE"); + iupAttribSetStr(param, "DATA_TYPE", "0"); /* string */ + extra = iParamGetStrExtra(line_ptr, '[', ']', &count); line_ptr += count; + iParamSetFileOptions(extra, param); + break; + case 'c': + iupAttribSetStr(param, "TYPE", "COLOR"); + iupAttribSetStr(param, "DATA_TYPE", "0"); /* string */ + break; + case 't': + iupAttribSetStr(param, "TYPE", "SEPARATOR"); + iupAttribSetStr(param, "DATA_TYPE", "-1"); /* NONE */ + break; + default: + return NULL; + } + + tip = iParamGetStrExtra(line_ptr, '{', '}', &count); + if (tip) + iupAttribStoreStr(param, "TIP", tip); + + return param; +} + +/******************************************************************************************* + Exported Functions +*******************************************************************************************/ + +int iupGetParamCount(const char *format, int *param_extra) +{ + int param_count = 0, sep = 0; + const char* s = format; + + *param_extra = 0; + while(*s) + { + if (*s == '%' && *(s+1) == 't') /* do not count separator lines */ + { + sep = 1; + (*param_extra)++; + } + + if (*s == '\n') + { + if (sep) + sep = 0; + else + param_count++; + } + + s++; + } + + return param_count; +} + +static void iParamDestroyAll(Ihandle **params) +{ + int i = 0; + while (params[i] != NULL) + { + IupDestroy(params[i]); + i++; + } +} + +int IupGetParamv(const char* title, Iparamcb action, void* user_data, const char* format, int param_count, int param_extra, void** param_data) +{ + Ihandle *dlg, *params[50]; + int i, line_size, p; + + assert(title && format); + if (!title || !format) + return 0; + + for (i = 0, p = 0; i < param_count+param_extra; i++) + { + int data_type; + + params[i] = IupParamf(format, &line_size); + assert(params[i]); + if (!params[i]) + return 0; + + data_type = IupGetInt(params[i], "DATA_TYPE"); + if (data_type == 1) + { + int *data_int = (int*)(param_data[p]); + if (!data_int) return 0; + iupAttribSetStrf(params[i], "VALUE", "%d", *data_int); + p++; + } + else if (data_type == 2) + { + float *data_float = (float*)(param_data[p]); + if (!data_float) return 0; + iupAttribSetStrf(params[i], "VALUE", "%g", *data_float); + p++; + } + else if (data_type == 0) + { + char *data_str = (char*)(param_data[p]); + if (!data_str) return 0; + iupAttribStoreStr(params[i], "VALUE", data_str); + p++; + } + + format += line_size; + } + params[i] = NULL; + + dlg = IupParamDlgP(params); + IupSetAttribute(dlg, "TITLE", (char*)title); + IupSetCallback(dlg, "PARAM_CB", (Icallback)action); + iupAttribSetStr(dlg, "USER_DATA", (char*)user_data); + + if (action) + action(dlg, -2, user_data); + + IupPopup(dlg, IUP_CENTERPARENT, IUP_CENTERPARENT); + + if (!IupGetInt(dlg, "STATUS")) + { + iParamDestroyAll(params); + IupDestroy(dlg); + return 0; + } + else + { + for (i = 0, p = 0; i < param_count; i++) + { + Ihandle* param; + int data_type; + char str[20]; + + sprintf(str, "PARAM%d", i); + param = (Ihandle*)iupAttribGet(dlg, str); + + data_type = iupAttribGetInt(param, "DATA_TYPE"); + if (data_type == 1) + { + int *data_int = (int*)(param_data[i]); + *data_int = iupAttribGetInt(param, "VALUE"); + p++; + } + else if (data_type == 2) + { + float *data_float = (float*)(param_data[i]); + *data_float = iupAttribGetFloat(param, "VALUE"); + p++; + } + else + { + char *data_str = (char*)(param_data[i]); + strcpy(data_str, iupAttribGet(param, "VALUE")); + p++; + } + } + + iParamDestroyAll(params); + IupDestroy(dlg); + return 1; + } +} + +int IupGetParam(const char* title, Iparamcb action, void* user_data, const char* format,...) +{ + int param_count, param_extra, i; + void* param_data[50]; + va_list arg; + + param_count = iupGetParamCount(format, ¶m_extra); + + va_start(arg, format); + for (i = 0; i < param_count; i++) + { + param_data[i] = (void*)(va_arg(arg, void*)); + } + va_end(arg); + + return IupGetParamv(title, action, user_data, format, param_count, param_extra, param_data); +} + diff --git a/iup/src/iup_globalattrib.c b/iup/src/iup_globalattrib.c new file mode 100755 index 0000000..00586fb --- /dev/null +++ b/iup/src/iup_globalattrib.c @@ -0,0 +1,153 @@ +/** \file + * \brief global attributes enviroment + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "iup.h" + +#include "iup_table.h" +#include "iup_globalattrib.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_assert.h" +#include "iup_str.h" + + +static Itable *iglobal_table = NULL; + +void iupGlobalAttribInit(void) +{ + iglobal_table = iupTableCreate(IUPTABLE_STRINGINDEXED); +} + +void iupGlobalAttribFinish(void) +{ + iupTableDestroy(iglobal_table); + iglobal_table = NULL; +} + +static int iGlobalChangingDefaultColor(const char *name) +{ + if (iupStrEqual(name, "DLGBGCOLOR") || + iupStrEqual(name, "DLGFGCOLOR") || + iupStrEqual(name, "MENUBGCOLOR") || + iupStrEqual(name, "MENUFGCOLOR") || + iupStrEqual(name, "TXTBGCOLOR") || + iupStrEqual(name, "TXTFGCOLOR")) + { + char str[50] = "_IUP_USER_DEFAULT_"; + strcat(str, name); + iupTableSet(iglobal_table, str, (void*)"1", IUPTABLE_POINTER); /* mark as changed by the User */ + return 1; + } + return 0; +} + +int iupGlobalDefaultColorChanged(const char *name) +{ + char str[50] = "_IUP_USER_DEFAULT_"; + strcat(str, name); + return iupTableGet(iglobal_table, str) != NULL; +} + +void iupGlobalSetDefaultColorAttrib(const char* name, int r, int g, int b) +{ + if (!iupGlobalDefaultColorChanged(name)) + { + char value[50]; + sprintf(value, "%3d %3d %3d", r, g, b); + iupTableSet(iglobal_table, name, (void*)value, IUPTABLE_STRING); + } +} + +void IupSetGlobal(const char *name, const char *value) +{ + iupASSERT(name!=NULL); + if (!name) return; + + if (iupStrEqual(name, "DEFAULTFONTSIZE")) + { + iupSetDefaultFontSizeGlobalAttrib(value); + return; + } + + if (iGlobalChangingDefaultColor(name) || iupdrvSetGlobal(name, value)) + { + if (!value) + iupTableRemove(iglobal_table, name); + else + iupTableSet(iglobal_table, name, (void*)value, IUPTABLE_POINTER); + } +} + +void IupStoreGlobal(const char *name, const char *value) +{ + iupASSERT(name!=NULL); + if (!name) return; + + if (iupStrEqual(name, "DEFAULTFONTSIZE")) + { + iupSetDefaultFontSizeGlobalAttrib(value); + return; + } + + if (iGlobalChangingDefaultColor(name) || iupdrvSetGlobal(name, value)) + { + if (!value) + iupTableRemove(iglobal_table, name); + else + iupTableSet(iglobal_table, name, (void*)value, IUPTABLE_STRING); + } +} + +char *IupGetGlobal(const char *name) +{ + char* value; + + iupASSERT(name!=NULL); + if (!name) + return NULL; + + if (iupStrEqual(name, "DEFAULTFONTSIZE")) + return iupGetDefaultFontSizeGlobalAttrib(); + + value = iupdrvGetGlobal(name); + + if (!value) + value = (char*)iupTableGet(iglobal_table, name); + + return value; +} + +int iupGlobalIsPointer(const char* name) +{ + static struct { + const char *name; + } ptr_table[] = { +#ifdef WIN32 + {"HINSTANCE"}, +#else + {"XDISPLAY"}, + {"XSCREEN"}, + {"APPSHELL"}, +#endif + }; +#define PTR_TABLE_SIZE ((sizeof ptr_table)/(sizeof ptr_table[0])) + + if (name) + { + int i; + for (i = 0; i < PTR_TABLE_SIZE; i++) + { + if (iupStrEqualNoCase(name, ptr_table[i].name)) + return 1; + } + } + + return 0; +} diff --git a/iup/src/iup_globalattrib.h b/iup/src/iup_globalattrib.h new file mode 100755 index 0000000..706a6ac --- /dev/null +++ b/iup/src/iup_globalattrib.h @@ -0,0 +1,33 @@ +/** \file + * \brief global attributes enviroment + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_GLOBALATTRIB_H +#define __IUP_GLOBALATTRIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* called only in IupOpen and IupClose */ +void iupGlobalAttribInit(void); +void iupGlobalAttribFinish(void); + +int iupGlobalIsPointer(const char* name); + +int iupGlobalDefaultColorChanged(const char *name); /* check if user changed */ +void iupGlobalSetDefaultColorAttrib(const char* name, int r, int g, int b); /* internal change method */ + +/* Other functions declared in <iup.h> and implemented here. +IupSetGlobal +IupStoreGlobal +IupGetGlobal +*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_hbox.c b/iup/src/iup_hbox.c new file mode 100755 index 0000000..e790636 --- /dev/null +++ b/iup/src/iup_hbox.c @@ -0,0 +1,309 @@ +/** \file + * \brief Hbox Control. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" +#include "iup_box.h" + + +static int iHboxSetRasterSizeAttrib(Ihandle* ih, const char* value) +{ + if (!value) + { + ih->userwidth = 0; + ih->userheight = 0; + } + else + { + int s = 0; + iupStrToInt(value, &s); + if (s > 0) + { + ih->userheight = 0; + ih->userwidth = s; + } + } + iupAttribSetStr(ih, "SIZE", NULL); /* clear SIZE in hash table */ + return 0; +} + +static int iHboxSetSizeAttrib(Ihandle* ih, const char* value) +{ + if (!value) + { + ih->userwidth = 0; + ih->userheight = 0; + } + else + { + int s = 0; + iupStrToInt(value, &s); + if (s > 0) + { + int charwidth, charheight; + iupdrvFontGetCharSize(ih, &charwidth, &charheight); + ih->userheight = 0; + ih->userwidth = iupWIDTH2RASTER(s, charwidth); + } + } + return 1; +} + +static int iHboxSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "ABOTTOM")) + ih->data->alignment = IUP_ALIGN_ABOTTOM; + else if (iupStrEqualNoCase(value, "ACENTER")) + ih->data->alignment = IUP_ALIGN_ACENTER; + else if (iupStrEqualNoCase(value, "ATOP")) + ih->data->alignment = IUP_ALIGN_ATOP; + return 0; +} + +static char* iHboxGetAlignmentAttrib(Ihandle* ih) +{ + static char* align2str[3] = {"ATOP", "ACENTER", "ABOTTOM"}; + return align2str[ih->data->alignment]; +} + +static void iHboxComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + Ihandle* child; + int children_naturalwidth, children_naturalheight; + + /* calculate total children natural size */ + int children_expand = 0; + int children_count = 0; + int children_natural_totalwidth = 0; + int children_natural_maxwidth = 0; + int children_natural_maxheight = 0; + + for (child = ih->firstchild; child; child = child->brother) + { + /* update child natural size first */ + iupBaseComputeNaturalSize(child); + + if (!child->is_floating) + { + children_expand |= child->expand; + children_natural_maxwidth = iupMAX(children_natural_maxwidth, child->naturalwidth); + children_natural_maxheight = iupMAX(children_natural_maxheight, child->naturalheight); + children_count++; + } + } + + /* reset to max natural width and/or height if NORMALIZESIZE is defined */ + if (ih->data->normalize_size) + iupNormalizeSizeBoxChild(ih, ih->data->normalize_size, children_natural_maxwidth, children_natural_maxheight); + + for (child = ih->firstchild; child; child = child->brother) + { + if (!child->is_floating) + children_natural_totalwidth += child->naturalwidth; + } + + /* leave room at the element for the maximum natural size of the children when is_homogeneous */ + if (ih->data->is_homogeneous) + children_natural_totalwidth = children_natural_maxwidth*children_count; + + /* compute the Hbox contents natural size */ + children_naturalwidth = children_natural_totalwidth + (children_count-1)*ih->data->gap + 2*ih->data->margin_x; + children_naturalheight = children_natural_maxheight + 2*ih->data->margin_y; + + /* Store to be used in iHboxCalcEmptyWidth */ + ih->data->children_naturalsize = children_naturalwidth; + + *expand = children_expand; + *w = children_naturalwidth; + *h = children_naturalheight; +} + +static int iHboxCalcHomogeneousWidth(Ihandle *ih) +{ + Ihandle* child; + int homogeneous_width; + + int children_count=0; + for (child = ih->firstchild; child; child = child->brother) + { + if (!child->is_floating) + children_count++; + } + if (children_count == 0) + return 0; + + /* equal spaces for all elements */ + homogeneous_width = (ih->currentwidth - (children_count-1)*ih->data->gap - 2*ih->data->margin_x)/children_count; + if (homogeneous_width<0) homogeneous_width = 0; + return homogeneous_width; +} + +static int iHboxCalcEmptyWidth(Ihandle *ih, int expand) +{ + /* This is the space that the child can be expanded. */ + Ihandle* child; + int empty_width; + + int expand_count=0; + for (child = ih->firstchild; child; child = child->brother) + { + if (!child->is_floating && child->expand & expand) + expand_count++; + } + if (expand_count == 0) + return 0; + + /* equal spaces for all expandable elements */ + empty_width = (ih->currentwidth - ih->data->children_naturalsize)/expand_count; + if (empty_width < 0) empty_width = 0; + return empty_width; +} + +static void iHboxSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink) +{ + /* update children */ + Ihandle* child; + int empty_w0 = 0, empty_w1 = 0, client_height; + + if (ih->data->expand_children) + ih->expand |= ih->data->expand_children; + + if (ih->data->is_homogeneous) + ih->data->homogeneous_size = iHboxCalcHomogeneousWidth(ih); + else + { + ih->data->homogeneous_size = 0; + + /* must calculate the space left for each control to grow inside the container */ + /* W1 means there is an EXPAND enabled inside */ + if (ih->expand & IUP_EXPAND_W1) + empty_w1 = iHboxCalcEmptyWidth(ih, IUP_EXPAND_W1); + /* Not W1 and W0 means that EXPAND is not enabled but there are some IupFill inside */ + else if (ih->expand & IUP_EXPAND_W0) + empty_w0 = iHboxCalcEmptyWidth(ih, IUP_EXPAND_W0); + } + + client_height = ih->currentheight - 2*ih->data->margin_y; + if (client_height<0) client_height=0; + + for (child = ih->firstchild; child; child = child->brother) + { + if (!child->is_floating) + { + int old_expand = child->expand; + if (ih->data->expand_children) + child->expand |= ih->data->expand_children; + + if (ih->data->homogeneous_size) + iupBaseSetCurrentSize(child, ih->data->homogeneous_size, client_height, shrink); + else + { + int empty = (child->expand & IUP_EXPAND_W1)? empty_w1: ((child->expand & IUP_EXPAND_W0)? empty_w0: 0); + iupBaseSetCurrentSize(child, child->naturalwidth+empty, client_height, shrink); + } + + if (ih->data->expand_children) + child->expand = old_expand; + } + else + { + /* update children to their own natural size */ + iupBaseSetCurrentSize(child, child->naturalwidth, child->naturalheight, shrink); + } + } +} + +static void iHboxSetChildrenPositionMethod(Ihandle* ih, int x, int y) +{ + int dy, client_height; + Ihandle* child; + + x += ih->data->margin_x; + y += ih->data->margin_y; + + client_height = ih->currentheight - 2*ih->data->margin_y; + if (client_height<0) client_height=0; + + for (child = ih->firstchild; child; child = child->brother) + { + if (!child->is_floating) + { + if (ih->data->alignment == IUP_ALIGN_ACENTER) + dy = (client_height - child->currentheight)/2; + else if (ih->data->alignment == IUP_ALIGN_ABOTTOM) + dy = client_height - child->currentheight; + else /* IUP_ALIGN_ATOP */ + dy = 0; + if (dy<0) dy = 0; + + /* update child */ + iupBaseSetPosition(child, x, y+dy); + + /* calculate next */ + if (ih->data->homogeneous_size) + x += ih->data->homogeneous_size + ih->data->gap; + else + x += child->currentwidth + ih->data->gap; + } + } +} + + +/******************************************************************************/ + + +Ihandle *IupHboxv(Ihandle **children) +{ + return IupCreatev("hbox", (void**)children); +} + +Ihandle *IupHbox(Ihandle* child, ...) +{ + Ihandle **children; + Ihandle *ih; + + va_list arglist; + va_start(arglist, child); + children = (Ihandle **)iupObjectGetParamList(child, arglist); + va_end(arglist); + + ih = IupCreatev("hbox", (void**)children); + free(children); + + return ih; +} + +Iclass* iupHboxGetClass(void) +{ + Iclass* ic = iupBoxClassBase(); + + ic->name = "hbox"; + + /* Class functions */ + ic->ComputeNaturalSize = iHboxComputeNaturalSizeMethod; + ic->SetChildrenCurrentSize = iHboxSetChildrenCurrentSizeMethod; + ic->SetChildrenPosition = iHboxSetChildrenPositionMethod; + + /* Overwrite Common */ + iupClassRegisterAttribute(ic, "SIZE", iupBaseGetSizeAttrib, iHboxSetSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "RASTERSIZE", iupBaseGetRasterSizeAttrib, iHboxSetRasterSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* Hbox only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", iHboxGetAlignmentAttrib, iHboxSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ATOP", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} diff --git a/iup/src/iup_image.c b/iup/src/iup_image.c new file mode 100755 index 0000000..12b1169 --- /dev/null +++ b/iup/src/iup_image.c @@ -0,0 +1,1017 @@ +/** \file + * \brief Image Resource. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <memory.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_image.h" +#include "iup_assert.h" +#include "iup_stdcontrols.h" + + +typedef struct _IimageStock +{ + iupImageStockCreateFunc func; + Ihandle* image; /* cache image */ + const char* native_name; /* used to map to GTK stock images */ +} IimageStock; + +static Itable *istock_table = NULL; /* the function hast table indexed by the name string */ + +void iupImageStockInit(void) +{ + istock_table = iupTableCreate(IUPTABLE_STRINGINDEXED); +} + +void iupImageStockFinish(void) +{ + char* name = iupTableFirst(istock_table); + while (name) + { + IimageStock* istock = (IimageStock*)iupTableGetCurr(istock_table); + if (iupObjectCheck(istock->image)) + IupDestroy(istock->image); + free(istock); + name = iupTableNext(istock_table); + } + + iupTableDestroy(istock_table); + istock_table = NULL; +} + +void iupImageStockSet(const char *name, iupImageStockCreateFunc func, const char* native_name) +{ + IimageStock* istock = (IimageStock*)iupTableGet(istock_table, name); + if (istock) + free(istock); /* overwrite a previous registration */ + + istock = (IimageStock*)malloc(sizeof(IimageStock)); + istock->func = func; + istock->image = NULL; + istock->native_name = native_name; + + iupTableSet(istock_table, name, (void*)istock, IUPTABLE_POINTER); +} + +static void iImageStockGet(const char* name, Ihandle* *ih, const char* *native_name) +{ + IimageStock* istock = (IimageStock*)iupTableGet(istock_table, name); + if (istock) + { + if (istock->image) + *ih = istock->image; + else if (istock->native_name) + *native_name = istock->native_name; + else if (istock->func) + { + istock->image = istock->func(); + *ih = istock->image; + } + } +} + +void iupImageStockLoad(const char *name) +{ + /* Used only in iupImageLibLoadAll */ + const char* native_name = NULL; + Ihandle* ih = NULL; + iImageStockGet(name, &ih, &native_name); + if (ih) + IupSetHandle(name, ih); + else if (native_name) + { + /* dummy image to save the GTK stock name */ + void* handle = iupdrvImageLoad(native_name, IUPIMAGE_IMAGE); + if (handle) + { + int w, h, bpp; + iupdrvImageGetInfo(handle, &w, &h, &bpp); + if (bpp == 32) + ih = IupImageRGBA(w,h,NULL); + else + ih = IupImageRGB(w,h,NULL); + IupSetHandle(native_name, ih); + } + } +} + + +/**************************************************************************************************/ +/**************************************************************************************************/ + + +int iupImageNormBpp(int bpp) +{ + if (bpp <= 8) return 8; + if (bpp <= 24) return 24; + return 32; +} + +static void iupColorSet(iupColor *c, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + c->r = r; + c->g = g; + c->b = b; + c->a = a; +} + +int iupImageInitColorTable(Ihandle *ih, iupColor* colors, int *colors_count) +{ + char attr[6], *value; + unsigned char red, green, blue; + int i, has_alpha = 0; + static iupColor default_colors[] = { + { 0,0,0,255 }, { 128,0,0,255 }, { 0,128,0,255 }, { 128,128,0,255 }, + { 0,0,128,255 }, { 128,0,128,255 }, { 0,128,128,255 }, { 192,192,192,255 }, + { 128,128,128,255 }, { 255,0,0,255 }, { 0,255,0,255 }, { 255,255,0,255 }, + { 0,0,255,255 }, { 255,0,255,255 }, { 0,255,255,255 }, { 255,255,255,255 } }; + + memset(colors, 0, sizeof(iupColor)*256); + + for (i=0;i<16;i++) + { + sprintf(attr, "%d", i); + value = iupAttribGet(ih, attr); + + if (value) + { + if (iupStrEqual(value, "BGCOLOR")) + { + iupColorSet(&colors[i], 0, 0, 0, 0); + has_alpha = 1; + } + else + { + if (!iupStrToRGB(value, &red, &green, &blue)) + iupColorSet(&colors[i], default_colors[i].r, default_colors[i].g, default_colors[i].b, 255); + else + iupColorSet(&colors[i], red, green, blue, 255); + } + } + else + { + iupColorSet(&colors[i], default_colors[i].r, default_colors[i].g, default_colors[i].b, 255); + } + } + + for (;i<256;i++) + { + sprintf(attr, "%d", i); + value = iupAttribGet(ih, attr); + if (!value) + break; + + if (iupStrEqual(value, "BGCOLOR")) + { + iupColorSet(&colors[i], 0, 0, 0, 0); + has_alpha = 1; + } + else + { + if (!iupStrToRGB(value, &red, &green, &blue)) + break; + + iupColorSet(&colors[i], red, green, blue, 255); + } + } + + if (colors_count) *colors_count = i; + + return has_alpha; +} + +void iupImageInitNonBgColors(Ihandle* ih, unsigned char *colors) +{ + char attr[6], *value; + int i; + + memset(colors, 0, 256); + + for (i=0;i<16;i++) + { + sprintf(attr, "%d", i); + value = iupAttribGet(ih, attr); + if (!iupStrEqual(value, "BGCOLOR")) + colors[i] = 1; + } + + for (;i<256;i++) + { + sprintf(attr, "%d", i); + value = iupAttribGet(ih, attr); + if (!value) + break; + + if (!iupStrEqual(value, "BGCOLOR")) + colors[i] = 1; + } +} + +void iupImageColorMakeInactive(unsigned char *r, unsigned char *g, unsigned char *b, unsigned char bg_r, unsigned char bg_g, unsigned char bg_b) +{ + if (*r==bg_r && *g==bg_g && *b==bg_b) /* preserve colors identical to the background color */ + { + *r = bg_r; + *g = bg_g; + *b = bg_b; + } + else + { + int ir = 0, ig = 0, ib = 0, + i = (*r+*g+*b)/3, + bg_i = (bg_r+bg_g+bg_b)/3; + + if (bg_i) + { + ir = (bg_r*i)/bg_i; + ig = (bg_g*i)/bg_i; + ib = (bg_b*i)/bg_i; + } + +#define LIGHTER(_c) ((255 + _c)/2) + ir = LIGHTER(ir); + ig = LIGHTER(ig); + ib = LIGHTER(ib); + + *r = iupBYTECROP(ir); + *g = iupBYTECROP(ig); + *b = iupBYTECROP(ib); + } +} + + +/**************************************************************************************************/ +/**************************************************************************************************/ + + +void* iupImageGetMask(const char* name) +{ + void* mask; + Ihandle *ih; + + if (!name) + return NULL; + + /* get handle from name */ + ih = IupGetHandle(name); + if (!ih) + return NULL; + + /* Check for an already created icon */ + mask = iupAttribGet(ih, "_IUPIMAGE_MASK"); + if (mask) + return mask; + + /* Not created, tries to create the mask */ + mask = iupdrvImageCreateMask(ih); + + /* save the pixbuf */ + iupAttribSetStr(ih, "_IUPIMAGE_MASK", (char*)mask); + + return mask; +} + +void* iupImageGetIcon(const char* name) +{ + void* icon; + Ihandle *ih; + + if (!name) + return NULL; + + /* Check first in the system resources. */ + icon = iupdrvImageLoad(name, IUPIMAGE_ICON); + if (icon) + return icon; + + /* get handle from name */ + ih = IupGetHandle(name); + if (!ih) + return NULL; + + /* Check for an already created icon */ + icon = iupAttribGet(ih, "_IUPIMAGE_ICON"); + if (icon) + return icon; + + /* Not created, tries to create the icon */ + icon = iupdrvImageCreateIcon(ih); + + /* save the pixbuf */ + iupAttribSetStr(ih, "_IUPIMAGE_ICON", (char*)icon); + + return icon; +} + +void* iupImageGetCursor(const char* name) +{ + void* cursor; + Ihandle *ih; + + if (!name) + return NULL; + + /* Check first in the system resources. */ + cursor = iupdrvImageLoad(name, IUPIMAGE_CURSOR); + if (cursor) + return cursor; + + /* get handle from name */ + ih = IupGetHandle(name); + if (!ih) + return NULL; + + /* Check for an already created cursor */ + cursor = iupAttribGet(ih, "_IUPIMAGE_CURSOR"); + if (cursor) + return cursor; + + /* Not created, tries to create the cursor */ + cursor = iupdrvImageCreateCursor(ih); + + /* save the pixbuf */ + iupAttribSetStr(ih, "_IUPIMAGE_CURSOR", (char*)cursor); + + return cursor; +} + +void iupImageGetInfo(const char* name, int *w, int *h, int *bpp) +{ + void* handle; + Ihandle *ih; + + if (!name) + return; + + /* Check first in the system resources. */ + handle = iupdrvImageLoad(name, IUPIMAGE_IMAGE); + if (handle) + { + iupdrvImageGetInfo(handle, w, h, bpp); + return; + } + + /* get handle from name */ + ih = IupGetHandle(name); + if (!ih) + { + /* Check in the stock images. */ + const char* native_name = NULL; + iImageStockGet(name, &ih, &native_name); + + if (native_name) + { + handle = iupdrvImageLoad(native_name, IUPIMAGE_IMAGE); + if (handle) + { + iupdrvImageGetInfo(handle, w, h, bpp); + return; + } + } + + if (!ih) + return; + } + + if (w) *w = ih->currentwidth; + if (h) *h = ih->currentheight; + if (bpp) *bpp = IupGetInt(ih, "BPP"); +} + +void* iupImageGetImage(const char* name, Ihandle* ih_parent, int make_inactive) +{ + char cache_name[100] = "_IUPIMAGE_IMAGE"; + char* bgcolor; + void* handle; + Ihandle *ih; + int bg_concat = 0; + + if (!name) + return NULL; + + /* Check first in the system resources. */ + handle = iupdrvImageLoad(name, IUPIMAGE_IMAGE); + if (handle) + return handle; + + /* get handle from name */ + ih = IupGetHandle(name); + if (!ih) + { + /* Check in the stock images. */ + const char* native_name = NULL; + iImageStockGet(name, &ih, &native_name); + + if (native_name) + { + handle = iupdrvImageLoad(native_name, IUPIMAGE_IMAGE); + if (handle) + return handle; + } + + if (!ih) + return NULL; + } + + bgcolor = iupAttribGet(ih, "BGCOLOR"); + if (ih_parent && !bgcolor) + bgcolor = IupGetAttribute(ih_parent, "BGCOLOR"); /* Use IupGetAttribute to use inheritance and native implementation */ + + if (make_inactive) + strcat(cache_name, "_INACTIVE"); + + if (iupAttribGet(ih, "_IUP_BGCOLOR_DEPEND") && bgcolor) + { + strcat(cache_name, "("); + strcat(cache_name, bgcolor); + strcat(cache_name, ")"); + bg_concat = 1; + } + + /* Check for an already created native image */ + handle = (void*)iupAttribGet(ih, cache_name); + if (handle) + return handle; + + if (ih_parent && iupAttribGetStr(ih_parent, "FLAT_ALPHA")) + iupAttribSetStr(ih, "FLAT_ALPHA", "1"); + + /* Creates the native image */ + handle = iupdrvImageCreateImage(ih, bgcolor, make_inactive); + + if (ih_parent && iupAttribGetStr(ih_parent, "FLAT_ALPHA")) + iupAttribSetStr(ih, "FLAT_ALPHA", NULL); + + if (iupAttribGet(ih, "_IUP_BGCOLOR_DEPEND") && bgcolor && !bg_concat) /* _IUP_BGCOLOR_DEPEND could be set during creation */ + { + strcat(cache_name, "("); + strcat(cache_name, bgcolor); + strcat(cache_name, ")"); + } + + /* save the native image in the cache */ + iupAttribSetStr(ih, cache_name, (char*)handle); + + return handle; +} + +void iupImageUpdateParent(Ihandle *ih) /* ih here is the element that contains images */ +{ + int inherit; + + /* Called when BGCOLOR is changed */ + /* it will re-create the image, if the case */ + + char* value = iupAttribGet(ih, "IMAGE"); + if (value) + iupClassObjectSetAttribute(ih, "IMAGE", value, &inherit); + + value = iupAttribGet(ih, "IMINACTIVE"); + if (value) + iupClassObjectSetAttribute(ih, "IMINACTIVE", value, &inherit); + + value = iupAttribGet(ih, "IMPRESS"); + if (value) + iupClassObjectSetAttribute(ih, "IMPRESS", value, &inherit); +} + +static char* iImageGetWidthAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(50); + sprintf(str, "%d", ih->currentwidth); + return str; +} + +static char* iImageGetHeightAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(50); + sprintf(str, "%d", ih->currentheight); + return str; +} + +void iupImageClearCache(Ihandle* ih, void* handle) +{ + char *name; + void* cur_handle; + + name = iupTableFirst(ih->attrib); + while (name) + { + if (iupStrEqualPartial(name, "_IUPIMAGE_")) + { + cur_handle = iupTableGetCurr(ih->attrib); + if (cur_handle == handle) + { + iupTableRemoveCurr(ih->attrib); + return; + } + } + + name = iupTableNext(ih->attrib); + } +} + +static void iImageUnMapMethod(Ihandle* ih) +{ + char *name; + void* handle; + + handle = iupAttribGet(ih, "_IUPIMAGE_ICON"); + if (handle) + { + iupdrvImageDestroy(handle, IUPIMAGE_ICON); + iupAttribSetStr(ih, "_IUPIMAGE_ICON", NULL); + } + + handle = iupAttribGet(ih, "_IUPIMAGE_CURSOR"); + if (handle) + { + iupdrvImageDestroy(handle, IUPIMAGE_CURSOR); + iupAttribSetStr(ih, "_IUPIMAGE_CURSOR", NULL); + } + + /* the remaining images are all IUPIMAGE_IMAGE */ + name = iupTableFirst(ih->attrib); + while (name) + { + if (iupStrEqualPartial(name, "_IUPIMAGE_")) + { + handle = iupTableGetCurr(ih->attrib); + if (handle) iupdrvImageDestroy(handle, IUPIMAGE_IMAGE); + } + + name = iupTableNext(ih->attrib); + } +} + +static int iImageCreate(Ihandle* ih, void** params, int bpp) +{ + int width, height, channels, count; + unsigned char *imgdata; + + iupASSERT(params!=NULL); + if (!params) + return IUP_ERROR; + + width = (int)(params[0]); + height = (int)(params[1]); + + iupASSERT(width>0); + iupASSERT(height>0); + + if (width <= 0 || height <= 0) + return IUP_ERROR; + + ih->currentwidth = width; + ih->currentheight = height; + + channels = 1; + if (bpp == 24) + channels = 3; + else if (bpp == 32) + channels = 4; + + count = width*height*channels; + imgdata = (unsigned char *)malloc(count); + + if (((int)(params[2])==-1) || ((int)(params[3])==-1)) /* compacted in one pointer */ + { + if ((int)(params[2])!=-1) + memcpy(imgdata, params[2], count); + } + else /* one param for each element */ + { + int i; + for(i=0; i<count; i++) + { + imgdata[i] = (unsigned char)((int)(params[i+2])); + } + } + + iupAttribSetStr(ih, "WID", (char*)imgdata); + iupAttribSetInt(ih, "BPP", bpp); + iupAttribSetInt(ih, "CHANNELS", channels); + + return IUP_NOERROR; +} + +static int iImageCreateMethod(Ihandle* ih, void** params) +{ + return iImageCreate(ih, params, 8); +} + +static int iImageRGBCreateMethod(Ihandle* ih, void** params) +{ + return iImageCreate(ih, params, 24); +} + +static int iImageRGBACreateMethod(Ihandle* ih, void** params) +{ + return iImageCreate(ih, params, 32); +} + +static void iImageDestroyMethod(Ihandle* ih) +{ + unsigned char* imgdata = (unsigned char*)iupAttribGetStr(ih, "WID"); + if (imgdata) + { + iupAttribSetStr(ih, "WID", NULL); + free(imgdata); + } +} + +/******************************************************************************/ + +Ihandle* IupImage(int width, int height, const unsigned char *imgdata) +{ + void *params[4]; + params[0] = (void*)width; + params[1] = (void*)height; + params[2] = imgdata? (void*)imgdata: (void*)-1; + params[3] = (void*)-1; + return IupCreatev("image", params); +} + +Ihandle* IupImageRGB(int width, int height, const unsigned char *imgdata) +{ + void *params[4]; + params[0] = (void*)width; + params[1] = (void*)height; + params[2] = imgdata? (void*)imgdata: (void*)-1; + params[3] = (void*)-1; + return IupCreatev("imagergb", params); +} + +Ihandle* IupImageRGBA(int width, int height, const unsigned char *imgdata) +{ + void *params[4]; + params[0] = (void*)width; + params[1] = (void*)height; + params[2] = imgdata? (void*)imgdata: (void*)-1; + params[3] = (void*)-1; + return IupCreatev("imagergba", params); +} + +static Iclass* iImageGetClassBase(char* name, int (*create_func)(Ihandle* ih, void** params)) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = name; + ic->format = "iiC"; /* (int,int,unsigned char*) */ + ic->nativetype = IUP_TYPEIMAGE; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 0; + + /* Class functions */ + ic->Create = create_func; + ic->Destroy = iImageDestroyMethod; + ic->Map = iupBaseTypeVoidMapMethod; + ic->UnMap = iImageUnMapMethod; + + /* Attribute functions */ + iupClassRegisterAttribute(ic, "WID", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "WIDTH", iImageGetWidthAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "HEIGHT", iImageGetHeightAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "RASTERSIZE", iupBaseGetRasterSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "BPP", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CHANNELS", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "HOTSPOT", NULL, NULL, "0:0", NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} + +Iclass* iupImageGetClass(void) +{ + return iImageGetClassBase("image", iImageCreateMethod); +} + +Iclass* iupImageRGBGetClass(void) +{ + return iImageGetClassBase("imagergb", iImageRGBCreateMethod); +} + +Iclass* iupImageRGBAGetClass(void) +{ + return iImageGetClassBase("imagergba", iImageRGBACreateMethod); +} + +static int SaveImageC(const char* file_name, Ihandle* ih, const char* name, FILE* packfile) +{ + int y, x, width, height, channels, linesize; + unsigned char* data; + FILE* file; + + if (packfile) + file = packfile; + else + file = fopen(file_name, "wb"); + + if (!file) + return 0; + + width = IupGetInt(ih, "WIDTH"); + height = IupGetInt(ih, "HEIGHT"); + channels = IupGetInt(ih, "CHANNELS"); + linesize = width*channels; + + data = (unsigned char*)IupGetAttribute(ih, "WID"); + + if (fprintf(file, "static Ihandle* load_image_%s(void)\n", name)<0) + { + if (!packfile) + fclose(file); + return 0; + } + + fprintf(file, "{\n"); + fprintf(file, " unsigned char imgdata[] = {\n"); + + for (y = 0; y < height; y++) + { + fprintf(file, " "); + + for (x = 0; x < linesize; x++) + { + if (x != 0) + fprintf(file, ", "); + + fprintf(file, "%d", (int)data[y*linesize+x]); + } + + if (y == height-1) + fprintf(file, "};\n\n"); + else + fprintf(file, ",\n"); + } + + if (channels == 1) + { + int c; + char str[20]; + char* color; + + fprintf(file, " Ihandle* image = IupImage(%d, %d, imgdata);\n\n", width, height); + + for (c = 0; c < 256; c++) + { + sprintf(str, "%d", c); + color = IupGetAttribute(ih, str); + if (!color) + break; + + fprintf(file, " IupSetAttribute(image, \"%d\", \"%s\");\n", c, color); + } + + fprintf(file, "\n"); + } + else if (channels == 3) + fprintf(file, " Ihandle* image = IupImageRGB(%d, %d, imgdata);\n", width, height); + else /* channels == 4 */ + fprintf(file, " Ihandle* image = IupImageRGBA(%d, %d, imgdata);\n", width, height); + + fprintf(file, " return image;\n"); + fprintf(file, "}\n\n"); + + if (!packfile) + fclose(file); + + return 1; +} + +static int SaveImageLua(const char* file_name, Ihandle* ih, const char* name, FILE* packfile) +{ + int y, x, width, height, channels, linesize; + unsigned char* data; + FILE* file; + + if (packfile) + file = packfile; + else + file = fopen(file_name, "wb"); + + if (!file) + return 0; + + width = IupGetInt(ih, "WIDTH"); + height = IupGetInt(ih, "HEIGHT"); + channels = IupGetInt(ih, "CHANNELS"); + linesize = width*channels; + + data = (unsigned char*)IupGetAttribute(ih, "WID"); + + if (fprintf(file, "function load_image_%s()\n", name)<0) + { + if (!packfile) + fclose(file); + return 0; + } + + if (channels == 1) + fprintf(file, " local %s = iup.image\n", name); + else if (channels == 3) + fprintf(file, " local %s = iup.imagergb\n", name); + else /* channels == 4 */ + fprintf(file, " local %s = iup.imagergba\n", name); + + fprintf(file, " {\n"); + + fprintf(file, " width = %d,\n", width); + fprintf(file, " height = %d,\n", height); + fprintf(file, " pixels = {\n"); + + for (y = 0; y < height; y++) + { + fprintf(file, " "); + for (x = 0; x < linesize; x++) + { + fprintf(file, "%d, ", (int)data[y*linesize+x]); + } + fprintf(file, "\n"); + } + + fprintf(file, " },\n"); + + if (channels == 1) + { + int c; + char* color; + unsigned int r, g, b; + char str[20]; + + fprintf(file, " colors = {\n"); + + for(c = 0; c < 256; c++) + { + sprintf(str, "%d", c); + color = IupGetAttribute(ih, str); + if (!color) + break; + + if (iupStrEqualNoCase(color, "BGCOLOR")) + fprintf(file, " \"BGCOLOR\",\n"); + else + { + sscanf(color, "%d %d %d", &r, &g, &b); + fprintf(file, " \"%d %d %d\",\n", r, g, b); + } + } + + fprintf(file, " }\n"); + } + + fprintf(file, " }\n"); + + fprintf(file, " return %s\n", name); + fprintf(file, "end\n\n"); + + if (!packfile) + fclose(file); + + return 1; +} + +static int SaveImageLED(const char* file_name, Ihandle* ih, const char* name, FILE* packfile) +{ + int y, x, width, height, channels, linesize; + unsigned char* data; + FILE* file; + + if (packfile) + file = packfile; + else + file = fopen(file_name, "wb"); + + if (!file) + return 0; + + width = IupGetInt(ih, "WIDTH"); + height = IupGetInt(ih, "HEIGHT"); + channels = IupGetInt(ih, "CHANNELS"); + linesize = width*channels; + + data = (unsigned char*)IupGetAttribute(ih, "WID"); + + if (channels == 1) + { + int c; + unsigned int r, g, b; + char str[20]; + char* color; + + if (fprintf(file, "%s = IMAGE\n", name)<0) + { + if (!packfile) + fclose(file); + return 0; + } + + fprintf(file, "[\n"); + for(c = 0; c < 256; c++) + { + sprintf(str, "%d", c); + color = IupGetAttribute(ih, str); + if (!color) + { + if (c < 16) + continue; + else + break; + } + + if (c != 0) + fprintf(file, ",\n"); + + if (iupStrEqualNoCase(color, "BGCOLOR")) + fprintf(file, " %d = \"BGCOLOR\"", c); + else + { + sscanf(color, "%d %d %d", &r, &g, &b); + fprintf(file, " %d = \"%d %d %d\"", c, r, g, b); + } + } + fprintf(file, "\n]\n"); + } + else if (channels == 3) + { + if (fprintf(file, "%s = IMAGERGB\n", name)<0) + { + if (!packfile) + fclose(file); + return 0; + } + } + else /* channels == 4 */ + { + if (fprintf(file, "%s = IMAGERGBA\n", name)<0) + { + if (!packfile) + fclose(file); + return 0; + } + } + + fprintf(file, "(%d, %d,\n", width, height); + + for (y = 0; y < height; y++) + { + fprintf(file, " "); + for (x = 0; x < linesize; x++) + { + if (y == height-1 && x==linesize-1) + fprintf(file, "%d", (int)data[y*linesize+x]); + else + fprintf(file, "%d, ", (int)data[y*linesize+x]); + } + fprintf(file, "\n"); + } + + fprintf(file, ")\n\n"); + + if (!packfile) + fclose(file); + + return 1; +} + +int iupSaveImageAsText(Ihandle* ih, FILE* packfile, const char* format, const char* name) +{ + int ret = 0; + if (iupStrEqualNoCase(format, "LED")) + ret = SaveImageLED(NULL, ih, name, packfile); + else if (iupStrEqualNoCase(format, "LUA")) + ret = SaveImageLua(NULL, ih, name, packfile); + else if (iupStrEqualNoCase(format, "C") || iupStrEqualNoCase(format, "H")) + ret = SaveImageC(NULL, ih, name, packfile); + return ret; +} + +int IupSaveImageAsText(Ihandle* ih, const char* file_name, const char* format, const char* name) +{ + int ret = 0; + if (!name) + { + name = IupGetName(ih); + if (!name) + name = "image"; + } + if (iupStrEqualNoCase(format, "LED")) + ret = SaveImageLED(file_name, ih, name, NULL); + else if (iupStrEqualNoCase(format, "LUA")) + ret = SaveImageLua(file_name, ih, name, NULL); + else if (iupStrEqualNoCase(format, "C") || iupStrEqualNoCase(format, "H")) + ret = SaveImageC(file_name, ih, name, NULL); + return ret; +} diff --git a/iup/src/iup_image.h b/iup/src/iup_image.h new file mode 100755 index 0000000..89e6795 --- /dev/null +++ b/iup/src/iup_image.h @@ -0,0 +1,61 @@ +/** \file + * \brief Image Resource Private Declarations + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_IMAGE_H +#define __IUP_IMAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +void* iupdrvImageCreateMask(Ihandle *ih); +void* iupdrvImageCreateIcon(Ihandle *ih); +void* iupdrvImageCreateCursor(Ihandle *ih); +void* iupdrvImageCreateImage(Ihandle *ih, const char* bgcolor, int make_inactive); + +enum {IUPIMAGE_IMAGE, IUPIMAGE_ICON, IUPIMAGE_CURSOR}; +void* iupdrvImageLoad(const char* name, int type); +void iupdrvImageDestroy(void* handle, int type); +int iupdrvImageGetInfo(void* handle, int *w, int *h, int *bpp); /* only for IUPIMAGE_IMAGE */ + +void* iupImageGetMask(const char* name); +void* iupImageGetIcon(const char* name); +void* iupImageGetCursor(const char* name); +void* iupImageGetImage(const char* name, Ihandle* parent, int make_inactive); +void iupImageGetInfo(const char* name, int *w, int *h, int *bpp); +void iupImageUpdateParent(Ihandle *parent); +void iupImageClearCache(Ihandle* ih, void* handle); + +typedef struct _iupColor { + unsigned char r, g, b, a; +} iupColor; + +int iupImageInitColorTable(Ihandle *ih, iupColor* colors, int *colors_count); +void iupImageInitNonBgColors(Ihandle* ih, unsigned char *colors); +void iupImageColorMakeInactive(unsigned char *r, unsigned char *g, unsigned char *b, + unsigned char bg_r, unsigned char bg_g, unsigned char bg_b); +int iupImageNormBpp(int bpp); + +#define iupALPHABLEND(_src,_dst,_alpha) (unsigned char)(((_src) * (_alpha) + (_dst) * (255 - (_alpha))) / 255) + +/* In Windows, RAW data is a DIB handle. + imgdata here is bottom-up arranged and has separated planes */ +void* iupdrvImageCreateImageRaw(int width, int height, int bpp, iupColor* colors, int colors_count, unsigned char *imgdata); +int iupdrvImageGetRawInfo(void* handle, int *w, int *h, int *bpp, iupColor* colors, int *colors_count); +void iupdrvImageGetRawData(void* handle, unsigned char* imgdata); + +void iupImageStockInit(void); +void iupImageStockFinish(void); +typedef Ihandle* (*iupImageStockCreateFunc)(void); +void iupImageStockSet(const char *name, iupImageStockCreateFunc func, const char* native_name); +void iupImageStockLoad(const char *name); /* Used only in iupImageLibLoadAll */ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_key.c b/iup/src/iup_key.c new file mode 100755 index 0000000..6c57c60 --- /dev/null +++ b/iup/src/iup_key.c @@ -0,0 +1,269 @@ +/** \file + * \brief Manage keys encoding and decoding. + * + * See Copyright Notice in "iup.h" + */ + +#include <memory.h> +#include <stdio.h> + +#include "iup.h" +#include "iupkey.h" +#include "iupcbs.h" + +#include "iup_key.h" +#include "iup_str.h" +#include "iup_object.h" +#include "iup_drv.h" +#include "iup_focus.h" + + +static struct +{ + char *name; + int code; +} ikey_map_list[]= + { + {"K_exclam", K_exclam}, + {"K_grave", K_grave}, + {"K_quotedbl", K_quotedbl}, + {"K_numbersign", K_numbersign}, + {"K_dollar", K_dollar}, + {"K_percent", K_percent}, + {"K_ampersand", K_ampersand}, + {"K_apostrophe", K_apostrophe}, + {"K_parentleft", K_parentleft}, + {"K_parentright", K_parentright}, + {"K_asterisk", K_asterisk}, {"K_sAsterisk",K_sAsterisk},{"K_cAsterisk",K_cAsterisk},{"K_mAsterisk",K_mAsterisk},{"K_yAsterisk",K_yAsterisk}, + {"K_plus", K_plus}, {"K_sPlus", K_sPlus}, {"K_cPlus", K_cPlus}, {"K_mPlus", K_mPlus}, {"K_yPlus", K_yPlus}, + {"K_comma", K_comma}, {"K_sComma", K_sComma}, {"K_cComma", K_cComma}, {"K_mComma", K_mComma}, {"K_yComma", K_yComma}, + {"K_minus", K_minus}, {"K_sMinus", K_sMinus}, {"K_cMinus", K_cMinus}, {"K_mMinus", K_mMinus}, {"K_yMinus", K_yMinus}, + {"K_period", K_period}, {"K_sPeriod", K_sPeriod}, {"K_cPeriod", K_cPeriod}, {"K_mPeriod", K_mPeriod}, {"K_yPeriod", K_yPeriod}, + {"K_slash", K_slash}, {"K_sSlash", K_sSlash}, {"K_cSlash", K_cSlash}, {"K_mSlash", K_mSlash}, {"K_ySlash", K_ySlash}, + {"K_colon", K_colon}, + {"K_semicolon ", K_semicolon}, {"K_cSemicolon ", K_cSemicolon}, {"K_mSemicolon ", K_mSemicolon}, {"K_ySemicolon ", K_ySemicolon}, + {"K_less", K_less}, + {"K_equal", K_equal}, {"K_cEqual", K_cEqual}, {"K_mEqual", K_mEqual}, {"K_yEqual", K_yEqual}, + {"K_greater", K_greater}, + {"K_question", K_question}, + {"K_bracketleft", K_bracketleft}, {"K_cBracketleft", K_cBracketleft}, {"K_mBracketleft", K_mBracketleft}, {"K_yBracketleft", K_yBracketleft}, + {"K_backslash", K_backslash}, {"K_cBackslash", K_cBackslash}, {"K_mBackslash", K_mBackslash}, {"K_yBackslash", K_yBackslash}, + {"K_bracketright", K_bracketright}, {"K_cBracketright", K_cBracketright}, {"K_mBracketright", K_mBracketright}, {"K_yBracketright", K_yBracketright}, + {"K_circum", K_circum}, + {"K_underscore", K_underscore}, + {"K_at", K_at}, + {"K_braceleft", K_braceleft}, + {"K_bar", K_bar}, + {"K_braceright", K_braceright}, + {"K_tilde", K_tilde}, + {"K_acute", K_acute}, + {"K_ccedilla" ,K_ccedilla}, {"K_Ccedilla" ,K_Ccedilla}, {"K_cCcedilla" ,K_cCcedilla}, {"K_mCcedilla" ,K_mCcedilla}, {"K_yCcedilla" ,K_yCcedilla}, + {"K_ESC" ,K_ESC}, {"K_sESC" ,K_sESC}, {"K_cESC" ,K_cESC}, {"K_mESC" ,K_mESC}, {"K_yESC" ,K_yESC}, + {"K_PAUSE" ,K_PAUSE}, {"K_sPAUSE" ,K_sPAUSE}, {"K_cPAUSE" ,K_cPAUSE}, {"K_mPAUSE" ,K_mPAUSE}, {"K_yPAUSE" ,K_yPAUSE}, + {"K_HOME" ,K_HOME}, {"K_sHOME" ,K_sHOME}, {"K_cHOME" ,K_cHOME}, {"K_mHOME" ,K_mHOME}, {"K_yHOME" ,K_yHOME}, + {"K_UP" ,K_UP}, {"K_sUP" ,K_sUP}, {"K_cUP" ,K_cUP}, {"K_mUP" ,K_mUP}, {"K_yUP" ,K_yUP}, + {"K_PGUP" ,K_PGUP}, {"K_sPGUP" ,K_sPGUP}, {"K_cPGUP" ,K_cPGUP}, {"K_mPGUP" ,K_mPGUP}, {"K_yPGUP" ,K_yPGUP}, + {"K_LEFT" ,K_LEFT}, {"K_sLEFT" ,K_sLEFT}, {"K_cLEFT" ,K_cLEFT}, {"K_mLEFT" ,K_mLEFT}, {"K_yLEFT" ,K_yLEFT}, + {"K_MIDDLE",K_MIDDLE}, {"K_sMIDDLE",K_sMIDDLE},{"K_cMIDDLE",K_cMIDDLE},{"K_mMIDDLE",K_mMIDDLE}, {"K_yMIDDLE",K_yMIDDLE}, + {"K_RIGHT" ,K_RIGHT}, {"K_sRIGHT" ,K_sRIGHT}, {"K_cRIGHT" ,K_cRIGHT}, {"K_mRIGHT" ,K_mRIGHT}, {"K_yRIGHT" ,K_yRIGHT}, + {"K_END" ,K_END}, {"K_sEND" ,K_sEND}, {"K_cEND" ,K_cEND}, {"K_mEND" ,K_mEND}, {"K_yEND" ,K_yEND}, + {"K_DOWN" ,K_DOWN}, {"K_sDOWN" ,K_sDOWN}, {"K_cDOWN" ,K_cDOWN}, {"K_mDOWN" ,K_mDOWN}, {"K_yDOWN" ,K_yDOWN}, + {"K_PGDN" ,K_PGDN}, {"K_sPGDN" ,K_sPGDN}, {"K_cPGDN" ,K_cPGDN}, {"K_mPGDN" ,K_mPGDN}, {"K_yPGDN" ,K_yPGDN}, + {"K_INS" ,K_INS}, {"K_sINS" ,K_sINS}, {"K_cINS" ,K_cINS}, {"K_mINS" ,K_mINS}, {"K_yINS" ,K_yINS}, + {"K_DEL" ,K_DEL}, {"K_sDEL" ,K_sDEL}, {"K_cDEL" ,K_cDEL}, {"K_mDEL" ,K_mDEL}, {"K_yDEL" ,K_yDEL}, + {"K_SP" ,K_SP}, {"K_sSP" ,K_sSP}, {"K_cSP" ,K_cSP}, {"K_mSP" ,K_mSP}, {"K_ySP" ,K_ySP}, + {"K_TAB" ,K_TAB}, {"K_sTAB" ,K_sTAB}, {"K_cTAB" ,K_cTAB}, {"K_mTAB" ,K_mTAB}, {"K_yTAB" ,K_yTAB}, + {"K_CR" ,K_CR}, {"K_sCR" ,K_sCR}, {"K_cCR" ,K_cCR}, {"K_mCR" ,K_mCR}, {"K_yCR" ,K_yCR}, + {"K_BS" ,K_BS}, {"K_sBS" ,K_sBS}, {"K_cBS" ,K_cBS}, {"K_mBS" ,K_mBS}, {"K_yBS" ,K_yBS}, + {"K_Print" ,K_Print}, {"K_sPrint" ,K_sPrint}, {"K_cPrint" ,K_cPrint}, {"K_mPrint" ,K_mPrint}, {"K_yPrint" ,K_yPrint}, + {"K_Menu" ,K_Menu}, {"K_sMenu" ,K_sMenu}, {"K_cMenu" ,K_cMenu}, {"K_mMenu" ,K_mMenu}, {"K_yMenu" ,K_yMenu}, + {"K_0", K_0}, {"K_c0", K_c0}, {"K_m0", K_m0}, {"K_y0", K_y0}, + {"K_1", K_1}, {"K_c1", K_c1}, {"K_m1", K_m1}, {"K_y1", K_y1}, + {"K_2", K_2}, {"K_c2", K_c2}, {"K_m2", K_m2}, {"K_y2", K_y2}, + {"K_3", K_3}, {"K_c3", K_c3}, {"K_m3", K_m3}, {"K_y3", K_y3}, + {"K_4", K_4}, {"K_c4", K_c4}, {"K_m4", K_m4}, {"K_y4", K_y4}, + {"K_5", K_5}, {"K_c5", K_c5}, {"K_m5", K_m5}, {"K_y5", K_y5}, + {"K_6", K_6}, {"K_c6", K_c6}, {"K_m6", K_m6}, {"K_y6", K_y6}, + {"K_7", K_7}, {"K_c7", K_c7}, {"K_m7", K_m7}, {"K_y7", K_y7}, + {"K_8", K_8}, {"K_c8", K_c8}, {"K_m8", K_m8}, {"K_y8", K_y8}, + {"K_9", K_9}, {"K_c9", K_c9}, {"K_m9", K_m9}, {"K_y9", K_y9}, + {"K_a", K_a}, {"K_A", K_A}, {"K_cA" ,K_cA}, {"K_mA" ,K_mA}, {"K_yA" ,K_yA}, + {"K_b", K_b}, {"K_B", K_B}, {"K_cB" ,K_cB}, {"K_mB" ,K_mB}, {"K_yB" ,K_yB}, + {"K_c", K_c}, {"K_C", K_C}, {"K_cC" ,K_cC}, {"K_mC" ,K_mC}, {"K_yC" ,K_yC}, + {"K_d", K_d}, {"K_D", K_D}, {"K_cD" ,K_cD}, {"K_mD" ,K_mD}, {"K_yD" ,K_yD}, + {"K_e", K_e}, {"K_E", K_E}, {"K_cE" ,K_cE}, {"K_mE" ,K_mE}, {"K_yE" ,K_yE}, + {"K_f", K_f}, {"K_F", K_F}, {"K_cF" ,K_cF}, {"K_mF" ,K_mF}, {"K_yF" ,K_yF}, + {"K_g", K_g}, {"K_G", K_G}, {"K_cG" ,K_cG}, {"K_mG" ,K_mG}, {"K_yG" ,K_yG}, + {"K_h", K_h}, {"K_H", K_H}, {"K_cH" ,K_cH}, {"K_mH" ,K_mH}, {"K_yH" ,K_yH}, + {"K_i", K_i}, {"K_I", K_I}, {"K_cI" ,K_cI}, {"K_mI" ,K_mI}, {"K_yI" ,K_yI}, + {"K_j", K_j}, {"K_J", K_J}, {"K_cJ" ,K_cJ}, {"K_mJ" ,K_mJ}, {"K_yJ" ,K_yJ}, + {"K_k", K_k}, {"K_K", K_K}, {"K_cK" ,K_cK}, {"K_mK" ,K_mK}, {"K_yK" ,K_yK}, + {"K_l", K_l}, {"K_L", K_L}, {"K_cL" ,K_cL}, {"K_mL" ,K_mL}, {"K_yL" ,K_yL}, + {"K_m", K_m}, {"K_M", K_M}, {"K_cM" ,K_cM}, {"K_mM" ,K_mM}, {"K_yM" ,K_yM}, + {"K_n", K_n}, {"K_N", K_N}, {"K_cN" ,K_cN}, {"K_mN" ,K_mN}, {"K_yN" ,K_yN}, + {"K_o", K_o}, {"K_O", K_O}, {"K_cO" ,K_cO}, {"K_mO" ,K_mO}, {"K_yO" ,K_yO}, + {"K_p", K_p}, {"K_P", K_P}, {"K_cP" ,K_cP}, {"K_mP" ,K_mP}, {"K_yP" ,K_yP}, + {"K_q", K_q}, {"K_Q", K_Q}, {"K_cQ" ,K_cQ}, {"K_mQ" ,K_mQ}, {"K_yQ" ,K_yQ}, + {"K_r", K_r}, {"K_R", K_R}, {"K_cR" ,K_cR}, {"K_mR" ,K_mR}, {"K_yR" ,K_yR}, + {"K_s", K_s}, {"K_S", K_S}, {"K_cS" ,K_cS}, {"K_mS" ,K_mS}, {"K_yS" ,K_yS}, + {"K_t", K_t}, {"K_T", K_T}, {"K_cT" ,K_cT}, {"K_mT" ,K_mT}, {"K_yT" ,K_yT}, + {"K_u", K_u}, {"K_U", K_U}, {"K_cU" ,K_cU}, {"K_mU" ,K_mU}, {"K_yU" ,K_yU}, + {"K_v", K_v}, {"K_V", K_V}, {"K_cV" ,K_cV}, {"K_mV" ,K_mV}, {"K_yV" ,K_yV}, + {"K_w", K_w}, {"K_W", K_W}, {"K_cW" ,K_cW}, {"K_mW" ,K_mW}, {"K_yW" ,K_yW}, + {"K_x", K_x}, {"K_X", K_X}, {"K_cX" ,K_cX}, {"K_mX" ,K_mX}, {"K_yX" ,K_yX}, + {"K_y", K_y}, {"K_Y", K_Y}, {"K_cY" ,K_cY}, {"K_mY" ,K_mY}, {"K_yY" ,K_yY}, + {"K_z", K_z}, {"K_Z", K_Z}, {"K_cZ" ,K_cZ}, {"K_mZ" ,K_mZ}, {"K_yZ" ,K_yZ}, + {"K_F1" ,K_F1}, {"K_sF1" ,K_sF1}, {"K_cF1" ,K_cF1}, {"K_mF1" ,K_mF1}, {"K_yF1" ,K_yF1}, + {"K_F2" ,K_F2}, {"K_sF2" ,K_sF2}, {"K_cF2" ,K_cF2}, {"K_mF2" ,K_mF2}, {"K_yF2" ,K_yF2}, + {"K_F3" ,K_F3}, {"K_sF3" ,K_sF3}, {"K_cF3" ,K_cF3}, {"K_mF3" ,K_mF3}, {"K_yF3" ,K_yF3}, + {"K_F4" ,K_F4}, {"K_sF4" ,K_sF4}, {"K_cF4" ,K_cF4}, {"K_mF4" ,K_mF4}, {"K_yF4" ,K_yF4}, + {"K_F5" ,K_F5}, {"K_sF5" ,K_sF5}, {"K_cF5" ,K_cF5}, {"K_mF5" ,K_mF5}, {"K_yF5" ,K_yF5}, + {"K_F6" ,K_F6}, {"K_sF6" ,K_sF6}, {"K_cF6" ,K_cF6}, {"K_mF6" ,K_mF6}, {"K_yF6" ,K_yF6}, + {"K_F7" ,K_F7}, {"K_sF7" ,K_sF7}, {"K_cF7" ,K_cF7}, {"K_mF7" ,K_mF7}, {"K_yF7" ,K_yF7}, + {"K_F8" ,K_F8}, {"K_sF8" ,K_sF8}, {"K_cF8" ,K_cF8}, {"K_mF8" ,K_mF8}, {"K_yF8" ,K_yF8}, + {"K_F9" ,K_F9}, {"K_sF9" ,K_sF9}, {"K_cF9" ,K_cF9}, {"K_mF9" ,K_mF9}, {"K_yF9" ,K_yF9}, + {"K_F10" ,K_F10}, {"K_sF10" ,K_sF10}, {"K_cF10" ,K_cF10}, {"K_mF10" ,K_mF10}, {"K_yF10" ,K_yF10}, + {"K_F11" ,K_F11}, {"K_sF11" ,K_sF11}, {"K_cF11" ,K_cF11}, {"K_mF11" ,K_mF11}, {"K_yF11" ,K_yF11}, + {"K_F12" ,K_F12}, {"K_sF12" ,K_sF12}, {"K_cF12" ,K_cF12}, {"K_mF12" ,K_mF12}, {"K_yF12" ,K_yF12}, + {NULL ,0} + }; + +static char* ikey_map[IUP_NUMMAXCODES]; + +void iupKeyInit(void) +{ + int i; + memset(ikey_map, 0, IUP_NUMMAXCODES*sizeof(char*)); + for (i = 0; ikey_map_list[i].name; i++) + ikey_map[ikey_map_list[i].code] = ikey_map_list[i].name; +} + +int iupKeyCanCaps(int code) +{ + if (code >= K_a && code <= K_z) + return 1; + if (code == K_ccedilla) + return 1; + return 0; +} + +char* iupKeyCodeToName(int code) +{ + if (code < 0 || code > IUP_NUMMAXCODES) + return NULL; + return ikey_map[code]; +} + +int iupKeyNameToCode(const char *name) +{ + int i; + for (i = 0; ikey_map_list[i].name; i++) + if (iupStrEqual(name, ikey_map_list[i].name)) + return ikey_map_list[i].code; + + return 0; +} + +void iupKeyForEach(void (*func)(const char *name, int code, void* user_data), void* user_data) +{ + int i; + for (i = 0; ikey_map_list[i].name; ++i) + func(ikey_map_list[i].name, ikey_map_list[i].code, user_data); +} + +int iupKeyCallKeyCb(Ihandle *ih, int code) +{ + char* name = iupKeyCodeToName(code); + for (; ih; ih = ih->parent) + { + IFni cb = NULL; + if (name) + cb = (IFni)IupGetCallback(ih, name); + if (!cb) + cb = (IFni)IupGetCallback(ih, "K_ANY"); + + if (cb) + { + int ret = cb(ih, code); + if (ret != IUP_CONTINUE) + return ret; + } + } + return IUP_DEFAULT; +} + +int iupKeyCallKeyPressCb(Ihandle *ih, int code, int press) +{ + IFnii cb = (IFnii)IupGetCallback(ih, "KEYPRESS_CB"); + if (cb) return cb(ih, code, press); + return IUP_DEFAULT; +} + +int iupKeyProcessNavigation(Ihandle* ih, int key, int shift) +{ + /* this is called after K_ANY is processed, + so the user may change its behavior */ + + if (key == K_cTAB) + { + int is_multiline = (iupStrEqual(ih->iclass->name, "multiline") || + (iupStrEqual(ih->iclass->name, "text") && IupGetInt(ih, "MULTILINE"))); + if (is_multiline) + { + if (shift) + IupPreviousField(ih); + else + IupNextField(ih); + return 0; /* abort default processing */ + } + } + else if (key == K_TAB || key == K_sTAB) + { + int is_multiline = (iupStrEqual(ih->iclass->name, "multiline") || + (iupStrEqual(ih->iclass->name, "text") && IupGetInt(ih, "MULTILINE"))); + if (!is_multiline) + { + if (key == K_sTAB) + IupPreviousField(ih); + else + IupNextField(ih); + return 0; /* abort default processing */ + } + } + else if (key == K_UP || key == K_DOWN) + { + int is_button = (iupStrEqual(ih->iclass->name, "button") || + iupStrEqual(ih->iclass->name, "toggle")); + if (is_button) + { + if (key == K_UP) + iupFocusPrevious(ih); + else + iupFocusNext(ih); + return 0; /* abort default processing */ + } + } + else if (key==K_ESC) + { + Ihandle* bt = IupGetAttributeHandle(IupGetDialog(ih), "DEFAULTESC"); + if (iupObjectCheck(bt) && iupStrEqual(bt->iclass->name, "button")) + iupdrvActivate(bt); + return 0; /* abort default processing */ + } + else if (key==K_CR || key==K_cCR) + { + int is_multiline = (iupStrEqual(ih->iclass->name, "multiline") || + (iupStrEqual(ih->iclass->name, "text") && IupGetInt(ih, "MULTILINE"))); + + if ((key==K_CR && !is_multiline) || (key==K_cCR && is_multiline)) + { + Ihandle* bt = IupGetAttributeHandle(IupGetDialog(ih), "DEFAULTENTER"); + if (iupObjectCheck(bt) && iupStrEqual(bt->iclass->name, "button")) + iupdrvActivate(bt); + return 0; /* abort default processing */ + } + } + + return 1; +} + diff --git a/iup/src/iup_key.h b/iup/src/iup_key.h new file mode 100755 index 0000000..37d6c9d --- /dev/null +++ b/iup/src/iup_key.h @@ -0,0 +1,70 @@ +/** \file + * \brief Manage keys encoding and decoding. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_KEY_H +#define __IUP_KEY_H + + +/** \defgroup key Key Coding and Key Callbacks + * \par + * See \ref iup_key.h + * \ingroup cpi */ + + +/** Returns the key name from its code. + * Returns NULL if code not found. + * \ingroup key */ +char *iupKeyCodeToName(int code); + +/** Returns the key code from its name. + * Returns 0 if name not found. + * \ingroup key */ +int iupKeyNameToCode(const char *name); + +/** Returns true if the key code can be changed by CAPSLOCK. + * \ingroup key */ +int iupKeyCanCaps(int code); + +/** Calls a function for each defined key. + * \ingroup key */ +void iupKeyForEach(void (*func)(const char *name, int code, void* user_data), void* user_data); + +/** Calls the K_ANY or K_* callbacks. Should be called when a keyboard event occoured. + * \ingroup key */ +int iupKeyCallKeyCb(Ihandle *ih, int c); + +/** Calls the KEYPRESS_CB callback. Should be called when a keyboard event occoured. + * \ingroup key */ +int iupKeyCallKeyPressCb(Ihandle *ih, int code, int press); + +/** Process Tab, DEFAULTENTER and DEFAULTESC in key press events. + * \ingroup key */ +int iupKeyProcessNavigation(Ihandle* ih, int key, int shift); + + +/* Called only from IupOpen. */ +void iupKeyInit(void); + + +#define IUPKEY_STATUS_SIZE 11 /* 10 chars + null */ +#define IUPKEY_STATUS_INIT " " /* 10 spaces */ +#define iupKEYSETSHIFT(_s) (_s[0]='S') +#define iupKEYSETCONTROL(_s) (_s[1]='C') +#define iupKEYSETBUTTON1(_s) (_s[2]='1') +#define iupKEYSETBUTTON2(_s) (_s[3]='2') +#define iupKEYSETBUTTON3(_s) (_s[4]='3') +#define iupKEYSETDOUBLE(_s) (_s[5]='D') +#define iupKEYSETALT(_s) (_s[6]='A') +#define iupKEYSETSYS(_s) (_s[7]='Y') +#define iupKEYSETBUTTON4(_s) (_s[8]='4') +#define iupKEYSETBUTTON5(_s) (_s[9]='5') + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_label.c b/iup/src/iup_label.c new file mode 100755 index 0000000..33d96af --- /dev/null +++ b/iup/src/iup_label.c @@ -0,0 +1,183 @@ +/** \file + * \brief Label Control. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" +#include "iup_label.h" +#include "iup_image.h" + + +static int iLabelSetSeparatorAttrib(Ihandle* ih, const char* value) +{ + /* valid only before map */ + if (ih->handle) + return 0; + + if (value) + { + if (iupStrEqualNoCase(value, "HORIZONTAL")) + ih->expand = IUP_EXPAND_WIDTH; + else if (iupStrEqualNoCase(value, "VERTICAL")) + ih->expand = IUP_EXPAND_HEIGHT; + else + return 0; + } + + return 1; +} + +static char* iLabelGetSeparatorAttrib(Ihandle* ih) +{ + if (ih->handle) + { + if (ih->data->type == IUP_LABEL_SEP_HORIZ) + return "HORIZONTAL"; + else if (ih->data->type == IUP_LABEL_SEP_VERT) + return "VERTICAL"; + } + return NULL; +} + +char* iupLabelGetPaddingAttrib(Ihandle* ih) +{ + if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT) + { + char *str = iupStrGetMemory(50); + sprintf(str, "%dx%d", ih->data->horiz_padding, ih->data->vert_padding); + return str; + } + else + return NULL; +} + + +/**************************************************************************************/ + + +static int iLabelCreateMethod(Ihandle* ih, void** params) +{ + if (params && params[0]) + iupAttribStoreStr(ih, "TITLE", (char*)(params[0])); + + ih->data = iupALLOCCTRLDATA(); + + /* used only by the Windows driver */ + ih->data->vert_alignment = IUP_ALIGN_ACENTER; + return IUP_NOERROR; +} + +static void iLabelComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + int natural_w = 0, + natural_h = 0, + type = ih->data->type; + (void)expand; /* unset if not a container */ + + if (!ih->handle) + { + /* if not mapped must initialize the internal values */ + char* value = iupAttribGet(ih, "SEPARATOR"); + if (value) + { + if (iupStrEqualNoCase(value, "HORIZONTAL")) + type = IUP_LABEL_SEP_HORIZ; + else /* "VERTICAL" */ + type = IUP_LABEL_SEP_VERT; + } + else + { + value = iupAttribGet(ih, "IMAGE"); + if (value) + type = IUP_LABEL_IMAGE; + else + type = IUP_LABEL_TEXT; + } + } + + if (type == IUP_LABEL_SEP_HORIZ) + natural_h = 2; + else if (type == IUP_LABEL_SEP_VERT) + natural_w = 2; + else if (type == IUP_LABEL_IMAGE) + { + iupImageGetInfo(iupAttribGet(ih, "IMAGE"), &natural_w, &natural_h, NULL); + + natural_w += 2*ih->data->horiz_padding; + natural_h += 2*ih->data->vert_padding; + } + else /* IUP_LABEL_TEXT */ + { + /* must use IupGetAttribute to check from the native implementation */ + char* title = IupGetAttribute(ih, "TITLE"); + char* str = iupStrProcessMnemonic(title, NULL, 0); /* remove & */ + iupdrvFontGetMultiLineStringSize(ih, str, &natural_w, &natural_h); + if (str && str!=title) free(str); + + natural_w += 2*ih->data->horiz_padding; + natural_h += 2*ih->data->vert_padding; + } + + *w = natural_w; + *h = natural_h; +} + + +/******************************************************************************/ + + +Ihandle* IupLabel(const char* title) +{ + void *params[2]; + params[0] = (void*)title; + params[1] = NULL; + return IupCreatev("label", params); +} + +Iclass* iupLabelGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "label"; + ic->format = "S"; /* one optional string */ + ic->nativetype = IUP_TYPECONTROL; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 0; + + /* Class functions */ + ic->Create = iLabelCreateMethod; + ic->ComputeNaturalSize = iLabelComputeNaturalSizeMethod; + + ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Common Callbacks */ + iupClassRegisterCallback(ic, "MAP_CB", ""); + iupClassRegisterCallback(ic, "UNMAP_CB", ""); + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Visual */ + iupBaseRegisterVisualAttrib(ic); + + /* IupLabel only */ + iupClassRegisterAttribute(ic, "SEPARATOR", iLabelGetSeparatorAttrib, iLabelSetSeparatorAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupdrvLabelInitClass(ic); + + return ic; +} diff --git a/iup/src/iup_label.h b/iup/src/iup_label.h new file mode 100755 index 0000000..f50d26f --- /dev/null +++ b/iup/src/iup_label.h @@ -0,0 +1,37 @@ +/** \file + * \brief Label Controls Private Declarations + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_LABEL_H +#define __IUP_LABEL_H + +#ifdef __cplusplus +extern "C" { +#endif + + +void iupdrvLabelInitClass(Iclass* ic); + +char* iupLabelGetPaddingAttrib(Ihandle* ih); + +enum{IUP_LABEL_SEP_HORIZ, IUP_LABEL_SEP_VERT, IUP_LABEL_IMAGE, IUP_LABEL_TEXT}; + +struct _IcontrolData +{ + int type, /* the 4 labels possibilities */ + horiz_padding, vert_padding; /* label margin */ + + /* used only by the Windows driver */ + int horiz_alignment, vert_alignment, + text_style; + unsigned long fgcolor; +}; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_layout.c b/iup/src/iup_layout.c new file mode 100755 index 0000000..b96293c --- /dev/null +++ b/iup/src/iup_layout.c @@ -0,0 +1,273 @@ +/** \file + * \brief Abstract Layout Management + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_drv.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_layout.h" +#include "iup_assert.h" + + +void IupRefresh(Ihandle* ih) +{ + Ihandle* dialog; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + dialog = IupGetDialog(ih); + if (dialog) + { + iupLayoutCompute(dialog); + if (dialog->handle) + iupLayoutUpdate(dialog); + } +} + +static void iLayoutDisplayUpdateChildren(Ihandle *ih) +{ + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + { + iLayoutDisplayUpdateChildren(child); + + if (child->handle && child->iclass->nativetype != IUP_TYPEVOID) + iupdrvDisplayUpdate(child); + } +} + +void IupUpdate(Ihandle* ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + if (ih->handle && ih->iclass->nativetype != IUP_TYPEVOID) + iupdrvDisplayUpdate(ih); +} + +void IupUpdateChildren(Ihandle* ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + iLayoutDisplayUpdateChildren(ih); +} + +static void iLayoutDisplayRedrawChildren(Ihandle *ih) +{ + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + { + iLayoutDisplayRedrawChildren(child); + + if (child->handle && child->iclass->nativetype != IUP_TYPEVOID) + iupdrvDisplayRedraw(child); + } +} + +void IupRedraw(Ihandle* ih, int children) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + if (ih->handle && ih->iclass->nativetype != IUP_TYPEVOID) + iupdrvDisplayRedraw(ih); + + if (children) + iLayoutDisplayRedrawChildren(ih); +} + +void iupLayoutUpdate(Ihandle* ih) +{ + Ihandle* child; + + /* update size and position of the native control */ + iupClassObjectLayoutUpdate(ih); + + /* update its children */ + for (child = ih->firstchild; child; child = child->brother) + { + if (child->handle) + iupLayoutUpdate(child); + } +} + +void iupLayoutCompute(Ihandle* ih) +{ + int shrink = iupAttribGetBoolean(ih, "SHRINK"); + + /* Compute the natural size for all elements in the dialog, + using the minimum visible size and the defined user size. + The minimum visible size is the size where all the controls can display + all their contents. + The defined user size is used to increase the value of the minimum visible size for containers, + for standard controls will replace the minimum visible size. + So the native size will be the maximum value between + minimum visible size and defined user size. + Also calculates the expand configuration for each element, but expand is used only in SetChildrenCurrentSize. + SEQUENCE: will first calculate the native size for the children, then for the element. */ + iupBaseComputeNaturalSize(ih); + + /* Set the current size (not reflected in the native element yet) based on + the natural size and the expand configuration. + If shrink is 0 (default) the current size of containers can be only larger than the natural size, + the result will depend on the EXPAND attribute. + If shrink is 1 the containers can be resized to sizes smaller than the natural size. + SEQUENCE: will first calculate the current size of the element, then for the children. */ + iupBaseSetCurrentSize(ih, 0, 0, shrink); + + /* Now that the current size is known, set the position of the elements + relative to the parent. + SEQUENCE: will first set the position of the element, then for the children. */ + iupBaseSetPosition(ih, 0, 0); +} + +static void iLayoutSetMinMaxSize(Ihandle* ih, int *w, int *h) +{ + if (ih->has_minsize) + { + char* value = iupAttribGet(ih, "MINSIZE"); + int min_w = 0, min_h = 0; /* MINSIZE default value */ + iupStrToIntInt(value, &min_w, &min_h, 'x'); + if (*w < min_w) *w = min_w; + if (*h < min_h) *h = min_h; + } + + if (ih->has_maxsize) + { + char* value = iupAttribGet(ih, "MAXSIZE"); + int max_w = 65535, max_h = 65535; /* MAXSIZE default value */ + iupStrToIntInt(value, &max_w, &max_h, 'x'); + if (*w > max_w) *w = max_w; + if (*h > max_h) *h = max_h; + } +} + +void iupBaseComputeNaturalSize(Ihandle* ih) +{ + /* always initialize the natural size using the user size */ + ih->naturalwidth = ih->userwidth; + ih->naturalheight = ih->userheight; + + if (ih->iclass->childtype!=IUP_CHILDNONE || ih->iclass->nativetype == IUP_TYPEDIALOG) + { + int w=0, h=0, children_expand; + + /* if a container then update the "expand" member from the EXPAND attribute */ + iupBaseContainerUpdateExpand(ih); + children_expand = ih->expand; /* use it as default value */ + + iupClassObjectComputeNaturalSize(ih, &w, &h, &children_expand); + + if (ih->iclass->nativetype == IUP_TYPEDIALOG) + { + /* only update the natural size if user size is not defined. */ + /* IupDialog is the only container where this must be done */ + /* if the natural size is bigger than the actual dialog size then + the dialog will be resized, if smaller then the dialog remains with the same size. */ + ih->expand |= children_expand; + if (ih->naturalwidth <= 0) ih->naturalwidth = iupMAX(ih->currentwidth, w); + if (ih->naturalheight <= 0) ih->naturalheight = iupMAX(ih->currentheight, h); + } + else + { + ih->expand &= children_expand; /* combine but only expand where the element can expand */ + ih->naturalwidth = iupMAX(ih->naturalwidth, w); + ih->naturalheight = iupMAX(ih->naturalheight, h); + + /* crop the natural size */ + iLayoutSetMinMaxSize(ih, &(ih->naturalwidth), &(ih->naturalheight)); + } + } + else + { + /* for non-container only compute if user size is not defined */ + if (ih->naturalwidth <= 0 || ih->naturalheight <= 0) + { + int w=0, h=0; + iupClassObjectComputeNaturalSize(ih, &w, &h, NULL); + + if (ih->naturalwidth <= 0) ih->naturalwidth = w; + if (ih->naturalheight <= 0) ih->naturalheight = h; + } + + /* crop the natural size */ + iLayoutSetMinMaxSize(ih, &(ih->naturalwidth), &(ih->naturalheight)); + } +} + +void iupBaseSetCurrentSize(Ihandle* ih, int w, int h, int shrink) +{ + if (ih->iclass->nativetype == IUP_TYPEDIALOG) + { + /* w and h parameters here are ignored, because they are always 0 for the dialog. */ + + /* current size is zero before map and when reset by the application */ + /* after that the current size must follow the actual size of the dialog */ + if (!ih->currentwidth) ih->currentwidth = ih->naturalwidth; + if (!ih->currentheight) ih->currentheight = ih->naturalheight; + + if (ih->firstchild) + iupClassObjectSetChildrenCurrentSize(ih, shrink); + } + else + { + if (ih->iclass->childtype!=IUP_CHILDNONE) + { + if (shrink) + { + /* if expand then use the given size, else use the natural size */ + /* this expand is a combination of the expand defined for the element and its children */ + ih->currentwidth = (ih->expand & IUP_EXPAND_WIDTH)? w: ih->naturalwidth; + ih->currentheight = (ih->expand & IUP_EXPAND_HEIGHT)? h: ih->naturalheight; + } + else + { + /* if expand then use the given size (if greater than natural size), else use the natural size */ + /* this expand is a combination of the expand defined for the element and its children */ + ih->currentwidth = (ih->expand & IUP_EXPAND_WIDTH)? iupMAX(ih->naturalwidth, w): ih->naturalwidth; + ih->currentheight = (ih->expand & IUP_EXPAND_HEIGHT)? iupMAX(ih->naturalheight, h): ih->naturalheight; + } + + if (ih->firstchild) + iupClassObjectSetChildrenCurrentSize(ih, shrink); + } + else + { + /* shrink is only used by containers, usually is 0 */ + /* for non containers is always 1, so they always can be smaller than the natural size */ + + /* if expand use the given size, else use the natural size */ + /* this expand is the defined for the element */ + ih->currentwidth = (ih->expand & IUP_EXPAND_WIDTH)? w: ih->naturalwidth; + ih->currentheight = (ih->expand & IUP_EXPAND_HEIGHT)? h: ih->naturalheight; + } + + /* crop the current size if expanded */ + if (ih->expand & IUP_EXPAND_WIDTH || ih->expand & IUP_EXPAND_HEIGHT) + iLayoutSetMinMaxSize(ih, &(ih->currentwidth), &(ih->currentheight)); + } +} + +void iupBaseSetPosition(Ihandle* ih, int x, int y) +{ + ih->x = x; + ih->y = y; + + if (ih->firstchild) + iupClassObjectSetChildrenPosition(ih, x, y); +} diff --git a/iup/src/iup_layout.h b/iup/src/iup_layout.h new file mode 100755 index 0000000..a2a0c29 --- /dev/null +++ b/iup/src/iup_layout.h @@ -0,0 +1,28 @@ +/** \file + * \brief Abstract Layout Management + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_LAYOUT_H +#define __IUP_LAYOUT_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* called from IupMap and IupRefresh */ +void iupLayoutCompute(Ihandle* ih); /* can be called before map */ +void iupLayoutUpdate(Ihandle* ih); /* called only after map */ + +/* Other functions declared in <iup.h> and implemented here. +IupRefresh +*/ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_ledlex.c b/iup/src/iup_ledlex.c new file mode 100755 index 0000000..3283a43 --- /dev/null +++ b/iup/src/iup_ledlex.c @@ -0,0 +1,366 @@ +/** \file + * \brief lexical analysis manager for LED + * + * See Copyright Notice in "iup.h" + */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <errno.h> + +#include "iup.h" + +#include "iup_class.h" +#include "iup_ledlex.h" +#include "iup_str.h" +#include "iup_table.h" +#include "iup_register.h" + + +static struct /* lexical variables */ +{ + const char* filename; /* file name */ + const char* f; + FILE* file; /* file handle */ + int token; /* lookahead iLexToken */ + char name[40960]; /* lexical identifier value */ + float number; /* lexical number value */ + int line; /* line number */ + Iclass *ic; /* control class when func is CONTROL_ */ +} ilex = {NULL, NULL, NULL, 0, "", (float) 0.0, 0, NULL}; + +static int iLexGetChar (void); +static int iLexToken(int *erro); +static int iLexCapture (char* dlm); +static int iLexSkip (char* dlm); +static int iLexCaptureAttr (void); + +int iupLexStart(const char* filename, int is_file) /* initialize lexical analysis */ +{ + ilex.filename = filename; + if (is_file) + { + ilex.file = fopen (ilex.filename,"r"); + if (!ilex.file) + return iupLexError (IUPLEX_FILENOTOPENED, filename); + } + else + { + ilex.f = ilex.filename; + ilex.file = NULL; + } + ilex.line = 0; + ilex.line = 1; + return iupLexAdvance(); +} + +void iupLexClose(void) +{ + if (!ilex.file) + return; + fclose (ilex.file); + ilex.file = NULL; +} + +static void iLexUngetc(int c) +{ + if (ilex.file) + ungetc(c, ilex.file); + else + { + if (*ilex.f != 0) + *(char*)ilex.f = (char)c; /* write back to the string ???? */ + } +} + +static int iLexGetc(void) +{ + if (ilex.file) + return getc(ilex.file); + else + { + if (*ilex.f != 0) + ilex.f++; + if (*ilex.f == 0) + return EOF; + return *ilex.f; + } +} + +int iupLexLookAhead(void) +{ + return ilex.token; +} + +int iupLexAdvance(void) +{ + int erro = 0; + ilex.token = iLexToken(&erro); + return erro; +} + +int iupLexFollowedBy(int t) +{ + return (ilex.token==t); +} + +int iupLexMatch(int t) +{ + if (ilex.token==t) + return iupLexAdvance(); + else + return iupLexError (IUPLEX_NOTMATCH, ilex.token, t); +} + + +int iupLexSeenMatch(int t, int *erro) +{ + if (ilex.token==t) + { + *erro = iupLexAdvance(); + return 1; + } + else + return 0; +} + +unsigned char iupLexByte(void) +{ + unsigned int b; + sscanf(ilex.name,"%u", &b); /* read as integer to avoid reading number as characters */ + if (b>255) b = 255; + return (unsigned char)b; +} + +int iupLexInt(void) +{ + int i; + sscanf(ilex.name,"%d", &i); + return i; +} + +float iupLexFloat(void) +{ + float f; + sscanf(ilex.name,"%g", &f); + return f; +} + +char* iupLexGetName(void) +{ + if (ilex.name) + return iupStrDup(ilex.name); + else + return NULL; +} + +char* iupLexName(void) +{ + return ilex.name; +} + +float iupLexGetNumber(void) +{ + return ilex.number; +} + +Iclass *iupLexGetClass(void) +{ + return ilex.ic; +} + +static int iLexToken(int *erro) +{ + for (;;) + { + int c = iLexGetChar(); + switch (c) + { + case 26: + case EOF: + return IUPLEX_TK_END; + + case ']': + return IUPLEX_TK_ENDATTR; + + case '#': /* iLexSkip comment */ + case '%': /* iLexSkip comment */ + iLexSkip ("\n\r"); + continue; + + case ' ': /* ignore whitespace */ + case '\t': + case '\n': + case '\r': + case '\f': + case '\v': + continue; + + case '=': /* attribuicao */ + return IUPLEX_TK_SET; + + case ',': + return IUPLEX_TK_COMMA; + + case '(': /* begin parameters */ + return IUPLEX_TK_BEGP; + + case ')': /* end parameters */ + return IUPLEX_TK_ENDP; + + case '[': /* attributes */ + if (iLexCaptureAttr() == IUPLEX_TK_END) + { + *erro=iupLexError (IUPLEX_NOTENDATTR); + return 0; + } + return IUPLEX_TK_ATTR; + + case '\"': /* string */ + iLexCapture ("\""); + return IUPLEX_TK_STR; + + case '\'': /* string */ + iLexCapture ("\'"); + return IUPLEX_TK_STR; + + default: + if (c > 32) /* identifier */ + { + char class_name[50]; + iLexUngetc(c); + iLexUngetc(iLexCapture ("=[](), \t\n\r\f\v")); + iupStrLower(class_name, iupLexName()); + ilex.ic = iupRegisterFindClass(class_name); + if (ilex.ic) + return IUPLEX_TK_FUNC; + else + return IUPLEX_TK_NAME; + } + } + return c; + } +} + +static int iLexCapture (char* dlm) +{ + int i=0; + int c; + do + { + c = iLexGetChar (); + if (i < sizeof(ilex.name)) + ilex.name[i++] = (char) c; + } while ((c > 0) && !strchr (dlm,c)); + ilex.name[i-1]='\0'; /* discard delimiter */ + return c; /* return delimiter */ +} + +static int iLexCaptureAttr (void) +{ + int i=0; + int c; + int aspas=0; + do + { + c = iLexGetChar (); + if (i < sizeof(ilex.name)) + ilex.name[i++] = (char) c; + if (c == '"') + ++aspas; + } while ((c > 0) && ((aspas & 1) || c != ']')); + ilex.name[i-1]='\0'; /* discard delimiter */ + return c; /* return delimiter */ +} + +static int iLexSkip (char* dlm) +{ + int c; + do + { + c = iLexGetChar (); + } while ((c > 0) && !strchr (dlm,c)); + return c; /* return delimiter */ +} + +static int iLexGetChar (void) +{ + int c = iLexGetc(); if (c == '\n') ++ilex.line; + if (c == '\\') + { + c = iLexGetc(); + if (c == 'n') + return '\n'; + else if (c == '\\') + return '\\'; + } + return c; +} + +static char* iupTokenStr(int t) +{ + switch (t) + { + case IUPLEX_TK_END : return "end of file"; + case IUPLEX_TK_BEGP : return "("; + case IUPLEX_TK_ENDP : return ")"; + case IUPLEX_TK_ATTR : return "["; + case IUPLEX_TK_STR : return "string"; + case IUPLEX_TK_NAME : return "identifier"; + case IUPLEX_TK_NUMB : return "number"; + case IUPLEX_TK_SET : return "="; + case IUPLEX_TK_COMMA: return ","; + case IUPLEX_TK_FUNC : return "function"; + case IUPLEX_TK_ENDATTR : return "]"; + } + return ""; +} + +static char ilex_erromsg[10240]; + +char *iupLexGetError(void) +{ + return ilex_erromsg; +} + +int iupLexError (int n, ...) +{ + char msg[10240]; + va_list va; + va_start(va,n); + switch (n) + { + case IUPLEX_FILENOTOPENED: + { + char *fn=va_arg(va,char *); + sprintf (msg, "cannot open file %s", fn); + } + break; + case IUPLEX_NOTMATCH: + { + int tr=va_arg(va,int); /* iLexToken read */ + int te=va_arg(va,int); /* iLexToken expected */ + char *str=iupTokenStr(tr); + char *ste=iupTokenStr(te); + sprintf (msg, "expected %s but found %s", ste, str); + } + break; + case IUPLEX_NOTENDATTR: + { + sprintf (msg, "missing ']'"); + } + break; + case IUPLEX_PARSEERROR: + { + char* s=va_arg(va,char*); /* iLexToken expected */ + sprintf(msg,"%.*s",(int)(sizeof(msg)-1),s); + } + break; + } + va_end(va); + sprintf(ilex_erromsg, "led(%s): bad input at line %d - %s\n", ilex.filename, ilex.line, msg); + return n; +} diff --git a/iup/src/iup_ledlex.h b/iup/src/iup_ledlex.h new file mode 100755 index 0000000..ad79ee1 --- /dev/null +++ b/iup/src/iup_ledlex.h @@ -0,0 +1,54 @@ +/** \file + * \brief lexical analysis manager for LED. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_LEX_H +#define __IUP_LEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* TOKENS */ +#define IUPLEX_TK_END -1 +#define IUPLEX_TK_BEGP 1 +#define IUPLEX_TK_ENDP 2 +#define IUPLEX_TK_ATTR 3 +#define IUPLEX_TK_STR 4 +#define IUPLEX_TK_NAME 5 +#define IUPLEX_TK_NUMB 6 +#define IUPLEX_TK_SET 7 +#define IUPLEX_TK_COMMA 8 +#define IUPLEX_TK_FUNC 9 +#define IUPLEX_TK_ENDATTR 10 + +/* ERRORS */ +#define IUPLEX_FILENOTOPENED 1 +#define IUPLEX_NOTMATCH 2 +#define IUPLEX_NOTENDATTR 3 +#define IUPLEX_PARSEERROR 4 + +char* iupLexGetError (void); +int iupLexStart (const char *filename, int is_file); +void iupLexClose (void); +int iupLexLookAhead (void); +int iupLexAdvance (void); +int iupLexFollowedBy (int t); +int iupLexMatch (int t); +int iupLexSeenMatch (int t, int *erro); +unsigned char iupLexByte (void); +int iupLexInt (void); +float iupLexFloat (void); +char* iupLexGetName (void); +char* iupLexName (void); +float iupLexGetNumber (void); +int iupLexError (int n, ...); +Iclass* iupLexGetClass (void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_ledparse.c b/iup/src/iup_ledparse.c new file mode 100755 index 0000000..2878e0b --- /dev/null +++ b/iup/src/iup_ledparse.c @@ -0,0 +1,288 @@ +/** \file + * \brief parser for LED. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <memory.h> +#include <string.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_ledlex.h" +#include "iup_str.h" +#include "iup_assert.h" + + +#define IPARSE_SYMBEXIST 1 +#define IPARSE_SYMBNOTDEF 2 + +static Ihandle* iParseExp (void); +static Ihandle* iParseFunction (Iclass *ic); +static int iParseError (int err, char *s); + +static int iparse_error = 0; +#define IPARSE_RETURN_IF_ERRO(_e) {iparse_error=(_e); if (iparse_error) return NULL;} +#define IPARSE_RETURN_IF_ERRO2(_e, _x) {iparse_error=(_e); if (iparse_error) { if (_x) free(_x); return NULL;} } + + +char* IupLoad(const char *filename) +{ + iupASSERT(filename!=NULL); + if (!filename) + return "invalid file name"; + + iparse_error = iupLexStart(filename, 1); + if (iparse_error) + { + iupLexClose(); + return iupLexGetError(); + } + + while (iupLexLookAhead() != IUPLEX_TK_END) + { + iParseExp(); + if (iparse_error) + { + iupLexClose(); + return iupLexGetError(); + } + } + + iupLexClose(); + return NULL; +} + +char* IupLoadBuffer(const char *buffer) +{ + iupASSERT(buffer!=NULL); + if (!buffer) + return "invalid buffer"; + + iparse_error = iupLexStart(buffer, 0); + if (iparse_error) + { + iupLexClose(); + return iupLexGetError(); + } + + while (iupLexLookAhead() != IUPLEX_TK_END) + { + iParseExp(); + if (iparse_error) + { + iupLexClose(); + return iupLexGetError(); + } + } + + iupLexClose(); + return NULL; +} + +static Ihandle* iParseExp(void) +{ + char* nm = NULL; + Ihandle* ih = NULL; + + int match = iupLexSeenMatch(IUPLEX_TK_FUNC,&iparse_error); + IPARSE_RETURN_IF_ERRO(iparse_error); + + if (match) + return iParseFunction(iupLexGetClass()); + + if (iupLexLookAhead() == IUPLEX_TK_NAME) + { + nm = iupLexGetName(); + IPARSE_RETURN_IF_ERRO(iupLexAdvance()); + } + else + { + iparse_error = iupLexMatch(IUPLEX_TK_NAME); + return NULL; /* force iparse_error */ + } + + match = iupLexSeenMatch(IUPLEX_TK_SET,&iparse_error); + IPARSE_RETURN_IF_ERRO(iparse_error); + + if (match) + { + ih = iParseExp(); + IPARSE_RETURN_IF_ERRO(iparse_error); + IupSetHandle(nm, ih); + } + else + { + ih = IupGetHandle(nm); + if (!ih) + IPARSE_RETURN_IF_ERRO(iParseError(IPARSE_SYMBNOTDEF,nm)); + } + + if (nm) free(nm); + return ih; +} + +static void* iParseControlParam(char type) +{ + switch(type) + { + case 'a': + IPARSE_RETURN_IF_ERRO(iupLexMatch(IUPLEX_TK_NAME)); + return iupLexGetName(); + + case 's': + IPARSE_RETURN_IF_ERRO(iupLexMatch(IUPLEX_TK_STR)); + return iupLexGetName(); + + case 'b': + case 'c': + IPARSE_RETURN_IF_ERRO(iupLexMatch(IUPLEX_TK_NAME)); + return (void*)(unsigned long)iupLexByte(); + + case 'i': + case 'j': + IPARSE_RETURN_IF_ERRO(iupLexMatch(IUPLEX_TK_NAME)); + return (void*)(unsigned long)iupLexInt(); + + case 'f': + IPARSE_RETURN_IF_ERRO(iupLexMatch(IUPLEX_TK_NAME)); + { + float f = iupLexFloat(); + unsigned long* l = (unsigned long*)&f; + return (void*)*l; + } + + case 'g': + case 'h': + { + char *new_control = (char*)iParseExp(); + IPARSE_RETURN_IF_ERRO(iparse_error); + return new_control; + } + + default: + return 0; + } +} + +static Ihandle* iParseControl(Iclass *ic) +{ + const char *format = ic->format; + if (!format || format[0] == 0) + return iupObjectCreate(ic, NULL); + else + { + Ihandle *new_control; + void** params; + int i, alloc_arg, num_arg, + num_format = strlen(format); + + num_arg = num_format; + alloc_arg = num_arg+20; + params = (void**)malloc(sizeof(void*)*alloc_arg); + + for (i = 0; i < num_arg; ) + { + char p_format = (char)tolower(format[i]); /* there is no optional parameters in LED */ + + if (i > 0) + IPARSE_RETURN_IF_ERRO2(iupLexMatch (IUPLEX_TK_COMMA), params); + + if (p_format != 'j' && /* not array */ + p_format != 'g' && + p_format != 'c') + { + params[i] = iParseControlParam(p_format); + i++; + IPARSE_RETURN_IF_ERRO2(iparse_error, params); + } + else /* array */ + { + int match; + do + { + if (num_arg == i) + { + num_arg++; + if (num_arg >= alloc_arg) + { + alloc_arg = num_arg+20; + params = realloc(params, sizeof(void*)*alloc_arg); + } + } + params[i] = iParseControlParam(p_format); + i++; + IPARSE_RETURN_IF_ERRO2(iparse_error, params); + match = iupLexSeenMatch(IUPLEX_TK_COMMA,&iparse_error); + IPARSE_RETURN_IF_ERRO2(iparse_error, params); + } while (match); + + /* after an array of parameters there are no more parameters */ + break; + } + } + + params[i] = NULL; + new_control = iupObjectCreate(ic, params); + + for (i = 0; params[i] && i<num_format ; i++) + { + if (format[i] == 'j' || + format[i] == 'g' || + format[i] == 'c') + break; + + if (format[i] == 'a' || format[i] == 's' || + format[i] == 'A' || format[i] == 'S') + free(params[i]); /* iupLexGetName returned a duplicated string */ + } + + free(params); + return new_control; + } +} + +static Ihandle* iParseFunction(Iclass *ic) +{ + Ihandle* ih = NULL; + char *attr = NULL; + + int match = iupLexSeenMatch(IUPLEX_TK_ATTR,&iparse_error); + IPARSE_RETURN_IF_ERRO(iparse_error); + + if (match) + attr = (char*)iupStrDup(iupLexName()); + + IPARSE_RETURN_IF_ERRO(iupLexMatch(IUPLEX_TK_BEGP)); + + ih = iParseControl(ic); + IPARSE_RETURN_IF_ERRO(iparse_error); + + if (attr) + { + IupSetAttributes(ih, attr); + free(attr); + } + + IPARSE_RETURN_IF_ERRO(iupLexMatch(IUPLEX_TK_ENDP)); + return ih; +} + +static int iParseError(int err, char *s) +{ + static char msg[256]; + switch (err) + { + case IPARSE_SYMBEXIST: + sprintf(msg, "symbol '%s' %s",s,"already exists"); + break; + case IUPLEX_NOTMATCH: + sprintf(msg, "symbol '%s' %s",s,"not defined"); + break; + } + return iupLexError(IUPLEX_PARSEERROR,msg); +} diff --git a/iup/src/iup_list.c b/iup/src/iup_list.c new file mode 100755 index 0000000..5965665 --- /dev/null +++ b/iup/src/iup_list.c @@ -0,0 +1,711 @@ +/** \file + * \brief List Control + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_assert.h" +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" +#include "iup_mask.h" +#include "iup_list.h" + + +void iupListSingleCallDblClickCallback(Ihandle* ih, IFnis cb, int pos) +{ + char *text; + char str[30]; + + if (pos<=0) + return; + + sprintf(str, "%d", pos); + text = IupGetAttribute(ih, str); + + if (cb(ih, pos, text) == IUP_CLOSE) + IupExitLoop(); +} + +static void iListCallActionCallback(Ihandle* ih, IFnsii cb, int pos, int state) +{ + char *text; + char str[30]; + + if (pos<=0) + return; + + sprintf(str, "%d", pos); + text = IupGetAttribute(ih, str); + + if (cb(ih, text, pos, state) == IUP_CLOSE) + IupExitLoop(); +} + +void iupListSingleCallActionCallback(Ihandle* ih, IFnsii cb, int pos) +{ + char* old_str = iupAttribGet(ih, "_IUPLIST_OLDVALUE"); + if (old_str) + { + int oldpos = atoi(old_str); + if (oldpos != pos) + { + iListCallActionCallback(ih, cb, oldpos, 0); + iListCallActionCallback(ih, cb, pos, 1); + } + } + else + iListCallActionCallback(ih, cb, pos, 1); + iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos); +} + +void iupListMultipleCallActionCallback(Ihandle* ih, IFnsii cb, IFns multi_cb, int* pos, int sel_count) +{ + int i, count = iupdrvListGetCount(ih); + + char* old_str = iupAttribGet(ih, "_IUPLIST_OLDVALUE"); + int old_count = old_str? strlen(old_str): 0; + + char* str = iupStrGetMemory(count+1); + memset(str, '-', count); + str[count]=0; + for (i=0; i<sel_count; i++) + str[pos[i]] = '+'; + + if (old_count != count) + { + old_count = 0; + old_str = NULL; + } + + if (multi_cb) + { + int unchanged = 1; + for (i=0; i<count && old_str; i++) + { + if (str[i] == old_str[i]) + str[i] = 'x'; /* mark unchanged values */ + else + unchanged = 0; + } + + if (old_str && unchanged) + return; + + if (multi_cb(ih, str) == IUP_CLOSE) + IupExitLoop(); + + for (i=0; i<count && old_str; i++) + { + if (str[i] == 'x') + str[i] = old_str[i]; /* restore unchanged values */ + } + } + else + { + /* must simulate the click on each item */ + for (i=0; i<count; i++) + { + if (i >= old_count) /* new items, if selected then call the callback */ + { + if (str[i] == '+') + iListCallActionCallback(ih, cb, i+1, 1); + } + else if (str[i] != old_str[i]) + { + if (str[i] == '+') + iListCallActionCallback(ih, cb, i+1, 1); + else + iListCallActionCallback(ih, cb, i+1, 0); + } + } + } + + iupAttribStoreStr(ih, "_IUPLIST_OLDVALUE", str); +} + +int iupListGetPos(Ihandle* ih, const char* name_id) +{ + int pos; + if (iupStrToInt(name_id, &pos)) + { + int count = iupdrvListGetCount(ih); + + pos--; /* IUP items start at 1 */ + + if (pos < 0) return -1; + if (pos > count-1) return -1; + + return pos; + } + return -1; +} + +void iupListSetInitialItems(Ihandle* ih) +{ + char str[20], *value; + int i = 1; + sprintf(str, "%d", i); + while ((value = iupAttribGet(ih, str))!=NULL) + { + iupdrvListAppendItem(ih, value); + iupAttribSetStr(ih, str, NULL); + + i++; + sprintf(str, "%d", i); + } +} + +char* iupListGetSpacingAttrib(Ihandle* ih) +{ + if (!ih->data->is_dropdown) + { + char *str = iupStrGetMemory(50); + sprintf(str, "%d", ih->data->spacing); + return str; + } + else + return NULL; +} + +char* iupListGetPaddingAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + char *str = iupStrGetMemory(50); + sprintf(str, "%dx%d", ih->data->horiz_padding, ih->data->vert_padding); + return str; + } + else + return NULL; +} + +char* iupListGetNCAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + char* str = iupStrGetMemory(100); + sprintf(str, "%d", ih->data->nc); + return str; + } + else + return NULL; +} + +int iupListSetIdValueAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int pos; + if (iupStrToInt(name_id, &pos)) + { + int count = iupdrvListGetCount(ih); + + pos--; /* IUP starts at 1 */ + + if (!value) + { + if (pos >= 0 && pos <= count-1) + { + if (pos == 0) + iupdrvListRemoveAllItems(ih); + else + { + int i = pos; + while (i < count) + { + iupdrvListRemoveItem(ih, pos); + i++; + } + } + } + } + else + { + if (pos >= 0 && pos <= count-1) + { + iupdrvListRemoveItem(ih, pos); + iupdrvListInsertItem(ih, pos, value); + } + else if (pos == count) + iupdrvListAppendItem(ih, value); + } + } + return 1; +} + +static int iListSetAppendItemAttrib(Ihandle* ih, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + if (value) + iupdrvListAppendItem(ih, value); + return 0; +} + +static int iListSetInsertItemAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + if (value) + { + int pos = iupListGetPos(ih, name_id); + if (pos!=-1) + iupdrvListInsertItem(ih, pos, value); + } + return 0; +} + +static int iListSetRemoveItemAttrib(Ihandle* ih, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + if (!value) + iupdrvListRemoveAllItems(ih); + else + { + int pos = iupListGetPos(ih, value); + if (pos!=-1) + iupdrvListRemoveItem(ih, pos); + } + return 0; +} + +static int iListGetCount(Ihandle* ih) +{ + int count; + if (ih->handle) + count = iupdrvListGetCount(ih); + else + { + char str[20]; + count = 0; + sprintf(str, "%d", count+1); + while (iupAttribGet(ih, str)) + { + count++; + sprintf(str, "%d", count+1); + } + } + return count; +} + +static char* iListGetCountAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(50); + sprintf(str, "%d", iListGetCount(ih)); + return str; +} + +static int iListSetDropdownAttrib(Ihandle* ih, const char* value) +{ + /* valid only before map */ + if (ih->handle) + return 0; + + if (iupStrBoolean(value)) + { + ih->data->is_dropdown = 1; + ih->data->is_multiple = 0; + } + else + ih->data->is_dropdown = 0; + + return 0; +} + +static char* iListGetDropdownAttrib(Ihandle* ih) +{ + if (ih->data->is_dropdown) + return "YES"; + else + return "NO"; +} + +static int iListSetMultipleAttrib(Ihandle* ih, const char* value) +{ + /* valid only before map */ + if (ih->handle) + return 0; + + if (iupStrBoolean(value)) + { + ih->data->is_multiple = 1; + ih->data->is_dropdown = 0; + ih->data->has_editbox = 0; + } + else + ih->data->is_multiple = 0; + + return 0; +} + +static char* iListGetMultipleAttrib(Ihandle* ih) +{ + if (ih->data->is_multiple) + return "YES"; + else + return "NO"; +} + +static int iListSetEditboxAttrib(Ihandle* ih, const char* value) +{ + /* valid only before map */ + if (ih->handle) + return 0; + + if (iupStrBoolean(value)) + { + ih->data->has_editbox = 1; + ih->data->is_multiple = 0; + } + else + ih->data->has_editbox = 0; + + return 0; +} + +static char* iListGetEditboxAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + return "YES"; + else + return "NO"; +} + +static int iListSetScrollbarAttrib(Ihandle* ih, const char* value) +{ + /* valid only before map */ + if (ih->handle) + return 0; + + else if (iupStrBoolean(value)) + ih->data->sb = 1; + else + ih->data->sb = 0; + + return 0; +} + +static char* iListGetScrollbarAttrib(Ihandle* ih) +{ + if (ih->data->sb) + return "YES"; + else + return "NO"; +} + +static char* iListGetMaskDataAttrib(Ihandle* ih) +{ + if (!ih->data->has_editbox) + return NULL; + + /* Used only by the OLD iupmask API */ + return (char*)ih->data->mask; +} + +static int iListSetMaskAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->has_editbox) + return 0; + + if (!value) + { + if (ih->data->mask) + iupMaskDestroy(ih->data->mask); + } + else + { + int casei = iupAttribGetInt(ih, "MASKCASEI"); + Imask* mask = iupMaskCreate(value,casei); + if (mask) + { + if (ih->data->mask) + iupMaskDestroy(ih->data->mask); + + ih->data->mask = mask; + return 1; + } + } + + return 0; +} + +static int iListSetMaskIntAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->has_editbox) + return 0; + + if (!value) + { + if (ih->data->mask) + iupMaskDestroy(ih->data->mask); + + iupAttribSetStr(ih, "MASK", NULL); + } + else + { + Imask* mask; + int min, max; + + if (iupStrToIntInt(value, &min, &max, ':')!=2) + return 0; + + mask = iupMaskCreateInt(min,max); + + if (ih->data->mask) + iupMaskDestroy(ih->data->mask); + + ih->data->mask = mask; + + if (min < 0) + iupAttribSetStr(ih, "MASK", IUP_MASK_INT); + else + iupAttribSetStr(ih, "MASK", IUP_MASK_UINT); + } + + return 0; +} + +static int iListSetMaskFloatAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->has_editbox) + return 0; + + if (!value) + { + if (ih->data->mask) + iupMaskDestroy(ih->data->mask); + + iupAttribSetStr(ih, "MASK", NULL); + } + else + { + Imask* mask; + float min, max; + + if (iupStrToFloatFloat(value, &min, &max, ':')!=2) + return 0; + + mask = iupMaskCreateFloat(min,max); + + if (ih->data->mask) + iupMaskDestroy(ih->data->mask); + + ih->data->mask = mask; + + if (min < 0) + iupAttribSetStr(ih, "MASK", IUP_MASK_FLOAT); + else + iupAttribSetStr(ih, "MASK", IUP_MASK_UFLOAT); + } + + return 0; +} + + +/*****************************************************************************************/ + + +static int iListCreateMethod(Ihandle* ih, void** params) +{ + if (params && params[0]) + iupAttribStoreStr(ih, "ACTION", (char*)(params[0])); + + ih->data = iupALLOCCTRLDATA(); + ih->data->sb = 1; + + return IUP_NOERROR; +} + +static void iListGetNaturalItemsSize(Ihandle *ih, int *w, int *h) +{ + char *value; + int visiblecolumns, + count = iListGetCount(ih); + + *w = 0; + *h = 0; + + iupdrvFontGetCharSize(ih, w, h); /* one line height, and one character width */ + + visiblecolumns = iupAttribGetInt(ih, "VISIBLECOLUMNS"); + if (visiblecolumns) + { + *w = iupdrvFontGetStringWidth(ih, "WWWWWWWWWW"); + *w = (visiblecolumns*(*w))/10; + } + else + { + int item_w, i; + char str[20]; + + for (i=1; i<=count; i++) + { + sprintf(str, "%d", i); + value = IupGetAttribute(ih, str); /* must use IupGetAttribute to check the native system */ + if (value) + { + item_w = iupdrvFontGetStringWidth(ih, value); + if (item_w > *w) + *w = item_w; + } + } + + if (*w == 0) /* default is 5 characters in 1 item */ + *w = iupdrvFontGetStringWidth(ih, "WWWWW"); + } + + /* compute height for multiple lines, drodown is just 1 line */ + if (!ih->data->is_dropdown) + { + int visiblelines, num_lines, line_size = *h; + + iupdrvListAddItemSpace(ih, h); /* this independs from spacing */ + + *h += 2*ih->data->spacing; /* this will be multiplied by the number of lines */ + *w += 2*ih->data->spacing; /* include also horizontal spacing */ + + num_lines = count; + if (num_lines == 0) num_lines = 1; + + visiblelines = iupAttribGetInt(ih, "VISIBLELINES"); + if (visiblelines) + num_lines = visiblelines; + + *h = *h * num_lines; + + if (ih->data->has_editbox) + *h += line_size; + } +} + +static void iListComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + int natural_w, natural_h; + int sb_size = iupdrvGetScrollbarSize(); + (void)expand; /* unset if not a container */ + + iListGetNaturalItemsSize(ih, &natural_w, &natural_h); + + /* compute the borders space */ + iupdrvListAddBorders(ih, &natural_w, &natural_h); + + if (ih->data->is_dropdown) + { + /* add room for dropdown box */ + natural_w += sb_size; + + if (natural_h < sb_size) + natural_h = sb_size; + } + else + { + /* add room for scrollbar */ + if (ih->data->sb) + { + natural_h += sb_size; + natural_w += sb_size; + } + } + + if (ih->data->has_editbox) + { + natural_w += 2*ih->data->horiz_padding; + natural_h += 2*ih->data->vert_padding; + } + + *w = natural_w; + *h = natural_h; +} + +static void iListDestroyMethod(Ihandle* ih) +{ + if (ih->data->mask) + iupMaskDestroy(ih->data->mask); +} + + +/******************************************************************************/ + + +Ihandle* IupList(const char* action) +{ + void *params[2]; + params[0] = (void*)action; + params[1] = NULL; + return IupCreatev("list", params); +} + +Iclass* iupListGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "list"; + ic->format = "A"; /* one optional callback name */ + ic->nativetype = IUP_TYPECONTROL; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + ic->has_attrib_id = 1; + + /* Class functions */ + ic->Create = iListCreateMethod; + ic->Destroy = iListDestroyMethod; + ic->ComputeNaturalSize = iListComputeNaturalSizeMethod; + + ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Callbacks */ + iupClassRegisterCallback(ic, "ACTION", "sii"); + iupClassRegisterCallback(ic, "MULTISELECT_CB", "s"); + iupClassRegisterCallback(ic, "DROPFILES_CB", "siii"); + iupClassRegisterCallback(ic, "DROPDOWN_CB", "i"); + iupClassRegisterCallback(ic, "DBLCLICK_CB", "is"); + iupClassRegisterCallback(ic, "VALUECHANGED_CB", ""); + + iupClassRegisterCallback(ic, "EDIT_CB", "is"); + iupClassRegisterCallback(ic, "CARET_CB", "iii"); + + /* Common Callbacks */ + iupBaseRegisterCommonCallbacks(ic); + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Visual */ + iupBaseRegisterVisualAttrib(ic); + + /* IupList only */ + iupClassRegisterAttribute(ic, "SCROLLBAR", iListGetScrollbarAttrib, iListSetScrollbarAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MULTIPLE", iListGetMultipleAttrib, iListSetMultipleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DROPDOWN", iListGetDropdownAttrib, iListSetDropdownAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "EDITBOX", iListGetEditboxAttrib, iListSetEditboxAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "COUNT", iListGetCountAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "INSERTITEM", NULL, iListSetInsertItemAttrib, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "APPENDITEM", NULL, iListSetAppendItemAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "REMOVEITEM", NULL, iListSetRemoveItemAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AUTOHIDE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "MASKCASEI", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MASK", NULL, iListSetMaskAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MASKINT", NULL, iListSetMaskIntAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MASKFLOAT", NULL, iListSetMaskFloatAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "OLD_MASK_DATA", iListGetMaskDataAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "VISIBLECOLUMNS", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VISIBLELINES", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupdrvListInitClass(ic); + + return ic; +} diff --git a/iup/src/iup_list.h b/iup/src/iup_list.h new file mode 100755 index 0000000..045116b --- /dev/null +++ b/iup/src/iup_list.h @@ -0,0 +1,53 @@ +/** \file + * \brief List Control + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_LIST_H +#define __IUP_LIST_H + +#ifdef __cplusplus +extern "C" { +#endif + + +void iupdrvListInitClass(Iclass* ic); +void iupdrvListAddBorders(Ihandle* ih, int *w, int *h); +void iupdrvListAddItemSpace(Ihandle* ih, int *h); +int iupdrvListGetCount(Ihandle* ih); +void iupdrvListAppendItem(Ihandle* ih, const char* value); +void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value); +void iupdrvListRemoveItem(Ihandle* ih, int pos); +void iupdrvListRemoveAllItems(Ihandle* ih); + +int iupListGetPos(Ihandle* ih, const char* name_id); +int iupListSetIdValueAttrib(Ihandle* ih, const char* name_id, const char* value); +void iupListSetInitialItems(Ihandle* ih); +void iupListSingleCallActionCallback(Ihandle* ih, IFnsii cb, int pos); +void iupListMultipleCallActionCallback(Ihandle* ih, IFnsii cb, IFns multi_cb, int* pos, int sel_count); +char* iupListGetNCAttrib(Ihandle* ih); +char* iupListGetPaddingAttrib(Ihandle* ih); +char* iupListGetSpacingAttrib(Ihandle* ih); +void iupListSingleCallDblClickCallback(Ihandle* ih, IFnis cb, int pos); + +struct _IcontrolData +{ + int sb, /* scrollbar configuration, can be changed only before map */ + nc, + spacing, + horiz_padding, + vert_padding, + last_caret_pos, + is_multiple, + is_dropdown, + has_editbox; + Imask* mask; +}; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_mask.c b/iup/src/iup_mask.c new file mode 100755 index 0000000..f241a22 --- /dev/null +++ b/iup/src/iup_mask.c @@ -0,0 +1,146 @@ +/** \file + * \brief mask pattern matching + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "iup_maskparse.h" +#include "iup_mask.h" +#include "iup_str.h" + + +#define IUP_MASK_FLOAT "[+/-]?(/d+/.?/d*|/./d+)" +#define IUP_MASK_UFLOAT "(/d+/.?/d*|/./d+)" +#define IUP_MASK_INT "[+/-]?/d+" +#define IUP_MASK_UINT "/d+" + +struct _Imask +{ + char* mask_str; + ImaskParsed* fsm; + int casei; + char type; + float fmin, + fmax; + int imin, + imax; +}; + + +int iupMaskCheck(Imask* mask, const char *val) +{ + int ret; + + /* empty text or no mask */ + if (!val || !(*val) || !mask) + return 1; + + ret = iupMaskMatch(val,mask->fsm,0,NULL,NULL,NULL,mask->casei); + if (ret == IMASK_PARTIALMATCH) + return -1; + if (ret != (int)strlen(val)) + return 0; + + switch(mask->type) + { + case 'I': + { + int ival = 0; + sscanf(val,"%d",&ival); + if(ival < mask->imin || ival > mask->imax) + return 0; + break; + } + case 'F': + { + float fval = 0; + sscanf(val,"%f",&fval); + if(fval < mask->fmin || fval > mask->fmax) + return 0; + break; + } + } + + return 1; +} + +Imask* iupMaskCreate(const char* mask_str, int casei) +{ + ImaskParsed* fsm; + Imask* mask; + char* copy_mask_str; + + if (!mask_str) + return NULL; + + /* Parse the mask first */ + copy_mask_str = iupStrDup(mask_str); + if (iupMaskParse(copy_mask_str, &fsm) != IMASK_PARSE_OK) + { + free(copy_mask_str); + return NULL; + } + + mask = (Imask*)malloc(sizeof(Imask)); + memset(mask, 0, sizeof(Imask)); + + mask->mask_str = copy_mask_str; + mask->casei = casei; + mask->fsm = fsm; + + return mask; +} + +Imask* iupMaskCreateInt(int min, int max) +{ + Imask* mask; + + if (min < 0) + mask = iupMaskCreate(IUP_MASK_INT, 0); + else + mask = iupMaskCreate(IUP_MASK_UINT, 0); + + if (mask) + { + mask->imin = min; + mask->imax = max; + mask->type = 'I'; + } + + return mask; +} + +Imask* iupMaskCreateFloat(float min, float max) +{ + Imask* mask; + + if (min < 0) + mask = iupMaskCreate(IUP_MASK_FLOAT, 0); + else + mask = iupMaskCreate(IUP_MASK_UFLOAT, 0); + + if (mask) + { + mask->fmin = min; + mask->fmax = max; + mask->type = 'F'; + } + + return mask; +} + +void iupMaskDestroy(Imask* mask) +{ + free(mask->mask_str); + free(mask->fsm); + free(mask); +} + +char* iupMaskGetStr(Imask* mask) +{ + return mask->mask_str; +} diff --git a/iup/src/iup_mask.h b/iup/src/iup_mask.h new file mode 100755 index 0000000..5e87f24 --- /dev/null +++ b/iup/src/iup_mask.h @@ -0,0 +1,55 @@ +/** \file + * \brief Mask functions + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_MASK_H +#define __IUP_MASK_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup mask Text Mask + * \par + * Used to filter text input in IupText. + * \par + * See \ref iup_mask.h + * \ingroup util */ + +typedef struct _Imask Imask; + +/** Creates a mask given a string. \n + * If casei is true, will turn the mask case insensitive. + * \ingroup mask */ +Imask* iupMaskCreate(const char* mask_str, int casei); + +/** Creates an integer mask with limits. + * \ingroup mask */ +Imask* iupMaskCreateInt(int min, int max); + +/** Creates a float mask with limits. + * \ingroup mask */ +Imask* iupMaskCreateFloat(float min, float max); + +/** Destroys the mask. + * \ingroup mask */ +void iupMaskDestroy(Imask* mask); + +/** Check if the value is valid using the mask to filter it. + * Returns 1 if full match, -1 if partial match, and 0 otherwise. + * \ingroup mask */ +int iupMaskCheck(Imask* mask, const char *value); + +/** Returns the mask string. + * \ingroup mask */ +char* iupMaskGetStr(Imask* mask); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_maskmatch.c b/iup/src/iup_maskmatch.c new file mode 100755 index 0000000..f0aa9fd --- /dev/null +++ b/iup/src/iup_maskmatch.c @@ -0,0 +1,582 @@ +/** \file + * \brief iupmask imask_match_functions + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "iup_maskparse.h" +#include "iup_maskmatch.h" + + +#define IMASK_MIN_STACK_ELEMENTS 1000 +enum {IMASK_CAPT_OPEN, IMASK_CAPT_CLOSE}; + +typedef struct _ImaskCapt +{ + struct _ImaskCapt* next_one; + int type; + short which_one; + long pos; +} ImaskCapt; + +typedef struct _ImaskMatchVars +{ + const char *text; + ImaskParsed *fsm; + iMaskMatchFunc function; + short *tested; + void *user; +} ImaskMatchVars; + + +typedef struct _ImaskStack +{ + short *stack; + short size; +} ImaskStack; + + +#define isalphanum(_x) (isalnum((int)(_x)) || ((_x) == '_')) + + +/* match functions corresponding to regular expressions */ + +static int match_blanks (const char *text, long j) +{ + return (((text[j] == '\t') || (text[j] == '\xff') || (text[j] == ' ') || + (text[j] == '\n'))) ? IMASK_NORMAL_MATCH : IMASK_NO_MATCH; +} + +static int match_non_blanks (const char *text, long j) +{ + return (!((text[j] == '\t') || (text[j] == '\xff') || + (text[j] == ' ') || (text[j] == '\n'))) + ? IMASK_NORMAL_MATCH : IMASK_NO_MATCH; +} + +static int match_alpha (const char *text, long j) +{ + return (isalpha((int)text[j])) ? IMASK_NORMAL_MATCH : IMASK_NO_MATCH; +} + +static int match_non_alpha (const char *text, long j) +{ + return (!isalpha((int)text[j]) && (text[j] != '\0')) + ? IMASK_NORMAL_MATCH : IMASK_NO_MATCH; +} + +static int match_digit (const char *text, long j) +{ + return (isdigit((int)text[j])) ? IMASK_NORMAL_MATCH : IMASK_NO_MATCH; +} + +static int match_non_digit (const char *text, long j) +{ + return (!isdigit((int)text[j]) && (text[j] != '\0')) + ? IMASK_NORMAL_MATCH : IMASK_NO_MATCH; +} + +static int match_alphanum (const char *text, long j) +{ + return isalphanum (text[j]) ? IMASK_NORMAL_MATCH : IMASK_NO_MATCH; +} + +static int match_non_alphanum (const char *text, long j) +{ + return (isalphanum (text[j]) || (text[j] == '\0')) + ? IMASK_NO_MATCH : IMASK_NORMAL_MATCH; +} + +static int match_word_boundary (const char *text, long j) +{ + if ((j == 0) && isalphanum (text[j])) + return IMASK_NO_CHAR_MATCH; + + else if (isalphanum (text[j - 1]) && !isalphanum (text[j])) + return IMASK_NO_CHAR_MATCH; + + else if (isalphanum (text[j]) && !isalphanum (text[j - 1])) + return IMASK_NO_CHAR_MATCH; + + return IMASK_NO_MATCH; + +} + +static ImaskMatchFunc imask_match_functions[] = +{ + {'w', &match_alphanum}, + {'W', &match_non_alphanum}, + {'d', &match_digit}, + {'D', &match_non_digit}, + {'S', &match_non_blanks}, + {'s', &match_blanks}, + {'b', &match_word_boundary}, + {'l', &match_alpha}, + {'L', &match_non_alpha}, + {'\0', NULL} +}; + +ImaskMatchFunc* iupMaskMatchGetFuncs(void) +{ + return imask_match_functions; +} + +static void iMaskMatchCaptureResult (ImaskMatchVars * vars, ImaskCapt * capture) +{ + ImaskCapt *next = NULL; + + while (capture != NULL) + { + ImaskCapt *cap = capture->next_one; + + capture->next_one = next; + next = capture; + capture = cap; + } + + capture = next; + next = NULL; + + while (capture != NULL) + { + if (capture->type == IMASK_CAPT_OPEN) + { + ImaskCapt *cap = capture->next_one; + + capture->next_one = next; + next = capture; + capture = cap; + } + else + { + if (capture->pos >= next->pos) + (*vars->function)((char)capture->which_one, next->pos, capture->pos, vars->text, vars->user); + + next = next->next_one; + capture = capture->next_one; + } + } +} + +static long iMaskMatchRecursive (ImaskMatchVars * vars, long j, int state, ImaskCapt * capture, int size) +{ + switch (vars->fsm[state].command) + { + case IMASK_NULL_CMD: + if (vars->fsm[state].next1 == 0) /*se chegou ao fim da maquina de estados */ + { + if (vars->function != NULL) + iMaskMatchCaptureResult (vars, capture); /* guarda capturas */ + + return j; + } + + /* verifica o estado atual ja foi avaliado antes */ + { + int count; + for (count = 0; count < size; count++) + if (vars->tested[count] == state) + return IMASK_NOMATCH; + } + + vars->tested[size++] = (short)state; /* indicada que o estado foi testado */ + + /* se houverem dois ramos, chama a funcao recursivamente, + retornando com o primeiro que completar a maquina */ + + if (vars->fsm[state].next1 != vars->fsm[state].next2) + { + long a; + + a = iMaskMatchRecursive (vars, j, vars->fsm[state].next2, capture, size); + + if (a != IMASK_NOMATCH) /* se deu match */ + return a; + + a = iMaskMatchRecursive (vars, j, vars->fsm[state].next1, capture, size); + + return a; + } + break; + + case IMASK_CAP_OPEN_CMD: + { + long a; + ImaskCapt new_cap; + + new_cap.next_one = capture; + new_cap.type = IMASK_CAPT_OPEN; + new_cap.pos = j; + new_cap.which_one = vars->fsm[state].ch; + + a = iMaskMatchRecursive (vars, j, vars->fsm[state].next1, &new_cap, size); + + return a; + } + break; + + case IMASK_CAP_CLOSE_CMD: + { + long a; + ImaskCapt new_cap; + + new_cap.next_one = capture; + new_cap.type = IMASK_CAPT_CLOSE; + new_cap.pos = j - 1; + new_cap.which_one = vars->fsm[state].ch; + + a = iMaskMatchRecursive (vars, j, vars->fsm[state].next1, &new_cap, size); + + return a; + } + + case IMASK_CLASS_CMD: + { + int temp, found = 0, negate; + + temp = vars->fsm[state].next1; + negate = vars->fsm[state].next2; + state++; + + while (vars->fsm[state].command != IMASK_NULL_CMD) + { + if (vars->fsm[state].command == IMASK_CLASS_CMD_RANGE) + { + if ((vars->text[j] >= vars->fsm[state].ch) && + (vars->text[j] <= vars->fsm[state].next1)) + { + found = 1; + break; + } + } + + else if ((vars->fsm[state].command == IMASK_CLASS_CMD_CHAR) && + (vars->text[j] == vars->fsm[state].ch)) + { + found = 1; + break; + }; + state++; + } + + if (found ^ negate) + { + if (vars->text[j] == '\0') + return IMASK_NOMATCH; + j++; + vars->tested = &vars->tested[size + 1]; + size = 0; + return iMaskMatchRecursive (vars, j, temp, capture, size); + } + else + return IMASK_NOMATCH; + } + + case IMASK_CHAR_CMD: + if (vars->text[j] != vars->fsm[state].ch) + return IMASK_NOMATCH; + j++; + vars->tested = &vars->tested[size + 1]; + size = 0; + break; + + case IMASK_ANY_CMD: + if ((vars->text[j] == '\0') || (vars->text[j] == '\n')) + return IMASK_NOMATCH; + j++; + vars->tested = &vars->tested[size + 1]; + size = 0; + break; + + case IMASK_SPC_CMD: + { + long a; + + a = (*imask_match_functions[(int) vars->fsm[state].ch].function) (vars->text, j); + + switch (a) + { + case IMASK_NO_MATCH: + return IMASK_NOMATCH; + + case IMASK_NORMAL_MATCH: + j++; + vars->tested = &vars->tested[size + 1]; + size = 0; + break; + + case IMASK_NO_CHAR_MATCH:; /* does nothing */ + } + } + break; + + case IMASK_BEGIN_CMD: + if (!((vars->text[j - 1] == '\n') || (j == 0))) + return IMASK_NOMATCH; + + break; + + case IMASK_END_CMD: + if (!((vars->text[j] == '\n') || (vars->text[j] == '\0'))) + return IMASK_NOMATCH; + + break; + } + + return iMaskMatchRecursive (vars, j, vars->fsm[state].next1, capture, size); +} + +static int iMaskInStack (ImaskStack * stack, int state) +{ + int a; + for (a = 0; a < stack->size; a++) + if (stack->stack[a] == state) + return 1; + + return 0; +} + +static void iMaskNewStack (ImaskStack * new_stack, short *stack) +{ + new_stack->size = 0; + new_stack->stack = stack; +} + +static void iMaskPushStack (ImaskStack * stack, int value) +{ + stack->stack[stack->size++] = (short)value; +} + +static void iMaskMoveStack (ImaskStack * dest, ImaskStack * source) +{ + short *temp = dest->stack; + dest->stack = source->stack; + source->stack = temp; + + dest->size = source->size; + source->size = 0; +} + +/* non recursive */ +static long iMaskMatchLocal (const char *text, ImaskParsed * fsm, long start, char *addchar, int casei) +{ + int finished = IMASK_NOMATCH; + ImaskStack now, next; + short a1[IMASK_MIN_STACK_ELEMENTS]; + short a2[IMASK_MIN_STACK_ELEMENTS]; + int state; + int j = 0; + int pos; + + if (addchar) addchar[0] = 0; + + j = start; + + iMaskNewStack(&now, a1); + iMaskNewStack(&next, a2); + + iMaskPushStack (&now, fsm[0].next1); + + for (;;) + { + for (pos = 0; pos < now.size; pos++) + { + state = now.stack[pos]; + + if (state == 0) + { + finished = j - start; + continue; + } + + if (fsm[state].command == IMASK_NULL_CMD) + { + if(!iMaskInStack (&now, fsm[state].next2)) + iMaskPushStack (&now, fsm[state].next2); + + if(fsm[state].next1 != fsm[state].next2) + { + if(!iMaskInStack (&now, fsm[state].next1)) + iMaskPushStack (&now, fsm[state].next1); + } + } + else if (text[j] == '\0'); /* ignore \0 */ + else if (((fsm[state].command == IMASK_CHAR_CMD) && + ((!casei && fsm[state].ch == text[j]) || + (casei && tolower(fsm[state].ch) == tolower(text[j])) + ) + ) || + ((fsm[state].command == IMASK_ANY_CMD) && + (text[j] != '\n') + ) + ) + iMaskPushStack (&next, fsm[state].next1); + else if (fsm[state].command == IMASK_SPC_CMD) + { + int ret; + + ret = (*(imask_match_functions[(int) fsm[state].ch].function))(text, j); + switch (ret) + { + case IMASK_NO_MATCH: + break; + + case IMASK_NORMAL_MATCH: + iMaskPushStack (&next, fsm[state].next1); + break; + + case IMASK_NO_CHAR_MATCH: + iMaskPushStack (&now, fsm[state].next1); + break; + } + } + else if (fsm[state].command == IMASK_CLASS_CMD) + { + int temp, found = 0, negate; + + temp = fsm[state].next1; + negate = fsm[state].next2; + state++; + + while (fsm[state].command != IMASK_NULL_CMD) + { + if (fsm[state].command == IMASK_CLASS_CMD_RANGE) + { + if((!casei && (text[j]>=fsm[state].ch) && + (text[j]<=fsm[state].next1) + ) || + (casei && (tolower(text[j])>=tolower(fsm[state].ch)) && + (tolower(text[j])<=tolower(fsm[state].next1)) + ) + ) + { + found = 1; + break; + } + } + else if ((fsm[state].command == IMASK_CLASS_CMD_CHAR) && + ((!casei && text[j] == fsm[state].ch) || + (casei && tolower(text[j]) == tolower(fsm[state].ch)) + ) + ) + { + found = 1; + break; + } + state++; + } + + if(found ^ negate) + { + iMaskPushStack (&next, temp); + state = temp; + } + } + else if (fsm[state].command == IMASK_BEGIN_CMD) + { + if (text[j - 1] == '\n' || j == 0) + iMaskPushStack (&now, fsm[state].next1); + } + else if (fsm[state].command == IMASK_END_CMD) + { + if (text[j] == '\n' || text[j] == '\0') + iMaskPushStack (&now, fsm[state].next1); + } + } + + if (text[j] == '\0') + { + if(next.size == 0 && finished == j) + { + return finished; + } + else if(addchar) + { + int pos; + + for (pos = 0; pos < now.size; pos++) + { + state = now.stack[pos]; + if (fsm[state].command == IMASK_CHAR_CMD) + { + iMaskPushStack (&next, state); + } + else if (fsm[state].command != IMASK_NULL_CMD) + { + next.size = 0; + break; + } + else + { + if (!iMaskInStack (&now, fsm[state].next2)) + iMaskPushStack (&now, fsm[state].next2); + + if (fsm[state].next1 != fsm[state].next2) + { + if (!iMaskInStack (&now, fsm[state].next1)) + iMaskPushStack (&now, fsm[state].next1); + } + } + } + + iMaskMoveStack (&now, &next); + + if (now.size == 1) + { + int inx=0; + state = now.stack[0]; + while(fsm[state].next1 == fsm[state].next2) + { + if(fsm[state].command == IMASK_CHAR_CMD) + addchar[inx++] = fsm[state].ch; + else if(fsm[state].command != IMASK_NULL_CMD) + break; + + state = fsm[state].next1; + } + addchar[inx]=0; + } + } + return IMASK_PARTIALMATCH; + } + + j++; + + if (next.size == 0) + { + if (finished > IMASK_NOMATCH) + return finished; + + return IMASK_NOMATCH; + } + + iMaskMoveStack (&now, &next); + } +} + +int iupMaskMatch (const char *text, ImaskParsed * fsm, long start, iMaskMatchFunc function, void *user, char *addchar, int icase) +{ + long ret; + short tested[10000]; /* to be eliminated */ + ImaskMatchVars vars; + + /* use recursive only for standard capture */ + + if (fsm[0].ch == IMASK_NOCAPTURE) + return iMaskMatchLocal (text, fsm, start, addchar, icase); + + vars.text = text; + vars.fsm = fsm; + vars.tested = tested; + vars.function = function; + vars.user = user; + + ret = iMaskMatchRecursive (&vars, start, fsm[0].next1, NULL, 0); + + return (int)((ret >= start) ? ret - start : ret); +} diff --git a/iup/src/iup_maskmatch.h b/iup/src/iup_maskmatch.h new file mode 100755 index 0000000..d0c7918 --- /dev/null +++ b/iup/src/iup_maskmatch.h @@ -0,0 +1,62 @@ +/** \file + * \brief Mask match private definitions + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_MASKMATCH_H +#define __IUP_MASKMATCH_H + +#ifdef __cplusplus +extern "C" { +#endif + + +enum +{ + IMASK_NULL_CMD=1, + IMASK_ANY_CMD=2, + IMASK_CHAR_CMD=3, + IMASK_SPC_CMD=4, + IMASK_CLASS_CMD=5, + IMASK_BEGIN_CMD=6, + IMASK_END_CMD=7, + IMASK_CAP_OPEN_CMD=71, + IMASK_CAP_CLOSE_CMD=72, + IMASK_NEG_OPEN_CMD=81, + IMASK_NEG_CLOSE_CMD=82 +}; + +enum +{ + IMASK_CLASS_CMD_RANGE=50, + IMASK_CLASS_CMD_CHAR=51 +}; + +enum +{ + IMASK_NORMAL_MATCH, + IMASK_NO_CHAR_MATCH, + IMASK_NO_MATCH +}; + +enum +{ + IMASK_CAPTURE=100, + IMASK_NOCAPTURE=101 +}; + +typedef struct _ImaskMatchFunc +{ + char ch; + int (*function) (const char *, long); +} ImaskMatchFunc; + +ImaskMatchFunc* iupMaskMatchGetFuncs(void); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_maskparse.c b/iup/src/iup_maskparse.c new file mode 100755 index 0000000..859d951 --- /dev/null +++ b/iup/src/iup_maskparse.c @@ -0,0 +1,547 @@ +/** \file + * \brief imask parser + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <setjmp.h> + +#include "iup_maskparse.h" +#include "iup_maskmatch.h" + +/* + * Table of characters (customizaveis atraves de iupMaskSetChar) + */ + +static char *imask_parse_chars = "|*+()[]-^/.?^${}~"; +/* 01234567890123456 */ + +#define OR_CH imask_parse_chars[0] /* OR CHaracter */ +#define CL_CH imask_parse_chars[1] /* CLosure CHaracter */ +#define OOM_CH imask_parse_chars[2] /* One Or More CHaracter */ +#define OPGR_CH imask_parse_chars[3] /* OPen GRoup CHaracter */ +#define CLGR_CH imask_parse_chars[4] /* CLose GRoup CHaracter */ +#define OPCL_CH imask_parse_chars[5] /* OPen CLass CHaracter */ +#define CLCL_CH imask_parse_chars[6] /* CLose CLass CHaracter */ +#define SEPCL_CH imask_parse_chars[7] /* SEParate CLass CHaracter */ +#define NEGCL_CH imask_parse_chars[8] /* NEGation CLass CHaracter */ +#define SPC_CH imask_parse_chars[9] /* SPeCial function CHaracter */ +#define ANY_CH imask_parse_chars[10] /* ANY CHaracter */ +#define ONE_CH imask_parse_chars[11] /* ONE or no CHaracter */ +#define BEGIN_CH imask_parse_chars[12] /* BEGINning of a line CHaracter*/ +#define END_CH imask_parse_chars[13] /* END of a line CHaracter */ +#define CAP_OPEN_CH imask_parse_chars[14] /* CAPture OPEN CHaracter */ +#define CAP_CLOSE_CH imask_parse_chars[15] /* CAPture CLOSE CHaracter */ +#define NEG_CH imask_parse_chars[16] /* NEGation CHaracter */ + +#define SPC2_CH '\\' /* SPeCial 2 CHaracter */ + +#define isvalid(c) (c != 0 && c != OR_CH && c != OPGR_CH && c != CLGR_CH &&\ + c != CL_CH && c != OPCL_CH && c != CLCL_CH &&\ + c != CAP_OPEN_CH && c != CAP_CLOSE_CH && c != OOM_CH) + +#define STATE_BLOCK 30 + +typedef struct _ImaskParseVars +{ + const char *string; + int state, j, num_states; + ImaskParsed *fsm; + short capture[30]; + short size; + char nextcap; + jmp_buf env; +} ImaskParseVars; + +static int iMaskParseExpression (ImaskParseVars * vars); +static int iMaskParseTerm (ImaskParseVars * vars); +static int iMaskParseFactor (ImaskParseVars * vars); +static void iMaskParseError (ImaskParseVars *vars); +static void iMaskParseNewState (ImaskParseVars * vars); +static void iMaskParseSetState (ImaskParseVars * vars, int state, char ch, char command, int next1, int next2); + +int iupMaskSetChar (int char_number, char new_char) +{ + if ((char_number < 0) || (char_number > (int)strlen(imask_parse_chars))) + return 0; + + imask_parse_chars[char_number] = new_char; + + return 1; +} + + /* + * Funcao de interface, recebe padrao e retorna array contendo as finite + * state machines (fsm) construidas a partir do padrao + */ + +int iupMaskParse(const char *text, ImaskParsed ** fsm) +{ + int t; + ImaskParseVars vars; + + /* inicializacao das variaveis */ + + vars.state = 1; + vars.j = 0; + vars.num_states = 0; + vars.size = 0; + vars.nextcap = 0; + vars.string = text; + + if ((vars.fsm = (ImaskParsed *) malloc (STATE_BLOCK * sizeof (ImaskParsed))) == NULL) + return IMASK_MEM_ERROR; + + vars.num_states = STATE_BLOCK; + + /* a principio, nao ha captura. Se ocorrer uma, ele e setado + para IMASK_CAPTURE */ + + vars.fsm[0].ch = IMASK_NOCAPTURE; + + if (setjmp (vars.env) == 0) + t = iMaskParseExpression (&vars); + + else + { + free (vars.fsm); + return IMASK_PARSE_ERROR; + } + + /* seta os estados inicial e final, guardando no inicial + (fsm[0].next1) o tamanho da maquina */ + + iMaskParseSetState (&vars, 0, vars.fsm[0].ch, IMASK_NULL_CMD, t, vars.state + 1); + iMaskParseSetState (&vars, vars.state, 0, IMASK_NULL_CMD, 0, 0); + + *fsm = vars.fsm; + + return IMASK_PARSE_OK; +} + +static int iMaskParseExpression (ImaskParseVars * vars) +{ + int r, t1; + int last_state = vars->state - 1; + + t1 = iMaskParseTerm (vars); + r = t1; + + if (vars->string[vars->j] == OR_CH) + { + int t2 = vars->state; + int t3; + + r = t2; + + vars->j++; + iMaskParseNewState (vars); + + t3 = iMaskParseExpression (vars); /* pega o 2o ramo do OR */ + + /* faz o primeiro state antes do OR apontar para o state de entrada + * do OR */ + + if (vars->fsm[last_state].next1 == t1) + vars->fsm[last_state].next1 = t2; + + if (vars->fsm[last_state].next2 == t1) + vars->fsm[last_state].next2 = t2; + + /* faz o ultimo state do primeiro ramo do OR apontar para o + * state de saida do OR */ + + if (vars->fsm[t2 - 1].next1 == t2) + vars->fsm[t2 - 1].next1 = vars->state; + + if (vars->fsm[t2 - 1].next2 == t2) + vars->fsm[t2 - 1].next2 = vars->state; + + iMaskParseSetState (vars, t2, 0, IMASK_NULL_CMD, t1, t3); + iMaskParseSetState (vars, vars->state, 0, IMASK_NULL_CMD, vars->state + 1, + vars->state + 1); + + iMaskParseNewState (vars); + } + return r; +} + +static int iMaskParseTerm (ImaskParseVars * vars) +{ + int r; + + r = iMaskParseFactor (vars); + + if ((vars->string[vars->j] == OPGR_CH) || + (isvalid (vars->string[vars->j])) || + (vars->string[vars->j] == OPCL_CH) || + (vars->string[vars->j] == CAP_OPEN_CH) || + (vars->string[vars->j] == NEG_CH)) + iMaskParseTerm (vars); + + if (!((vars->string[vars->j] == OR_CH) || + (vars->string[vars->j] == CLGR_CH) || + (vars->string[vars->j] == '\0') || + (vars->string[vars->j] == CAP_CLOSE_CH))) + iMaskParseError (vars); + + return r; +} + +static int iMaskParseFactor (ImaskParseVars * vars) +{ + int r, t1, t2 = 0; + + t1 = vars->state; + + if (vars->string[vars->j] == OPGR_CH) + { + vars->j++; + t2 = iMaskParseExpression (vars); + + if (vars->string[vars->j] == CLGR_CH) + vars->j++; + else + iMaskParseError (vars); + } + + else if (vars->string[vars->j] == CAP_OPEN_CH) + { + vars->fsm[0].ch = IMASK_CAPTURE; + iMaskParseSetState (vars, vars->state, vars->nextcap, + IMASK_CAP_OPEN_CMD, vars->state + 1, vars->state + 1); + t2 = vars->state; + iMaskParseNewState (vars); + vars->capture[++vars->size] = vars->nextcap++; + vars->j++; + + iMaskParseExpression (vars); + + if (vars->string[vars->j] == CAP_CLOSE_CH) + { + iMaskParseSetState (vars, vars->state, (char)vars->capture[vars->size--], + IMASK_CAP_CLOSE_CMD, vars->state + 1, vars->state + 1); + + iMaskParseNewState (vars); + vars->j++; + } + else + iMaskParseError (vars); + + } + + else if (vars->string[vars->j] == ANY_CH) + { + iMaskParseSetState (vars, vars->state, 1, IMASK_ANY_CMD, vars->state + 1, vars->state + 1); + t2 = vars->state; + vars->j++; + iMaskParseNewState (vars); + } + + else if (vars->string[vars->j] == NEG_CH) + { + int t6; + t2 = vars->state; + vars->j++; + iMaskParseNewState (vars); + t6 = iMaskParseFactor (vars); + iMaskParseSetState (vars, t2, 1, IMASK_NEG_OPEN_CMD, t6, vars->state); + iMaskParseSetState (vars, vars->state, 1, IMASK_NEG_CLOSE_CMD, vars->state + 1, vars->state + 1); + iMaskParseNewState (vars); + } + + else if (vars->string[vars->j] == BEGIN_CH) + { + iMaskParseSetState (vars, vars->state, 1, IMASK_BEGIN_CMD, vars->state + 1, + vars->state + 1); + t2 = vars->state; + vars->j++; + iMaskParseNewState (vars); + } + else if (vars->string[vars->j] == END_CH) + { + iMaskParseSetState (vars, vars->state, 1, IMASK_END_CMD, vars->state + 1, + vars->state + 1); + t2 = vars->state; + vars->j++; + iMaskParseNewState (vars); + } + + else if (isvalid (vars->string[vars->j]) && (vars->string[vars->j] + != SPC_CH) && (vars->string[vars->j] != ANY_CH)) + { + iMaskParseSetState (vars, vars->state, vars->string[vars->j], + IMASK_CHAR_CMD, vars->state + 1, vars->state + 1); + t2 = vars->state; + vars->j++; + iMaskParseNewState (vars); + } + + else if (vars->string[vars->j] == OPCL_CH) + { + vars->j++; + iMaskParseSetState (vars, vars->state, 0, IMASK_CLASS_CMD, 0, 0); + + if (vars->string[vars->j] == NEGCL_CH) + { + vars->fsm[vars->state].next2 = 1; + vars->j++; + } + + t2 = vars->state; + iMaskParseNewState (vars); + + if (vars->string[vars->j] == SEPCL_CH) + iMaskParseError (vars); + + while ((vars->string[vars->j] != CLCL_CH) && (vars->string[vars->j] != '\n') + && (vars->string[vars->j] != '\0')) + { + if (vars->string[vars->j] == SPC_CH) + { + char temp; + + vars->j++; + switch (vars->string[vars->j]) + { + case 'n': + temp = '\n'; + break; + + case 't': + temp = '\t'; + break; + + case 'e': + temp = 27; + break; + + default: + temp = vars->string[vars->j]; + } + iMaskParseSetState (vars, vars->state, temp, IMASK_CLASS_CMD_CHAR, 0, 0); + vars->j++; + iMaskParseNewState (vars); + } + else if (vars->string[vars->j] == SEPCL_CH) + { + char temp = 0; + + vars->j++; + + if (vars->string[vars->j] == SPC_CH) + { + vars->j++; + switch (vars->string[vars->j]) + { + case 'n': + temp = '\n'; + break; + + case 't': + temp = '\t'; + break; + + case 'e': + temp = 27; + break; + + default: + temp = vars->string[vars->j]; + } + } + else if (vars->string[vars->j] != CLCL_CH) + temp = vars->string[vars->j]; + + else + iMaskParseError (vars); + + iMaskParseSetState (vars, vars->state - 1, vars->fsm[vars->state - 1].ch, + IMASK_CLASS_CMD_RANGE, temp, 0); + vars->j++; + } + else if (vars->string[vars->j] == BEGIN_CH) + { + iMaskParseSetState (vars, vars->state, 1, IMASK_BEGIN_CMD, vars->state + 1, vars->state + 1); + t2 = vars->state; + vars->j++; + iMaskParseNewState (vars); + } + else if (vars->string[vars->j] == END_CH) + { + iMaskParseSetState (vars, vars->state, 1, IMASK_END_CMD, vars->state + 1, vars->state + 1); + t2 = vars->state; + vars->j++; + iMaskParseNewState (vars); + } + + else + { + iMaskParseSetState (vars, vars->state, vars->string[vars->j], IMASK_CLASS_CMD_CHAR, 0, 0); + vars->j++; + iMaskParseNewState (vars); + } + + } + if (vars->string[vars->j] != CLCL_CH) + iMaskParseError (vars); + iMaskParseSetState (vars, vars->state, 0, IMASK_NULL_CMD, vars->state + 1, vars->state + 1); + vars->fsm[t2].next1 = vars->state; + vars->j++; + iMaskParseNewState (vars); + + } + + else if (vars->string[vars->j] == SPC_CH) + { + int loop1 = 0; + ImaskMatchFunc* match_functions = iupMaskMatchGetFuncs(); + + vars->j++; + + while (match_functions[loop1].ch != '\0' && + match_functions[loop1].ch != vars->string[vars->j]) + loop1++; + + if (match_functions[loop1].ch == '\0') + { + int temp; + + switch (vars->string[vars->j]) + { + case 'n': + temp = '\n'; + break; + + case 't': + temp = '\t'; + break; + + case 'e': + temp = 27; + break; + + case 'x': + vars->j++; + sscanf (&vars->string[vars->j], "%2x", &temp); + vars->j++; + break; + + case 'o': + vars->j++; + sscanf (&vars->string[vars->j], "%3o", &temp); + vars->j += 2; + break; + + default: + if (isdigit((int)vars->string[vars->j])) + { + sscanf (&vars->string[vars->j], "%3d", &temp); + if (temp > 255) + { + iMaskParseError (vars); + } + vars->j += 2; + } + else + temp = vars->string[vars->j]; + } + iMaskParseSetState (vars, vars->state, (char)temp, IMASK_CHAR_CMD, vars->state + 1, vars->state + 1); + } + + else + { + iMaskParseSetState (vars, vars->state, (char)loop1, IMASK_SPC_CMD, vars->state + 1, vars->state + 1); + } + + t2 = vars->state; + vars->j++; + iMaskParseNewState (vars); + } + else + iMaskParseError (vars); + + if (vars->string[vars->j] == CL_CH) + { + iMaskParseSetState (vars, vars->state, 0, IMASK_NULL_CMD, vars->state + 1, t2); + r = vars->state; + + if (vars->fsm[t1 - 1].next1 == t1) + vars->fsm[t1 - 1].next1 = vars->state; + + if (vars->fsm[t1 - 1].next2 == t1) + vars->fsm[t1 - 1].next2 = vars->state; + + vars->j++; + iMaskParseNewState (vars); + } + + else if (vars->string[vars->j] == ONE_CH) + { + iMaskParseSetState (vars, vars->state, 0, IMASK_NULL_CMD, vars->state + 1, t2); + r = vars->state; + + if (vars->fsm[t1 - 1].next1 == t1) + vars->fsm[t1 - 1].next1 = vars->state; + + if (vars->fsm[t1 - 1].next2 == t1) + vars->fsm[t1 - 1].next2 = vars->state; + + if (vars->fsm[vars->state - 1].next1 == vars->state) + vars->fsm[vars->state - 1].next1 = vars->state + 1; + + if (vars->fsm[vars->state - 1].next2 == vars->state) + vars->fsm[vars->state - 1].next2 = vars->state + 1; + + vars->j++; + iMaskParseNewState (vars); + + iMaskParseSetState (vars, vars->state, 0, IMASK_NULL_CMD, vars->state + 1, vars->state + 1); + + iMaskParseNewState (vars); + } + else if (vars->string[vars->j] == OOM_CH) + { + iMaskParseSetState (vars, vars->state, 0, IMASK_NULL_CMD, vars->state + 1, t2); + r = t2; + + vars->j++; + + iMaskParseNewState (vars); + + } + else + r = t2; + + return r; +} + +static void iMaskParseError (ImaskParseVars * vars) +{ + longjmp (vars->env, 1); +} + +static void iMaskParseNewState (ImaskParseVars * vars) +{ + + if (vars->state >= vars->num_states - 1) + { + ImaskParsed *new_fsm = (ImaskParsed*) realloc (vars->fsm, (vars->num_states + STATE_BLOCK) * sizeof (ImaskParsed)); + vars->fsm = new_fsm; + vars->num_states += STATE_BLOCK; + } + + vars->state++; +} + +static void iMaskParseSetState (ImaskParseVars * vars, int state, char ch, char command, int next1, int next2) +{ + vars->fsm[state].ch = ch; + vars->fsm[state].command = command; + vars->fsm[state].next1 = next1; + vars->fsm[state].next2 = next2; +} diff --git a/iup/src/iup_maskparse.h b/iup/src/iup_maskparse.h new file mode 100755 index 0000000..a12a7fa --- /dev/null +++ b/iup/src/iup_maskparse.h @@ -0,0 +1,46 @@ +/** \file + * \brief Mask internal functions + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_MASKPARSE_H +#define __IUP_MASKPARSE_H + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct _ImaskParsed +{ + char ch; + int command; + int next1; + int next2; +} ImaskParsed; + +typedef int (*iMaskMatchFunc) (char which_one, long next_pos, long capture_pos, const char *text, void* user_data); + +/* Parse the mask and if it is ok create and returns the internal structure. */ +int iupMaskParse(const char* mask, ImaskParsed** imk); + +/* Do the pattern matching on the given text. */ +int iupMaskMatch(const char* text, ImaskParsed* imk, long start, iMaskMatchFunc mask_func, void* user_data, char *addchar, int icase); + +/* Change a control character. */ +int iupMaskSetChar(int char_number, char new_char); + +/* iupMaskMatch return codes */ +#define IMASK_PARSE_OK 0 /* No error */ +#define IMASK_NOMATCH -1 /* no match */ +#define IMASK_MEM_ERROR -2 /* memory error */ +#define IMASK_PARSE_ERROR -3 /* parser error */ +#define IMASK_PARTIALMATCH -4 /* partial match */ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_menu.c b/iup/src/iup_menu.c new file mode 100755 index 0000000..7e62744 --- /dev/null +++ b/iup/src/iup_menu.c @@ -0,0 +1,364 @@ +/** \file + * \brief Menu Resources. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <memory.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_assert.h" +#include "iup_key.h" +#include "iup_stdcontrols.h" +#include "iup_drvinfo.h" +#include "iup_menu.h" + + +struct _IcontrolData +{ + int child_id; /* serial number used by child controls */ +}; + +static Ihandle* iMenuGetTopMenu(Ihandle* ih) +{ + for (; ih->parent; ih = ih->parent) + ; /* empty*/ + return ih; +} + +int iupMenuGetChildId(Ihandle* ih) +{ + Ihandle* dlg = IupGetDialog(ih); + if (dlg) + return iupDialogGetChildId(ih); + else + { + int id; + ih = iMenuGetTopMenu(ih); + if (!ih) return -1; + id = ih->data->child_id; + if (id == 0) id = 100; /* initial number */ + ih->data->child_id = id+1; + return id; + } +} + +char* iupMenuGetChildIdStr(Ihandle* ih) +{ + Ihandle* dlg = IupGetDialog(ih); + if (dlg) + return iupDialogGetChildIdStr(ih); + else + { + char *str = iupStrGetMemory(50); + Ihandle* dialog = iMenuGetTopMenu(ih); + sprintf(str, "iup-%s-%d", ih->iclass->name, dialog->data->child_id); + return str; + } +} + +int iupMenuIsMenuBar(Ihandle* ih) +{ + if (ih->parent && ih->parent->iclass->nativetype == IUP_TYPEDIALOG) + return 1; + else + return 0; +} + +static void iMenuAdjustPos(int *x, int *y) +{ + int cursor_x = 0, cursor_y = 0; + int screen_width = 0, screen_height = 0; + + if (*x == IUP_CENTER || *y == IUP_CENTER || + *x == IUP_RIGHT || *y == IUP_RIGHT || + *x == IUP_CENTERPARENT || *y == IUP_CENTERPARENT) + iupdrvGetScreenSize(&screen_width, &screen_height); + + if (*x == IUP_MOUSEPOS || *y == IUP_MOUSEPOS) + iupdrvGetCursorPos(&cursor_x, &cursor_y); + + switch (*x) + { + case IUP_CENTER: + *x = screen_width/2; + break; + case IUP_LEFT: + *x = 0; + break; + case IUP_RIGHT: + *x = screen_width; + break; + case IUP_MOUSEPOS: + *x = cursor_x; + break; + } + + switch (*y) + { + case IUP_CENTER: + *y = screen_height/2; + break; + case IUP_LEFT: + *y = 0; + break; + case IUP_RIGHT: + *y = screen_height; + break; + case IUP_MOUSEPOS: + *y = cursor_y; + break; + } +} + +char* iupMenuProcessTitle(Ihandle* ih, const char* title) +{ + int keychar; + char* str; + + char* key = iupAttribGet(ih, "KEY"); + if (!key) return (char*)title; + + keychar = iupKeyNameToCode(key); + if (!keychar) return (char*)title; + + str = strchr(title, keychar); + if (str) + { + int len = strlen(title); + char *new_title = malloc(len+1+1); + int pos = str-title; + memcpy(new_title, title, pos); + new_title[pos] = '&'; + memcpy(new_title+pos+1, title+pos, len-pos+1); + return new_title; + } + + return (char*)title; +} + +int iupMenuPopup(Ihandle* ih, int x, int y) +{ + iMenuAdjustPos(&x, &y); + return iupdrvMenuPopup(ih, x, y); +} + + +/******************************************************************/ + + +static int iItemCreateMethod(Ihandle* ih, void** params) +{ + if (params) + { + if (params[0]) iupAttribStoreStr(ih, "TITLE", (char*)(params[0])); + if (params[1]) iupAttribStoreStr(ih, "ACTION", (char*)(params[1])); + } + return IUP_NOERROR; +} + +static int iSubmenuCreateMethod(Ihandle* ih, void** params) +{ + if (params) + { + if (params[0]) iupAttribStoreStr(ih, "TITLE", (char*)(params[0])); + if (params[1]) + { + Ihandle* child = (Ihandle*)(params[1]); + if (child->iclass->nativetype == IUP_TYPEMENU) + IupAppend(ih, child); + } + } + return IUP_NOERROR; +} + +static int iMenuCreateMethod(Ihandle* ih, void** params) +{ + ih->data = iupALLOCCTRLDATA(); + + if (params) + { + Ihandle** iparams = (Ihandle**)params; + while (*iparams) + { + Ihandle* child = (Ihandle*)(*iparams); + if (child->iclass->nativetype == IUP_TYPEMENU) + IupAppend(ih, child); + iparams++; + } + } + + return IUP_NOERROR; +} + + +/******************************************************************************************/ + + +Iclass* iupSeparatorGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "separator"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPEMENU; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 0; + + /* Common */ + iupClassRegisterAttribute(ic, "WID", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "NAME", NULL, iupBaseSetNameAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupdrvSeparatorInitClass(ic); + + return ic; +} + +Iclass* iupItemGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "item"; + ic->format = "SA"; /* one optional string and one optional callback name */ + ic->nativetype = IUP_TYPEMENU; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + + /* Class functions */ + ic->Create = iItemCreateMethod; + + /* Callbacks */ + iupClassRegisterCallback(ic, "HIGHLIGHT_CB", ""); + iupClassRegisterCallback(ic, "ACTION", ""); + + /* Common Callbacks */ + iupClassRegisterCallback(ic, "MAP_CB", ""); + iupClassRegisterCallback(ic, "UNMAP_CB", ""); + iupClassRegisterCallback(ic, "HELP_CB", ""); + + /* Common */ + iupClassRegisterAttribute(ic, "WID", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "NAME", NULL, iupBaseSetNameAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "AUTOTOGGLE", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "KEY", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupdrvItemInitClass(ic); + + return ic; +} + +Iclass* iupSubmenuGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "submenu"; + ic->format = "SH"; /* one string and one Ihandle (both optional) */ + ic->nativetype = IUP_TYPEMENU; + ic->childtype = IUP_CHILD_ONE; + ic->is_interactive = 1; + + /* Class functions */ + ic->Create = iSubmenuCreateMethod; + + /* Callbacks */ + iupClassRegisterCallback(ic, "HIGHLIGHT_CB", ""); + + /* Common Callbacks */ + iupClassRegisterCallback(ic, "MAP_CB", ""); + iupClassRegisterCallback(ic, "UNMAP_CB", ""); + + /* Common */ + iupClassRegisterAttribute(ic, "WID", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "NAME", NULL, iupBaseSetNameAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "KEY", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupdrvSubmenuInitClass(ic); + + return ic; +} + +Iclass* iupMenuGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "menu"; + ic->format = "g"; /* (Ihandle**) */ + ic->nativetype = IUP_TYPEMENU; + ic->childtype = IUP_CHILDMANY; + ic->is_interactive = 1; + + /* Class functions */ + ic->Create = iMenuCreateMethod; + + /* Callbacks */ + iupClassRegisterCallback(ic, "OPEN_CB", ""); + iupClassRegisterCallback(ic, "MENUCLOSE_CB", ""); + + /* Common Callbacks */ + iupClassRegisterCallback(ic, "MAP_CB", ""); + iupClassRegisterCallback(ic, "UNMAP_CB", ""); + + /* Common */ + iupClassRegisterAttribute(ic, "WID", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "NAME", NULL, iupBaseSetNameAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "RADIO", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupdrvMenuInitClass(ic); + + return ic; +} + +/************************************************************************/ + +Ihandle* IupItem(const char* title, const char* action) +{ + void *params[2]; + params[0] = (void*)title; + params[1] = (void*)action; + return IupCreatev("item", params); +} + +Ihandle* IupSubmenu(const char* title, Ihandle* child) +{ + void *params[2]; + params[0] = (void*)title; + params[1] = (void*)child; + return IupCreatev("submenu", params); +} + +Ihandle *IupMenuv(Ihandle **children) +{ + return IupCreatev("menu", (void**)children); +} + +Ihandle *IupMenu(Ihandle *child, ...) +{ + Ihandle **children; + Ihandle *ih; + + va_list arglist; + va_start(arglist, child); + children = (Ihandle **)iupObjectGetParamList(child, arglist); + va_end(arglist); + + ih = IupCreatev("menu", (void**)children); + free(children); + + return ih; +} + +Ihandle* IupSeparator(void) +{ + return IupCreate("separator"); +} diff --git a/iup/src/iup_menu.h b/iup/src/iup_menu.h new file mode 100755 index 0000000..f1eb164 --- /dev/null +++ b/iup/src/iup_menu.h @@ -0,0 +1,35 @@ +/** \file + * \brief IUP Menu Class + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_MENU_H +#define __IUP_MENU_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Shows a popup menu in the given position. +* Must return IUP_ERROR or IUP_NOERROR. +* Called only from IupPopup. +*/ +int iupMenuPopup(Ihandle* ih, int x, int y); + +int iupdrvMenuPopup(Ihandle* ih, int x, int y); +void iupdrvSeparatorInitClass(Iclass* ic); +void iupdrvItemInitClass(Iclass* ic); +void iupdrvMenuInitClass(Iclass* ic); +void iupdrvSubmenuInitClass(Iclass* ic); + +char* iupMenuProcessTitle(Ihandle* ih, const char* title); +int iupMenuGetChildId(Ihandle* ih); +char* iupMenuGetChildIdStr(Ihandle* ih); +int iupMenuIsMenuBar(Ihandle* ih); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_messagedlg.c b/iup/src/iup_messagedlg.c new file mode 100755 index 0000000..816e740 --- /dev/null +++ b/iup/src/iup_messagedlg.c @@ -0,0 +1,70 @@ +/** \file + * \brief IupMessageDlg class + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_stdcontrols.h" + + +Ihandle* IupMessageDlg(void) +{ + return IupCreate("messagedlg"); +} + +Iclass* iupMessageDlgGetClass(void) +{ + Iclass* ic = iupClassNew(iupDialogGetClass()); + + ic->name = "messagedlg"; + ic->nativetype = IUP_TYPEDIALOG; + ic->is_interactive = 1; + + /* reset not used native dialog methods */ + ic->parent->LayoutUpdate = NULL; + ic->parent->SetChildrenPosition = NULL; + ic->parent->Map = NULL; + ic->parent->UnMap = NULL; + + iupdrvMessageDlgInitClass(ic); + + /* only the default values */ + iupClassRegisterAttribute(ic, "DIALOGTYPE", NULL, NULL, IUPAF_SAMEASSYSTEM, "MESSAGE", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "BUTTONS", NULL, NULL, IUPAF_SAMEASSYSTEM, "OK", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "BUTTONDEFAULT", NULL, NULL, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "BUTTONRESPONSE", NULL, NULL, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT); + + return ic; +} + +void IupMessage(const char* title, const char* message) +{ + Ihandle* dlg = IupCreate("messagedlg"); + + IupSetAttribute(dlg, "TITLE", (char*)title); + IupSetAttribute(dlg, "VALUE", (char*)message); + IupSetAttribute(dlg, "PARENTDIALOG", IupGetGlobal("PARENTDIALOG")); + + IupPopup(dlg, IUP_CENTER, IUP_CENTER); + IupDestroy(dlg); +} + +void IupMessagef(const char *title, const char *format, ...) +{ + static char message[SHRT_MAX]; + va_list arglist; + va_start(arglist, format); + vsprintf(message, format, arglist); + va_end (arglist); + IupMessage(title, message); +} diff --git a/iup/src/iup_names.c b/iup/src/iup_names.c new file mode 100755 index 0000000..9ec01a6 --- /dev/null +++ b/iup/src/iup_names.c @@ -0,0 +1,193 @@ +/** \file + * \brief Ihandle <-> Name table manager. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> + +#include "iup.h" + +#include "iup_str.h" +#include "iup_table.h" +#include "iup_names.h" +#include "iup_object.h" +#include "iup_class.h" +#include "iup_assert.h" +#include "iup_str.h" + + +static Itable *inames_strtable = NULL; /* table indexed by name containing Ihandle* address */ +static Itable *inames_ihtable = NULL; /* table indexed by Ihandle* address containing names */ + +void iupNamesDestroyHandles(void) +{ + char *name; + Ihandle** ih_array, *ih; + int count, i = 0; + + count = iupTableCount(inames_strtable); + if (!count) + return; + + ih_array = (Ihandle**)malloc(count * sizeof(Ihandle*)); + + /* store the names before updating so we can remove elements in the loop */ + name = iupTableFirst(inames_strtable); + while (name) + { + ih = (Ihandle*)iupTableGetCurr(inames_strtable); + if (iupObjectCheck(ih)) + { + ih_array[i] = ih; + i++; + } + name = iupTableNext(inames_strtable); + } + + count = i; + for (i = 0; i < count; i++) + { + if (iupObjectCheck(ih_array[i])) + IupDestroy(ih_array[i]); + } + + free(ih_array); +} + +void iupNamesInit(void) +{ + inames_strtable = iupTableCreate(IUPTABLE_STRINGINDEXED); + inames_ihtable = iupTableCreate(IUPTABLE_POINTERINDEXED); +} + +void iupNamesFinish(void) +{ + iupTableDestroy(inames_strtable); + inames_strtable = NULL; + + iupTableDestroy(inames_ihtable); + inames_ihtable = NULL; +} + +void iupRemoveAllNames(Ihandle* ih) +{ + char *name; + Ihandle *cur_ih; + + name = iupTableFirst(inames_strtable); + while (name) + { + cur_ih = (Ihandle*)iupTableGetCurr(inames_strtable); + if (iupObjectCheck(cur_ih) && cur_ih == ih) + iupTableRemoveCurr(inames_strtable); + + name = iupTableNext(inames_strtable); + } + + iupTableRemove(inames_ihtable, (char*)ih); +} + +Ihandle *IupGetHandle(const char *name) +{ + if (!name) /* no iupASSERT needed here */ + return NULL; + return (Ihandle*)iupTableGet (inames_strtable, name); +} + +Ihandle* IupSetHandle(const char *name, Ihandle *ih) +{ + Ihandle *old_ih; + + iupASSERT(name!=NULL); + if (!name) + return NULL; + + old_ih = iupTableGet(inames_strtable, name); + if (ih != NULL) + { + iupTableSet(inames_strtable, name, ih, IUPTABLE_POINTER); + iupTableSet(inames_ihtable, (char*)ih, (char*)name, IUPTABLE_STRING); /* keep only the last name set */ + } + else + { + ih = iupTableGet(inames_strtable, name); + iupTableRemove(inames_strtable, name); + if (ih) + { + char* cur_name = iupTableGet(inames_ihtable, (char*)ih); + if (iupStrEqualNoCase(cur_name, name)) + iupTableRemove(inames_ihtable, (char*)ih); + } + } + return old_ih; +} + +int IupGetAllNames(char** names, int n) +{ + int i = 0; + char* name; + + if (!names || !n) + return iupTableCount(inames_strtable); + + name = iupTableFirst(inames_strtable); + while (name) + { + names[i] = name; + i++; + if (i == n) + break; + + name = iupTableNext(inames_strtable); + } + return i; +} + +static int iNamesCountDialogs(void) +{ + int i = 0; + char* name = iupTableFirst(inames_strtable); + while (name) + { + Ihandle* dlg = (Ihandle*)iupTableGetCurr(inames_strtable); + if (iupObjectCheck(dlg) && dlg->iclass->nativetype == IUP_TYPEDIALOG) + i++; + + name = iupTableNext(inames_strtable); + } + return i; +} + +int IupGetAllDialogs(char** names, int n) +{ + int i = 0; + char* name; + + if (!names || !n) + return iNamesCountDialogs(); + + name = iupTableFirst(inames_strtable); + while (name) + { + Ihandle* dlg = (Ihandle*)iupTableGetCurr(inames_strtable); + if (iupObjectCheck(dlg) && dlg->iclass->nativetype == IUP_TYPEDIALOG) + { + names[i] = name; + i++; + if (i == n) + break; + } + + name = iupTableNext(inames_strtable); + } + return i; +} + +char* IupGetName(Ihandle* ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return NULL; + return iupTableGet(inames_ihtable, (char*)ih); +} diff --git a/iup/src/iup_names.h b/iup/src/iup_names.h new file mode 100755 index 0000000..9d3adc7 --- /dev/null +++ b/iup/src/iup_names.h @@ -0,0 +1,34 @@ +/** \file + * \brief Ihandle <-> Name table manager. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_NAMES_H +#define __IUP_NAMES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* called only in IupOpen and IupClose */ +void iupNamesInit(void); +void iupNamesFinish(void); +void iupNamesDestroyHandles(void); + +/* called from IupDestroy */ +void iupRemoveAllNames(Ihandle* ih); + +/* Other functions declared in <iup.h> and implemented here. +IupGetName +IupGetAllDialogs +IupGetAllNames +IupSetHandle +IupGetHandle +*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_normalizer.c b/iup/src/iup_normalizer.c new file mode 100755 index 0000000..7f7a5ff --- /dev/null +++ b/iup/src/iup_normalizer.c @@ -0,0 +1,188 @@ +/** \file + * \brief Normalizer Element. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_array.h" +#include "iup_stdcontrols.h" + + +enum {NORMALIZE_NONE, NORMALIZE_WIDTH, NORMALIZE_HEIGHT}; + +struct _IcontrolData +{ + Iarray* ih_array; +}; + +int iupNormalizeGetNormalizeSize(const char* value) +{ + if (!value) + return NORMALIZE_NONE; + if (iupStrEqualNoCase(value, "HORIZONTAL")) + return NORMALIZE_WIDTH; + if (iupStrEqualNoCase(value, "VERTICAL")) + return NORMALIZE_HEIGHT; + if (iupStrEqualNoCase(value, "BOTH")) + return NORMALIZE_WIDTH|NORMALIZE_HEIGHT; + return NORMALIZE_NONE; +} + +char* iupNormalizeGetNormalizeSizeStr(int normalize) +{ + char* int2str[] = {"NONE", "HORIZONTAL", "VERTICAL", "BOTH"}; + return int2str[normalize]; +} + +void iupNormalizeSizeBoxChild(Ihandle *ih, int normalize, int children_natural_maxwidth, int children_natural_maxheight) +{ + /* It is called from Vbox and Hbox ComputeNaturalSizeMethod after the natural size is calculated */ + /* reset the natural width and/or height */ + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + { + if (!child->is_floating && (child->iclass->nativetype != IUP_TYPEVOID || !iupStrEqual(child->iclass->name, "fill"))) + { + if (normalize & NORMALIZE_WIDTH) + child->naturalwidth = children_natural_maxwidth; + if (normalize & NORMALIZE_HEIGHT) + child->naturalheight = children_natural_maxheight; + } + } +} + +static int iNormalizerSetNormalizeAttrib(Ihandle* ih, const char* value) +{ + int i, count; + Ihandle** ih_list; + Ihandle* ih_control; + int natural_maxwidth = 0, natural_maxheight = 0; + int normalize = iupNormalizeGetNormalizeSize(value); + if (!normalize) + return 1; + + count = iupArrayCount(ih->data->ih_array); + ih_list = (Ihandle**)iupArrayGetData(ih->data->ih_array); + + for (i = 0; i < count; i++) + { + ih_control = ih_list[i]; + iupBaseComputeNaturalSize(ih_control); + natural_maxwidth = iupMAX(natural_maxwidth, ih_control->naturalwidth); + natural_maxheight = iupMAX(natural_maxheight, ih_control->naturalheight); + } + + for (i = 0; i < count; i++) + { + ih_control = ih_list[i]; + if (!ih_control->is_floating && (ih_control->iclass->nativetype != IUP_TYPEVOID || !iupStrEqual(ih_control->iclass->name, "fill"))) + { + if (normalize & NORMALIZE_WIDTH) + ih_control->userwidth = natural_maxwidth; + if (normalize & NORMALIZE_HEIGHT) + ih_control->userheight = natural_maxheight; + } + } + return 1; +} + +static int iNormalizerSetAddControlHandleAttrib(Ihandle* ih, const char* value) +{ + Ihandle* ih_control = (Ihandle*)value; + Ihandle** ih_list = (Ihandle**)iupArrayInc(ih->data->ih_array); + int count = iupArrayCount(ih->data->ih_array); + ih_list[count-1] = ih_control; + return 0; +} + +static int iNormalizerSetAddControlAttrib(Ihandle* ih, const char* value) +{ + return iNormalizerSetAddControlHandleAttrib(ih, (char*)IupGetHandle(value)); +} + +static void iNormalizerComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + (void)w; + (void)h; + (void)expand; + iNormalizerSetNormalizeAttrib(ih, iupAttribGetStr(ih, "NORMALIZE")); +} + +static int iNormalizerCreateMethod(Ihandle* ih, void** params) +{ + ih->data = iupALLOCCTRLDATA(); + ih->data->ih_array = iupArrayCreate(10, sizeof(Ihandle*)); + + if (params) + { + Ihandle** iparams = (Ihandle**)params; + Ihandle** ih_list; + int i = 0; + while (*iparams) + { + ih_list = (Ihandle**)iupArrayInc(ih->data->ih_array); + ih_list[i] = *iparams; + i++; + iparams++; + } + } + + return IUP_NOERROR; +} + +static void iNormalizerDestroy(Ihandle* ih) +{ + iupArrayDestroy(ih->data->ih_array); +} + +Iclass* iupNormalizerGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "normalizer"; + ic->format = "g"; /* array of Ihandle */ + ic->nativetype = IUP_TYPEVOID; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 0; + + /* Class functions */ + ic->Create = iNormalizerCreateMethod; + ic->Map = iupBaseTypeVoidMapMethod; + ic->ComputeNaturalSize = iNormalizerComputeNaturalSizeMethod; + ic->Destroy = iNormalizerDestroy; + + iupClassRegisterAttribute(ic, "NORMALIZE", NULL, iNormalizerSetNormalizeAttrib, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ADDCONTROL_HANDLE", NULL, iNormalizerSetAddControlHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ADDCONTROL", NULL, iNormalizerSetAddControlAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} + +Ihandle *IupNormalizerv(Ihandle **ih_list) +{ + return IupCreatev("normalizer", (void**)ih_list); +} + +Ihandle *IupNormalizer(Ihandle* ih_first, ...) +{ + Ihandle **ih_list; + Ihandle *ih; + + va_list arglist; + va_start(arglist, ih_first); + ih_list = (Ihandle **)iupObjectGetParamList(ih_first, arglist); + va_end(arglist); + + ih = IupCreatev("normalizer", (void**)ih_list); + free(ih_list); + + return ih; +} diff --git a/iup/src/iup_object.c b/iup/src/iup_object.c new file mode 100755 index 0000000..7f4ce23 --- /dev/null +++ b/iup/src/iup_object.c @@ -0,0 +1,180 @@ +/** \file + * \brief Ihandle management + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <memory.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_assert.h" +#include "iup_register.h" +#include "iup_names.h" + + +static Ihandle* iHandleCreate(void) +{ + Ihandle *ih = (Ihandle*)malloc(sizeof(Ihandle)); + memset(ih, 0, sizeof(Ihandle)); + + ih->sig[0] = 'I'; + ih->sig[1] = 'U'; + ih->sig[2] = 'P'; + ih->sig[3] = 0; + + ih->serial = -1; + + ih->attrib = iupTableCreate(IUPTABLE_STRINGINDEXED); + + return ih; +} + +static void iHandleDestroy(Ihandle* ih) +{ + iupTableDestroy(ih->attrib); + memset(ih, 0, sizeof(Ihandle)); + free(ih); +} + +int iupObjectCheck(Ihandle* ih) +{ + char* sig = (char*)ih; + + if (!ih) return 0; + + if (sig[0] != 'I' || + sig[1] != 'U' || + sig[2] != 'P' || + sig[3] != 0) + return 0; + + return 1; +} + +Ihandle* iupObjectCreate(Iclass* iclass, void** params) +{ + /* create the base handle structure */ + Ihandle* ih = iHandleCreate(); + + ih->iclass = iclass; + + /* create the element */ + if (iupClassObjectCreate(ih, params) == IUP_ERROR) + { + iupERROR1("IUP object creation failed (%s).", iclass->name); + iHandleDestroy(ih); + return NULL; + } + + /* ensure attributes default values, at this time only the ones that can be set before map */ + iupClassObjectEnsureDefaultAttributes(ih); + + return ih; +} + +void** iupObjectGetParamList(void* first, va_list arglist) +{ + const int INITIAL_NUMBER = 50; + void **params; + void *param; + int max_count = INITIAL_NUMBER, count = 0; + + params = (void **) malloc (sizeof (void *) * INITIAL_NUMBER); + + param = first; + + while (param != NULL) + { + params[count] = param; + count++; + + /* verifica se precisa realocar memoria */ + if (count >= max_count) + { + void **new_params = NULL; + + max_count += INITIAL_NUMBER; + + new_params = (void **) realloc (params, sizeof (void *) * max_count); + + params = new_params; + } + + param = va_arg (arglist, void*); + } + params[count] = NULL; + + return params; +} + +Ihandle* IupCreatev(const char *name, void **params) +{ + Iclass *ic; + iupASSERT(name!=NULL); + ic = iupRegisterFindClass(name); + if (ic) + return iupObjectCreate(ic, params); + else + return NULL; +} + +Ihandle *IupCreatep(const char *name, void* first, ...) +{ + va_list arglist; + void **params; + Ihandle *ih; + iupASSERT(name!=NULL); + + va_start(arglist, first); + params = iupObjectGetParamList(first, arglist); + va_end(arglist); + + ih = IupCreatev(name, params); + free(params); + + return ih; +} + +Ihandle* IupCreate(const char *name) +{ + iupASSERT(name!=NULL); + return IupCreatev(name, NULL); +} + +void IupDestroy(Ihandle *ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + /* Hide before destroy to avoid children redraw */ + if (ih->iclass->nativetype == IUP_TYPEDIALOG) + IupHide(ih); + + /* Destroy all its children. + Just need to remove the first child, + IupDetach will update firstchild. */ + while (ih->firstchild) + IupDestroy(ih->firstchild); + + /* unmap if mapped and remove from its parent child list */ + IupDetach(ih); + + /* destroy the element */ + iupClassObjectDestroy(ih); + + /* destroy the private data */ + if (ih->data) + free(ih->data); + + /* removes all the names associated with the element */ + iupRemoveAllNames(ih); + + /* destroy the base handle structure */ + iHandleDestroy(ih); +} diff --git a/iup/src/iup_object.h b/iup/src/iup_object.h new file mode 100755 index 0000000..6f6b668 --- /dev/null +++ b/iup/src/iup_object.h @@ -0,0 +1,132 @@ +/** \file + * \brief Ihandle Object Definition + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_OBJECT_H +#define __IUP_OBJECT_H + +#include <stdarg.h> +#include "iup_class.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup object Ihandle Object + * \par + * Object handle for all the elements. + * \par + * See \ref iup_object.h + * \ingroup cpi */ + + +/* SIZE to RASTERSIZE + * \ingroup object */ +#define iupWIDTH2RASTER(_w, _cw) ((int)((_w * _cw)/4.0 + 0.5)) +/* SIZE to RASTERSIZE + * \ingroup object */ +#define iupHEIGHT2RASTER(_h, _ch) ((int)((_h * _ch)/8.0 + 0.5)) + +/* RASTERSIZE to SIZE + * \ingroup object */ +#define iupRASTER2WIDTH(_w, _cw) ((int)((_w * 4.0)/_cw + 0.5)) +/* RASTERSIZE to SIZE + * \ingroup object */ +#define iupRASTER2HEIGHT(_h, _ch) ((int)((_h * 8.0)/_ch + 0.5)) + + +/** Expand configuration + * \ingroup object */ +enum Iexpand { + IUP_EXPAND_NONE = 0x00, + IUP_EXPAND_H0 = 0x01, /* only set by IupFill */ + IUP_EXPAND_H1 = 0x02, + IUP_EXPAND_W0 = 0x04, /* only set by IupFill */ + IUP_EXPAND_W1 = 0x08 +}; + +/** Expand configuration + * \ingroup object */ +#define IUP_EXPAND_WIDTH (IUP_EXPAND_W1 | IUP_EXPAND_W0) +/** Expand configuration + * \ingroup object */ +#define IUP_EXPAND_HEIGHT (IUP_EXPAND_H1 | IUP_EXPAND_H0) +/** Expand configuration + * \ingroup object */ +#define IUP_EXPAND_BOTH (IUP_EXPAND_WIDTH | IUP_EXPAND_HEIGHT) + + +/** A simple definition that do not depends on the native system, + but helps a lot when writing native code. See \ref iup_object.h for definitions. + * \ingroup object */ +#if defined(GTK_MAJOR_VERSION) +typedef struct _GtkWidget InativeHandle; +#elif defined(XmVERSION) +typedef struct _WidgetRec InativeHandle; +#elif defined(WINVER) +typedef struct HWND__ InativeHandle; +#else +typedef struct _InativeHandle InativeHandle; +#endif + +/** Each control may define its own structure in its private module. + * \ingroup object */ +typedef struct _IcontrolData IcontrolData; +/** IcontrolData allocation utility. + * \ingroup object */ +#define iupALLOCCTRLDATA() ((IcontrolData*)calloc(1, sizeof(IcontrolData))) + + +/** Structure used by all the elements. + * \ingroup object */ +struct Ihandle_ +{ + char sig[4]; /**< IUP Signature, initialized with "IUP", cleared on destroy */ + Iclass* iclass; /**< Ihandle Class */ + Itable* attrib; /**< attributes table */ + int serial; /**< serial number used for controls that need a numeric id, initialized with -1 */ + InativeHandle* handle; /**< native handle. initialized when mapped. InativeHandle definition is system dependent. */ + int expand; /**< expand configuration, a combination of \ref Iexpand, for containers is a combination of the children expand's */ + int is_floating; /**< floating attribute */ + int x, y; /**< upper-left corner relative to the native parent. always 0 for the dialog. */ + int userwidth, userheight; /**< user defined size for the control using SIZE or RASTERSIZE */ + int naturalwidth, naturalheight; /**< the calculated size based in the control contents and the user size */ + int currentwidth, currentheight; /**< actual size of the control in pixels (window size, including decorations and margins). */ + int has_maxsize, has_minsize; /**< indicates that the control has the attributes MAXSIZE and/or MINSIZE */ + Ihandle* parent; /**< previous control in the hierarchy tree */ + Ihandle* firstchild; /**< first child control in the hierarchy tree */ + Ihandle* brother; /**< next control inside parent */ + IcontrolData* data; /**< private control data. automatically freed if not NULL in destroy */ +}; + + +/* Creates an object. initializes iclass and nativetype. + * Called only from IupCreate and IupLoad. */ +Ihandle* iupObjectCreate(Iclass* ic, void** params); + + +/** Utility that returns an array of parameters. Must call free for the returned value after usage. + * Used by the creation functions of objects that receives a NULL terminated array of parameters. + * \ingroup object */ +void** iupObjectGetParamList(void* first, va_list arglist); + +/** Checks if the handle is still valid based on the signature. + * \ingroup object */ +int iupObjectCheck(Ihandle* ih); + + +/* Other functions declared in <iup.h> and implemented here. +IupCreate +IupCreatev +IupCreatep +IupDestroy +*/ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_open.c b/iup/src/iup_open.c new file mode 100755 index 0000000..e02561e --- /dev/null +++ b/iup/src/iup_open.c @@ -0,0 +1,119 @@ +/** \file + * \brief Windows Driver Core + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" + +#include "iup_str.h" +#include "iup_globalattrib.h" +#include "iup_names.h" +#include "iup_func.h" +#include "iup_drv.h" +#include "iup_drvinfo.h" +#include "iup_drvfont.h" +#include "iup_predial.h" +#include "iup_class.h" +#include "iup_register.h" +#include "iup_key.h" +#include "iup_image.h" +#include "iup_dlglist.h" +#include "iup_assert.h" +#include "iup_strmessage.h" + + +static int iup_opened = 0; +static int iup_dummy_argc = 0; +static char ** iup_dummy_argv = {0}; + +int iupIsOpened(void) +{ + return iup_opened; +} + +int IupOpen(int *argc, char ***argv) +{ + if (iup_opened) + return IUP_OPENED; + iup_opened = 1; + + if (!argc || !(*argc) || !argv) + { + argc = &iup_dummy_argc; + argv = &iup_dummy_argv; + } + + iupNamesInit(); + iupFuncInit(); + iupStrMessageInit(); + iupGlobalAttribInit(); + iupRegisterInit(); + iupKeyInit(); + iupImageStockInit(); + + IupSetLanguage("ENGLISH"); + IupSetGlobal("VERSION", IupVersion()); + IupSetGlobal("COPYRIGHT", IUP_COPYRIGHT); + + if (iupdrvOpen(argc, argv) == IUP_NOERROR) + { + char* value; + + iupdrvFontInit(); + + IupStoreGlobal("SYSTEM", iupdrvGetSystemName()); + IupStoreGlobal("SYSTEMVERSION", iupdrvGetSystemVersion()); + IupStoreGlobal("COMPUTERNAME", iupdrvGetComputerName()); + IupStoreGlobal("USERNAME", iupdrvGetUserName()); + IupSetGlobal("DEFAULTFONT", iupdrvGetSystemFont()); /* Use SetGlobal because iupdrvGetSystemFont returns a static string */ + + iupRegisterInternalClasses(); + + value = getenv("IUP_QUIET"); + if (value && !iupStrBoolean(value)) /* if not defined do NOT print */ + printf("IUP %s %s\n", IupVersion(), IUP_COPYRIGHT); + + value = getenv("IUP_VERSION"); + if (iupStrBoolean(value)) + iupVersionDlg(); + + return IUP_NOERROR; + } + else + { +#ifdef IUP_ASSERT + /* can not use pre-defined dialogs here, so only output to console. */ + fprintf(stderr, "IUP ERROR: IupOpen failed.\n"); +#endif + return IUP_ERROR; + } +} + +void IupClose(void) +{ + if (!iup_opened) + return; + iup_opened = 0; + + iupdrvSetIdleFunction(NULL); /* stop any idle */ + + iupDlgListDestroyAll(); /* destroy all dialogs */ + iupNamesDestroyHandles(); /* destroy everything else that have names */ + iupImageStockFinish(); /* release stock images hash table and the images */ + + iupRegisterFinish(); /* release native classes */ + + iupdrvFontFinish(); /* release font cache */ + iupdrvClose(); /* release native handles and allocated memory */ + + iupGlobalAttribFinish(); /* release global hash table */ + iupStrMessageFinish(); /* release messages hash table */ + iupFuncFinish(); /* release callbacks hash table */ + iupNamesFinish(); /* release names hash table */ + + iupStrGetMemory(-1); /* Frees internal buffer */ +} diff --git a/iup/src/iup_predial.c b/iup/src/iup_predial.c new file mode 100755 index 0000000..b48e246 --- /dev/null +++ b/iup/src/iup_predial.c @@ -0,0 +1,510 @@ +/** \file + * \brief pre-defined dialogs + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <stdarg.h> +#include <time.h> + +#include "iup.h" + +#include "iup_predial.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_strmessage.h" + + +static int CB_button_OK (Ihandle* ih) +{ + iupAttribSetStr(IupGetDialog(ih), "STATUS", "1"); + return IUP_CLOSE; +} + +static int CB_button_CANCEL (Ihandle* ih) +{ + iupAttribSetStr(IupGetDialog(ih), "STATUS", "-1"); + return IUP_CLOSE; +} + +static int CB_lista (Ihandle *h, char *n, int o, int v) +{ + static clock_t oldtimesel = 0; + static int oldopc = 0; + (void)n; /* not used */ + if (v) + { + clock_t timesel = clock(); + + iupAttribSetStrf(IupGetDialog(h), "_IUP_LIST_NUMBER", "%d", o-1); + + if (((timesel-oldtimesel) < 500) && (o == oldopc)) + return IUP_CLOSE; + + oldtimesel = timesel; + oldopc = o; + } + return IUP_DEFAULT; +} + +int IupListDialog (int type, const char *title, int size, const char** list_str, + int op, int max_col, int max_lin, int* marks) +{ + Ihandle *lst, *ok, *dlg, *cancel, *dlg_box, *button_box; + int i, bt; + char attrib_str[20]; + char *m=NULL; + + if (size > 999) + size = 999; + + lst = IupList(NULL); + + for (i=0;i<size;i++) + { + sprintf(attrib_str,"%d",i+1); + IupSetAttribute(lst,attrib_str,list_str[i]); + } + sprintf(attrib_str,"%d",i+1); + IupSetAttribute(lst,attrib_str,NULL); + IupSetAttribute(lst,"EXPAND","YES"); + + ok = IupButton("OK", NULL); + IupSetAttribute(ok,"PADDING" ,"20x5"); + IupSetCallback(ok, "ACTION", (Icallback)CB_button_OK); + + cancel = IupButton(iupStrMessageGet("IUP_CANCEL"), NULL); + IupSetAttribute(cancel,"PADDING" ,"20x5"); + IupSetCallback(cancel, "ACTION", (Icallback)CB_button_CANCEL); + + button_box = IupHbox( + IupFill(), + ok, + cancel, + NULL); + IupSetAttribute(button_box,"MARGIN","0x0"); + IupSetAttribute(button_box, "NORMALIZESIZE", "HORIZONTAL"); + + dlg_box = IupVbox( + lst, + button_box, + NULL); + + IupSetAttribute(dlg_box,"MARGIN","10x10"); + IupSetAttribute(dlg_box,"GAP","10"); + + dlg = IupDialog(dlg_box); + + if (type == 1) + { + if (op<1 || op>size) op=1; + iupAttribSetStrf(dlg, "_IUP_LIST_NUMBER", "%d", op-1); + IupSetfAttribute(lst,"VALUE","%d",op); + IupSetCallback(lst, "ACTION", (Icallback)CB_lista); + } + else if ((type == 2) && (marks != NULL)) + { + m=(char *)marks; + for (i=0;i<size;i++) + m[i] = marks[i] ? '+' : '-'; + m[i]='\0'; + IupSetAttribute(lst,"MULTIPLE","YES"); + IupSetAttribute(lst,"VALUE",m); + } + + if (max_lin < 4) max_lin = 4; + IupSetfAttribute(lst, "VISIBLELINES", "%d", max_lin); + IupSetfAttribute(lst, "VISIBLECOLUMNS", "%d", max_col); + + IupSetAttribute(dlg,"TITLE", title); + IupSetAttribute(dlg,"MINBOX","NO"); + IupSetAttribute(dlg,"MAXBOX","NO"); + IupSetAttributeHandle(dlg,"DEFAULTENTER", ok); + IupSetAttributeHandle(dlg,"DEFAULTESC", cancel); + IupSetAttribute(dlg,"PARENTDIALOG", IupGetGlobal("PARENTDIALOG")); + IupSetAttribute(dlg,"ICON", IupGetGlobal("ICON")); + + IupPopup(dlg,IUP_CENTERPARENT,IUP_CENTERPARENT); + + if ((type == 2) && (marks != NULL)) + { + m=IupGetAttribute(lst,"VALUE"); + for (i=0;i<size;i++) + marks[i] = (m[i] == '+'); + } + + bt = IupGetInt(dlg, "STATUS"); + if (type == 1) + { + if (bt == 1) + bt = iupAttribGetInt(dlg, "_IUP_LIST_NUMBER"); + else + bt = -1; + } + else + { + if (bt != 1) + bt = -1; + } + + IupDestroy(dlg); + + return bt; +} + +static int iAlarmButtonAction_CB(Ihandle *ih) +{ + iupAttribSetStr(IupGetDialog(ih), "_IUP_BUTTON_NUMBER", iupAttribGet(ih, "_IUP_BUTTON_NUMBER")); + return IUP_CLOSE; +} + +int IupAlarm(const char *title, const char *msg, const char *b1, const char *b2, const char *b3) +{ + Ihandle *dlg, *dlg_box, *button_box, *button, *default_esc, *default_enter; + int bt, len; + char* padding; + + msg = msg? msg: ""; + + if (b1 == NULL) + return 0; + + len = strlen(b1); + if (b2) + { + int len2 = strlen(b2); + if (len2 > len) + len = len2; + } + if (b3) + { + int len3 = strlen(b3); + if (len3 > len) + len = len3; + } + + if (len > 7) + padding = "12x2"; + else + padding = "18x5"; + + button_box = IupHbox(NULL); + IupSetAttribute(button_box, "NORMALIZESIZE", "HORIZONTAL"); + IupSetAttribute(button_box,"MARGIN","0x0"); + IupAppend(button_box, IupFill()); /* to center the buttons */ + + button = IupButton(b1, NULL); + iupAttribSetStrf(button, "_IUP_BUTTON_NUMBER", "1"); + IupSetAttribute(button, "PADDING", padding); + IupAppend(button_box, button); + IupSetCallback (button, "ACTION", (Icallback)iAlarmButtonAction_CB); + default_enter = button; + default_esc = button; + + if (b2 != NULL) + { + button = IupButton(b2, NULL); + iupAttribSetStr(button, "_IUP_BUTTON_NUMBER", "2"); + IupSetAttribute(button, "PADDING", padding); + IupAppend(button_box, button); + IupSetCallback (button, "ACTION", (Icallback)iAlarmButtonAction_CB); + default_esc = button; + } + + if (b3 != NULL) + { + button = IupButton(b3, NULL); + iupAttribSetStr(button, "_IUP_BUTTON_NUMBER", "3"); + IupSetAttribute(button, "PADDING", padding); + IupAppend(button_box, button); + IupSetCallback (button, "ACTION", (Icallback)iAlarmButtonAction_CB); + default_esc = button; + } + + IupAppend(button_box, IupFill()); /* to center the buttons */ + + dlg_box = IupVbox( + IupLabel(msg), + IupSetAttributes(IupLabel(NULL), "SEPARATOR=HORIZONTAL"), + button_box, + NULL); + + IupSetAttribute(dlg_box,"MARGIN","10x10"); + IupSetAttribute(dlg_box,"GAP","10"); + + dlg = IupDialog(dlg_box); + + IupSetAttribute(dlg,"TITLE", title); + IupSetAttribute(dlg,"DIALOGFRAME","YES"); + IupSetAttribute(dlg,"DIALOGHINT","YES"); + IupSetAttributeHandle(dlg,"DEFAULTENTER", default_enter); + IupSetAttributeHandle(dlg,"DEFAULTESC", default_esc); + IupSetAttribute(dlg,"PARENTDIALOG", IupGetGlobal("PARENTDIALOG")); + IupSetAttribute(dlg,"ICON", IupGetGlobal("ICON")); + + IupPopup(dlg,IUP_CENTERPARENT,IUP_CENTERPARENT); + + bt = iupAttribGetInt(dlg, "_IUP_BUTTON_NUMBER"); + + IupDestroy(dlg); + + return bt; +} + +int iupDataEntry(int maxlin, + int* maxcol, + int* maxscr, + char* title, + char** text, + char** data) +{ + int i, bt; + Ihandle *ok, *cancel, *dlg, *vb, *hb, **txt, **lbl, *button_box, *dlg_box; + + txt = (Ihandle **)calloc(maxlin, sizeof(Ihandle*)); + if (txt == NULL) return -2; + lbl = (Ihandle **)calloc(maxlin+1, sizeof(Ihandle*)); + + vb = IupVbox(NULL); + + for (i=0; i<maxlin; i++) + { + txt[i] = IupText(NULL); + IupSetAttribute(txt[i],"VALUE",data[i]); + IupSetfAttribute(txt[i],"VISIBLECOLUMNS","%dx", maxscr[i]); + IupSetfAttribute(txt[i],"NC", "%d", maxcol[i]); + IupSetAttribute(txt[i],"EXPAND","HORIZONTAL"); + + hb = IupHbox(lbl[i] = IupLabel(text[i]), txt[i], NULL); + IupSetAttribute(hb,"MARGIN","0x0"); + IupSetAttribute(hb,"ALIGNMENT","ACENTER"); + IupAppend(vb, hb); + } + lbl[i] = NULL; + IupInsert(vb, NULL, IupNormalizerv(lbl)); + + ok = IupButton("OK", NULL); + IupSetAttribute(ok, "PADDING", "20x0"); + IupSetCallback(ok, "ACTION", (Icallback)CB_button_OK); + + cancel = IupButton(iupStrMessageGet("IUP_CANCEL"), NULL); + IupSetAttribute(cancel, "PADDING", "20x0"); + IupSetCallback(cancel, "ACTION", (Icallback)CB_button_CANCEL); + + button_box = IupHbox( + IupFill(), + ok, + cancel, + NULL); + IupSetAttribute(button_box,"MARGIN","0x0"); + IupSetAttribute(button_box, "NORMALIZESIZE", "HORIZONTAL"); + + dlg_box = IupVbox( + IupFrame(vb), + button_box, + NULL); + IupSetAttribute(dlg_box,"MARGIN","10x10"); + IupSetAttribute(dlg_box,"GAP","5"); + + dlg = IupDialog(dlg_box); + + IupSetAttribute(dlg,"TITLE",title); + IupSetAttribute(dlg,"MINBOX","NO"); + IupSetAttribute(dlg,"MAXBOX","NO"); + IupSetAttributeHandle(dlg,"DEFAULTENTER", ok); + IupSetAttributeHandle(dlg,"DEFAULTESC", cancel); + IupSetAttribute(dlg,"PARENTDIALOG",IupGetGlobal("PARENTDIALOG")); + IupSetAttribute(dlg,"ICON", IupGetGlobal("ICON")); + + IupMap(dlg); + + IupSetfAttribute(dlg,"MAXSIZE", "65535x%d", IupGetInt2(dlg, "RASTERSIZE")); + IupSetAttribute(dlg,"MINSIZE", IupGetAttribute(dlg, "RASTERSIZE")); + + IupPopup(dlg,IUP_CENTERPARENT,IUP_CENTERPARENT); + + for (i=0; i<maxlin; i++) + { + data[i] = (char *)iupStrDup(IupGetAttribute(txt[i], "VALUE")); + } + + free(txt); + + bt = IupGetInt(dlg, "STATUS"); + IupDestroy(dlg); + return bt; +} + +static void iupStrSplitFileName(const char* filename, char *dir, char *filter) +{ + int i, n = strlen(filename); + + /* Look for last folder separator and split filter from directory */ + for (i=n-1;i>=0; i--) + { + if (filename[i] == '\\' || filename[i] == '/') + { + if (dir) + { + strncpy(dir, filename, i+1); + dir[i+1] = 0; + } + + if (filter) + { + strcpy(filter, filename+i+1); + filter[n-i] = 0; + } + + return; + } + } +} + +int IupGetFile(char* filename) +{ + Ihandle *dlg = 0; + int ret; + char filter[4096] = "*.*"; + static char dir[4096] = ""; /* static will make the dir persist from one call to another if not defined */ + + if (!filename) return -1; + + dlg = IupFileDlg(); + + iupStrSplitFileName(filename, dir, filter); + + IupSetAttribute(dlg, "FILTER", filter); + IupSetAttribute(dlg, "DIRECTORY", dir); + IupSetAttribute(dlg, "ALLOWNEW", "YES"); + IupSetAttribute(dlg, "NOCHANGEDIR", "YES"); + IupSetAttribute(dlg, "PARENTDIALOG", IupGetGlobal("PARENTDIALOG")); + IupSetAttribute(dlg, "ICON", IupGetGlobal("ICON")); + + IupPopup(dlg, IUP_CENTERPARENT, IUP_CENTERPARENT); + + ret = IupGetInt(dlg, "STATUS"); + if (ret != -1) + { + char* value = IupGetAttribute(dlg, "VALUE"); + if (value) + { + strcpy(filename, value); + iupStrSplitFileName(filename, dir, NULL); + } + } + + IupDestroy(dlg); + + return ret; +} + +int IupGetText(const char* title, char* text) +{ + Ihandle *ok, *cancel, *multi_text, *button_box, *dlg_box, *dlg; + int bt; + + multi_text = IupMultiLine(NULL); + IupSetAttribute(multi_text,"EXPAND", "YES"); + IupSetAttribute(multi_text,"VALUE", text); + IupSetAttribute(multi_text,"FONT", "Courier, 12"); + IupSetAttribute(multi_text, "VISIBLELINES", "10"); + IupSetAttribute(multi_text, "VISIBLECOLUMNS", "50"); + + ok = IupButton("OK", NULL); + IupSetAttribute(ok, "PADDING", "20x5"); + IupSetCallback(ok, "ACTION", (Icallback)CB_button_OK); + + cancel = IupButton(iupStrMessageGet("IUP_CANCEL"), NULL); + IupSetAttribute(cancel, "PADDING", "20x5"); + IupSetCallback(cancel, "ACTION", (Icallback)CB_button_CANCEL); + + button_box = IupHbox( + IupFill(), + ok, + cancel, + NULL); + IupSetAttribute(button_box,"MARGIN","0x0"); + IupSetAttribute(button_box, "NORMALIZESIZE", "HORIZONTAL"); + + dlg_box = IupVbox( + multi_text, + button_box, + NULL); + + IupSetAttribute(dlg_box,"MARGIN","10x10"); + IupSetAttribute(dlg_box,"GAP","10"); + + dlg = IupDialog (dlg_box); + + IupSetAttribute(dlg,"TITLE", title); + IupSetAttribute(dlg,"MINBOX","NO"); + IupSetAttribute(dlg,"MAXBOX","NO"); + IupSetAttributeHandle(dlg,"DEFAULTENTER", ok); + IupSetAttributeHandle(dlg,"DEFAULTESC", cancel); + IupSetAttribute(dlg,"PARENTDIALOG", IupGetGlobal("PARENTDIALOG")); + IupSetAttribute(dlg,"ICON", IupGetGlobal("ICON")); + + IupMap(dlg); + + IupSetAttribute(multi_text, "VISIBLELINES", NULL); + IupSetAttribute(multi_text, "VISIBLECOLUMNS", NULL); + + IupPopup(dlg, IUP_CENTERPARENT, IUP_CENTERPARENT); + + bt = IupGetInt(dlg, "STATUS"); + if (bt==1) + strcpy(text, IupGetAttribute(multi_text, "VALUE")); + else + bt = 0; /* return 0 instead of -1 */ + + IupDestroy(dlg); + return bt; +} + +int IupGetColor(int x, int y, unsigned char *r, unsigned char *g, unsigned char *b) +{ + int ret; + Ihandle* dlg = IupColorDlg(); + + IupSetAttribute(dlg, "TITLE", iupStrMessageGet("IUP_GETCOLOR")); + IupSetfAttribute(dlg, "VALUE", "%d %d %d", *r, *g, *b); + IupSetAttribute(dlg, "PARENTDIALOG", IupGetGlobal("PARENTDIALOG")); + IupSetAttribute(dlg, "ICON", IupGetGlobal("ICON")); + + IupPopup(dlg, x, y); + + ret = IupGetInt(dlg, "STATUS"); + if (ret) + iupStrToRGB(IupGetAttribute(dlg, "VALUE"), r, g, b); + + IupDestroy(dlg); + + return ret; +} + +void iupVersionDlg(void) +{ + Ihandle* dlg; + + dlg = IupDialog(IupVbox(IupFrame(IupVbox( + IupLabel(IupVersion()), + IupLabel(IUP_VERSION_DATE), + IupLabel(IUP_COPYRIGHT), + NULL)), + IupButton("OK", NULL), + NULL)); + + IupSetAttribute(dlg,"TITLE","IUP Version"); + IupSetAttribute(dlg,"DIALOGFRAME","YES"); + IupSetAttribute(dlg,"DIALOGHINT","YES"); + IupSetAttribute(dlg,"GAP","10"); + IupSetAttribute(dlg,"MARGIN","10x10"); + + IupPopup(dlg, IUP_CENTERPARENT, IUP_CENTERPARENT); + IupDestroy(dlg); +} diff --git a/iup/src/iup_predial.h b/iup/src/iup_predial.h new file mode 100755 index 0000000..e282e53 --- /dev/null +++ b/iup/src/iup_predial.h @@ -0,0 +1,32 @@ +/** \file + * \brief IUP Core pre-defined dialogs. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_PREDIAL_H +#define __IUP_PREDIAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Used by the IupScanf implementation */ +int iupDataEntry(int maxlin, int* maxcol, int* maxscr, char* title, char** text, char** data); + +/* Popups a dialog with IUP Version, used in IupOpen */ +void iupVersionDlg(void); + +/* Other functions declared in <iup.h> and implemented here. +IupListDialog +IupAlarm +IupMessagef +IupGetFile +IupGetText +*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_progressbar.c b/iup/src/iup_progressbar.c new file mode 100755 index 0000000..76fdefc --- /dev/null +++ b/iup/src/iup_progressbar.c @@ -0,0 +1,118 @@ +/** \file + * \brief ProgressBar control + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" +#include "iup_progressbar.h" + + +void iProgressBarCropValue(Ihandle* ih) +{ + if(ih->data->value > ih->data->vmax) + ih->data->value = ih->data->vmax; + else if(ih->data->value < ih->data->vmin) + ih->data->value = ih->data->vmin; +} + +char* iProgressBarGetValueAttrib(Ihandle* ih) +{ + char* value = iupStrGetMemory(30); + sprintf(value, "%g", ih->data->value); + return value; +} + +char* iProgressBarGetDashedAttrib(Ihandle* ih) +{ + if(ih->data->dashed) + return "YES"; + else + return "NO"; +} + +static int iProgressBarSetMinAttrib(Ihandle* ih, const char* value) +{ + ih->data->vmin = atof(value); + iProgressBarCropValue(ih); + return 1; +} + +static int iProgressBarSetMaxAttrib(Ihandle* ih, const char* value) +{ + ih->data->vmax = atof(value); + iProgressBarCropValue(ih); + return 1; +} + +static int iProgressBarCreateMethod(Ihandle* ih, void **params) +{ + (void)params; + + ih->data = iupALLOCCTRLDATA(); + + /* default values */ + ih->data->vmax = 1; + ih->data->dashed = 0; + + /* progress bar natural size is 200x30 */ + IupSetAttribute(ih, "RASTERSIZE", "200x30"); + + return IUP_NOERROR; +} + +Iclass* iupProgressBarGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "progressbar"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPECONTROL; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 0; + + /* Class functions */ + ic->Create = iProgressBarCreateMethod; + + ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Common Callbacks */ + iupClassRegisterCallback(ic, "MAP_CB", ""); + iupClassRegisterCallback(ic, "UNMAP_CB", ""); + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Visual */ + iupBaseRegisterVisualAttrib(ic); + + /* IupProgressBar only */ + iupClassRegisterAttribute(ic, "MIN", NULL, iProgressBarSetMinAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MAX", NULL, iProgressBarSetMaxAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "ORIENTATION", NULL, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NOT_MAPPED); + + iupdrvProgressBarInitClass(ic); + + return ic; +} + +Ihandle *IupProgressBar(void) +{ + return IupCreate("progressbar"); +} diff --git a/iup/src/iup_progressbar.h b/iup/src/iup_progressbar.h new file mode 100755 index 0000000..44ffb7f --- /dev/null +++ b/iup/src/iup_progressbar.h @@ -0,0 +1,35 @@ +/** \file + * \brief ProgressBar Control + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_PROGRESSBAR_H +#define __IUP_PROGRESSBAR_H + +#ifdef __cplusplus +extern "C" { +#endif + + +struct _IcontrolData +{ + int dashed, + marquee; + + double value, /* value is min < value < max */ + vmin, + vmax; +}; + +void iProgressBarCropValue(Ihandle* ih); +char* iProgressBarGetValueAttrib(Ihandle* ih); +char* iProgressBarGetDashedAttrib(Ihandle* ih); + +void iupdrvProgressBarInitClass(Iclass* ic); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_radio.c b/iup/src/iup_radio.c new file mode 100755 index 0000000..c6e7cdd --- /dev/null +++ b/iup/src/iup_radio.c @@ -0,0 +1,195 @@ +/** \file + * \brief Radio Control. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" + + +Ihandle *iupRadioFindToggleParent(Ihandle* ih_toggle) +{ + Ihandle *p; + for (p=ih_toggle; p->parent; p=p->parent) + { + if (p->iclass->nativetype == IUP_TYPEVOID && + iupStrEqual(p->iclass->name, "radio")) + return p; + } + + return NULL; +} + +static int iRadioFindToggleChild(Ihandle* ih, Ihandle* ih_toggle) +{ + Ihandle* child; + + if (ih == ih_toggle) /* found child that match the toggle */ + return 1; + + for (child = ih->firstchild; child; child = child->brother) + { + if (iRadioFindToggleChild(child, ih_toggle)) + return 1; + } + + return 0; +} + +static Ihandle* iRadioGetToggleChildOn(Ihandle* ih) +{ + Ihandle* child; + + if (iupStrEqual(ih->iclass->name, "toggle") && /* found child that is a toggle and it is ON */ + IupGetInt(ih, "VALUE")) + return ih; + + for (child = ih->firstchild; child; child = child->brother) + { + Ihandle* ih_toggle = iRadioGetToggleChildOn(child); + if (ih_toggle) + return ih_toggle; + } + + return NULL; +} + +/******************************************************************************/ + + +static int iRadioSetValueHandleAttrib(Ihandle* ih, const char* value) +{ + Ihandle* ih_toggle = (Ihandle*)value; + if (!iupObjectCheck(ih_toggle)) + return 0; + + if (!iupStrEqual(ih_toggle->iclass->name, "toggle")) + return 0; + + if (iRadioFindToggleChild(ih->firstchild, ih_toggle)) + IupSetAttribute(ih_toggle, "VALUE", "ON"); + + return 0; +} + +char* iRadioGetValueHandleAttrib(Ihandle* ih) +{ + return (char*)iRadioGetToggleChildOn(ih->firstchild); +} + +static int iRadioSetValueAttrib(Ihandle* ih, const char* value) +{ + Ihandle *ih_toggle; + + if (!value) + return 0; + + ih_toggle = IupGetHandle(value); + if (!ih_toggle) + return 0; + + iRadioSetValueHandleAttrib(ih, (char*)ih_toggle); + return 0; +} + +char* iRadioGetValueAttrib(Ihandle* ih) +{ + Ihandle *ih_toggle = (Ihandle*)iRadioGetValueHandleAttrib(ih); + if (!ih_toggle) + return NULL; + + return IupGetName(ih_toggle); +} + +/******************************************************************************/ + + +static int iRadioCreateMethod(Ihandle* ih, void** params) +{ + if (params) + { + Ihandle** iparams = (Ihandle**)params; + if (*iparams) + IupAppend(ih, *iparams); + } + return IUP_NOERROR; +} + +static void iRadioComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + Ihandle* child = ih->firstchild; + if (child) + { + /* update child natural size first */ + iupBaseComputeNaturalSize(child); + + *expand = child->expand; + *w = child->naturalwidth; + *h = child->naturalheight; + } +} + +static void iRadioSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink) +{ + iupBaseSetCurrentSize(ih->firstchild, ih->currentwidth, ih->currentheight, shrink); +} + +static void iRadioSetChildrenPositionMethod(Ihandle* ih, int x, int y) +{ + iupBaseSetPosition(ih->firstchild, x, y); +} + + +/******************************************************************************/ + + +Ihandle* IupRadio(Ihandle* child) +{ + void *params[2]; + params[0] = (void*)child; + params[1] = NULL; + return IupCreatev("radio", params); +} + +Iclass* iupRadioGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "radio"; + ic->format = "H"; /* one optional ihandle */ + ic->nativetype = IUP_TYPEVOID; + ic->childtype = IUP_CHILD_ONE; + ic->is_interactive = 0; + + /* Class functions */ + ic->Create = iRadioCreateMethod; + ic->Map = iupBaseTypeVoidMapMethod; + ic->ComputeNaturalSize = iRadioComputeNaturalSizeMethod; + ic->SetChildrenCurrentSize = iRadioSetChildrenCurrentSizeMethod; + ic->SetChildrenPosition = iRadioSetChildrenPositionMethod; + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Base Container */ + iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CLIENTSIZE", iupBaseGetRasterSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* Radio only */ + iupClassRegisterAttribute(ic, "VALUE", iRadioGetValueAttrib, iRadioSetValueAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE_HANDLE", iRadioGetValueHandleAttrib, iRadioSetValueHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + + return ic; +} diff --git a/iup/src/iup_register.c b/iup/src/iup_register.c new file mode 100755 index 0000000..4c58038 --- /dev/null +++ b/iup/src/iup_register.c @@ -0,0 +1,123 @@ +/** \file +* \brief Register the Internal Controls +* +* See Copyright Notice in "iup.h" +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_register.h" +#include "iup_stdcontrols.h" + + +static Itable *iregister_table = NULL; /* table indexed by name containing Iclass* address */ + +void iupRegisterInit(void) +{ + iregister_table = iupTableCreate(IUPTABLE_STRINGINDEXED); +} + +void iupRegisterFinish(void) +{ + char* name = iupTableFirst(iregister_table); + while (name) + { + Iclass* ic = (Iclass*)iupTableGetCurr(iregister_table); + iupClassRelease(ic); + name = iupTableNext(iregister_table); + } + + iupTableDestroy(iregister_table); + iregister_table = NULL; +} + +int iupRegisterGetClasses(char *list[], int n) +{ + int i = 0; + char* name = iupTableFirst(iregister_table); + + if (!list || !n) + return iupTableCount(iregister_table); + + while (name) + { + list[i] = name; + i++; + if (i == n) + break; + + name = iupTableNext(iregister_table); + } + + return i; +} + +Iclass* iupRegisterFindClass(const char* name) +{ + return (Iclass*)iupTableGet(iregister_table, name); +} + +void iupRegisterClass(Iclass* ic) +{ + Iclass* old_ic = (Iclass*)iupTableGet(iregister_table, ic->name); + if (old_ic) + iupClassRelease(old_ic); + + iupTableSet(iregister_table, ic->name, (void*)ic, IUPTABLE_POINTER); +} + + +/***************************************************************/ + +void iupRegisterInternalClasses(void) +{ + iupRegisterClass(iupDialogGetClass()); + iupRegisterClass(iupMessageDlgGetClass()); + iupRegisterClass(iupColorDlgGetClass()); + iupRegisterClass(iupFontDlgGetClass()); + iupRegisterClass(iupFileDlgGetClass()); + + iupRegisterClass(iupTimerGetClass()); + iupRegisterClass(iupImageGetClass()); + iupRegisterClass(iupImageRGBGetClass()); + iupRegisterClass(iupImageRGBAGetClass()); + iupRegisterClass(iupUserGetClass()); + iupRegisterClass(iupClipboardGetClass()); + + iupRegisterClass(iupRadioGetClass()); + iupRegisterClass(iupFillGetClass()); + iupRegisterClass(iupHboxGetClass()); + iupRegisterClass(iupVboxGetClass()); + iupRegisterClass(iupZboxGetClass()); + iupRegisterClass(iupCboxGetClass()); + iupRegisterClass(iupSboxGetClass()); + iupRegisterClass(iupNormalizerGetClass()); + + iupRegisterClass(iupMenuGetClass()); + iupRegisterClass(iupItemGetClass()); + iupRegisterClass(iupSeparatorGetClass()); + iupRegisterClass(iupSubmenuGetClass()); + + iupRegisterClass(iupLabelGetClass()); + iupRegisterClass(iupButtonGetClass()); + iupRegisterClass(iupToggleGetClass()); + iupRegisterClass(iupCanvasGetClass()); + iupRegisterClass(iupFrameGetClass()); + iupRegisterClass(iupTextGetClass()); + iupRegisterClass(iupMultilineGetClass()); + iupRegisterClass(iupListGetClass()); + + iupRegisterClass(iupProgressBarGetClass()); + iupRegisterClass(iupValGetClass()); + iupRegisterClass(iupTabsGetClass()); + iupRegisterClass(iupSpinGetClass()); + iupRegisterClass(iupSpinboxGetClass()); + iupRegisterClass(iupTreeGetClass()); +} diff --git a/iup/src/iup_register.h b/iup/src/iup_register.h new file mode 100755 index 0000000..b5e6907 --- /dev/null +++ b/iup/src/iup_register.h @@ -0,0 +1,47 @@ +/** \file + * \brief Register the Controls + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_REGISTER_H +#define __IUP_REGISTER_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup register Class Registration + * \par + * All controls are registered so the creation using IupCreate can work. + * \par + * See \ref iup_register.h + * \ingroup cpi */ + + +/** Returns a class instance from a class name. The class name must be previously registered using \ref iupRegisterClass. + * \ingroup register */ +Iclass* iupRegisterFindClass(const char* name); + +/** Register a class. + * \ingroup register */ +void iupRegisterClass(Iclass* ic); + + +/* Register the internal classes. Called only from IupOpen. */ +void iupRegisterInternalClasses(void); + +/* Initializes the class registry. Called only from IupOpen. */ +void iupRegisterInit(void); +void iupRegisterFinish(void); + +/* Get the registered classes. Used in documentation tests. */ +int iupRegisterGetClasses(char *list[], int n); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_sbox.c b/iup/src/iup_sbox.c new file mode 100755 index 0000000..5a71d33 --- /dev/null +++ b/iup/src/iup_sbox.c @@ -0,0 +1,413 @@ +/** \file + * \brief iupsbox control + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "iup.h" +#include "iupcbs.h" +#include "iupkey.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" +#include "iup_childtree.h" + + +#define ISBOX_THICK 5 + +enum { ISBOX_NORTH, ISBOX_SOUTH, ISBOX_WEST, ISBOX_EAST }; + +struct _IcontrolData +{ + int w, h; + int isholding; + int start_x, start_y; + int start_w, start_h; + + int direction; /* one of the types: ISBOX_NORTH, ISBOX_SOUTH, ISBOX_WEST, ISBOX_EAST */ +}; + + +static int iSboxGetYborder(Ihandle* ih) +{ + if (ih->data->direction == ISBOX_NORTH || ih->data->direction == ISBOX_SOUTH) + return ISBOX_THICK; + else + return 0; +} + +static int iSboxGetXborder(Ihandle* ih) +{ + if (ih->data->direction == ISBOX_EAST || ih->data->direction == ISBOX_WEST) + return ISBOX_THICK; + else + return 0; +} + +static void iSboxSaveDimension(Ihandle* ih, int w, int h) +{ + ih->data->w = w; + ih->data->h = h; +} + +static void iSboxAddDecorOffset(Ihandle* ih, int *x, int *y) +{ + /* skip north thumb if there is one */ + if (ih->data->direction == ISBOX_NORTH) + *y += ISBOX_THICK; + + /* skip west thumb if there is one */ + if (ih->data->direction == ISBOX_WEST) + *x += ISBOX_THICK; +} + +static void iSboxGetFinalSize(Ihandle* ih, int direction, int *w, int *h) +{ + int final_x, final_y; + int diff_x, diff_y; + + iupStrToIntInt(IupGetGlobal("CURSORPOS"), &final_x, &final_y, 'x'); + + diff_x = final_x - ih->data->start_x; + diff_y = final_y - ih->data->start_y; + + if(direction == ISBOX_WEST) + diff_x = -diff_x; + + if(direction == ISBOX_NORTH) + diff_y = -diff_y; + + *w = diff_x + ih->data->start_w; + *h = diff_y + ih->data->start_h; +} + +static void iSboxShakeControls(Ihandle* ih) +{ + int new_w, new_h; + + iSboxGetFinalSize(ih, ih->data->direction, &new_w, &new_h); + + if (ih->data->direction == ISBOX_WEST || ih->data->direction == ISBOX_EAST) + { + if (new_w != ih->data->w) + { + if (new_w > ih->naturalwidth) + iSboxSaveDimension(ih, new_w, ih->data->h); + else + iSboxSaveDimension(ih, new_w, ih->naturalwidth); + } + } + else if (ih->data->direction == ISBOX_SOUTH || ih->data->direction == ISBOX_NORTH) + { + if(new_h != ih->data->h) + { + if (new_h > ih->naturalheight) + iSboxSaveDimension(ih, ih->data->w, new_h); + else + iSboxSaveDimension(ih, ih->naturalheight, new_h); + } + } + + IupRefresh(ih); /* may affect all the elements in the dialog */ +} + + +/*****************************************************************************\ +|* Callbacks of canvas bar *| +\*****************************************************************************/ + + +static int iSboxMotion_CB(Ihandle* bar, int x, int y, char *r) +{ + Ihandle* ih = bar->parent; + + if (ih->data->isholding) + iSboxShakeControls(ih); + + (void)x; + (void)y; + (void)r; + return IUP_DEFAULT; +} + +static int iSboxButton_CB(Ihandle* bar, int button, int pressed, int x, int y, char* status) +{ + Ihandle* ih = bar->parent; + + if (button!=IUP_BUTTON1) + return IUP_DEFAULT; + + if (!ih->data->isholding && pressed) + { + ih->data->isholding = 1; + + /* Save the cursor position */ + iupStrToIntInt(IupGetGlobal("CURSORPOS"), &ih->data->start_x, &ih->data->start_y, 'x'); + + /* Save the initial size */ + ih->data->start_w = ih->data->w; + ih->data->start_h = ih->data->h; + } + else if (ih->data->isholding && !pressed) + ih->data->isholding = 0; + + (void)x; + (void)y; + (void)status; + return IUP_DEFAULT; +} + +static int iSboxFocus_CB(Ihandle* bar, int focus) +{ + Ihandle* ih = bar->parent; + + if (!ih || focus) /* use only kill focus */ + return IUP_DEFAULT; + + if (ih->data->isholding) + ih->data->isholding = 0; + + return IUP_DEFAULT; +} + + +/*****************************************************************************\ +|* Attributes *| +\*****************************************************************************/ + + +static char* iSboxGetClientSizeAttrib(Ihandle* ih) +{ + int width, height; + char* str = iupStrGetMemory(20); + width = ih->currentwidth; + height = ih->currentheight; + width -= iSboxGetXborder(ih); + height -= iSboxGetYborder(ih); + if (width < 0) width = 0; + if (height < 0) height = 0; + sprintf(str, "%dx%d", width, height); + return str; +} + +static int iSboxSetColorAttrib(Ihandle* ih, const char* value) +{ + IupSetAttribute(ih->firstchild, "BGCOLOR", value); + return 0; /* do not store value in hash table */ +} + +static int iSboxSetDirectionAttrib(Ihandle* ih, const char* value) +{ + if (ih->handle) /* only before map */ + return 0; + + if (iupStrEqual(value, "NORTH")) + ih->data->direction = ISBOX_NORTH; + else if(iupStrEqual(value, "SOUTH")) + ih->data->direction = ISBOX_SOUTH; + else if(iupStrEqual(value, "WEST")) + ih->data->direction = ISBOX_WEST; + else /* Default = EAST */ + ih->data->direction = ISBOX_EAST; + + if (ih->data->direction == ISBOX_EAST || ih->data->direction == ISBOX_WEST) + IupSetAttribute(ih->firstchild, "CURSOR", "RESIZE_WE"); + else + IupSetAttribute(ih->firstchild, "CURSOR", "RESIZE_NS"); + + return 0; /* do not store value in hash table */ +} + + +/*****************************************************************************\ +|* Methods *| +\*****************************************************************************/ + + +static void iSboxComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + int natural_w = ih->naturalwidth, + natural_h = ih->naturalheight; + + /* only allow expand in the oposite direction, complement iupBaseContainerUpdateExpand */ + if (ih->data->direction == ISBOX_EAST || ih->data->direction == ISBOX_WEST) + ih->expand &= ~IUP_EXPAND_WIDTH; + else + ih->expand &= ~IUP_EXPAND_HEIGHT; + + /* always has at least one child, the bar */ + + /* This is an unusual element, the iupBaseComputeNaturalSize logic is done twice, one here and one back there. */ + + if (ih->firstchild->brother) + { + Ihandle* child = ih->firstchild->brother; + + /* update child natural size first */ + iupBaseComputeNaturalSize(child); + + *expand = child->expand; + + /* calculate as in iupBaseComputeNaturalSize */ + natural_w = iupMAX(natural_w, child->naturalwidth + iSboxGetXborder(ih)); + natural_h = iupMAX(natural_h, child->naturalheight + iSboxGetYborder(ih)); + } + + /* update control to fit its children according to direction */ + + /* bar */ + if (ih->data->direction == ISBOX_EAST || ih->data->direction == ISBOX_WEST) + { + ih->data->w = iupMAX(natural_w, ih->data->w); + ih->data->h = natural_h; + } + else /* ISBOX_NORTH || ISBOX_SOUTH */ + { + ih->data->w = natural_w; + ih->data->h = iupMAX(natural_h, ih->data->h); + } + + /* child */ + if (ih->firstchild->brother) + { + Ihandle* child = ih->firstchild->brother; + child->naturalwidth = ih->data->w - iSboxGetXborder(ih); + child->naturalheight = ih->data->h - iSboxGetYborder(ih); + } + + *w = ih->data->w; + *h = ih->data->h; +} + +static void iSboxSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink) +{ + /* bar */ + if ((ih->data->direction == ISBOX_NORTH || ih->data->direction == ISBOX_SOUTH)) + { + ih->firstchild->currentwidth = ih->currentwidth; + ih->firstchild->currentheight = ISBOX_THICK; + } + else + { + ih->firstchild->currentwidth = ISBOX_THICK; + ih->firstchild->currentheight = ih->currentheight; + } + + /* child */ + if (ih->firstchild->brother) + { + int width = ih->currentwidth-iSboxGetXborder(ih); + int height = ih->currentheight-iSboxGetYborder(ih); + if (width < 0) width = 0; + if (height < 0) height = 0; + + iupBaseSetCurrentSize(ih->firstchild->brother, width, height, shrink); + } +} + +static void iSboxSetChildrenPositionMethod(Ihandle* ih, int x, int y) +{ + int posx = 0, posy = 0; + + /* bar */ + if (ih->data->direction == ISBOX_EAST) + { + posx = ih->data->w - ISBOX_THICK; + if (posx<0) posx = 0; + } + if (ih->data->direction == ISBOX_SOUTH) + { + posy = ih->data->h - ISBOX_THICK; + if (posy<0) posy = 0; + } + + iupBaseSetPosition(ih->firstchild, x+posx, y+posy); + + /* child */ + if (ih->firstchild->brother) + { + iSboxAddDecorOffset(ih, &x, &y); + iupBaseSetPosition(ih->firstchild->brother, x, y); + } +} + +static int iSboxCreateMethod(Ihandle* ih, void** params) +{ + Ihandle* bar; + + ih->data = iupALLOCCTRLDATA(); + + ih->data->direction = ISBOX_EAST; + ih->data->h = -1; + ih->data->w = -1; + + bar = IupCanvas(NULL); + iupChildTreeAppend(ih, bar); /* bar will always be the firstchild */ + + IupSetAttribute(bar, "BORDER", "YES"); + IupSetAttribute(bar, "EXPAND", "NO"); + IupSetAttribute(bar, "BGCOLOR", "192 192 192"); + + /* Setting callbacks */ + IupSetCallback(bar, "BUTTON_CB", (Icallback) iSboxButton_CB); + IupSetCallback(bar, "FOCUS_CB", (Icallback) iSboxFocus_CB); + IupSetCallback(bar, "MOTION_CB", (Icallback) iSboxMotion_CB); + + if (params) + { + Ihandle** iparams = (Ihandle**)params; + if (*iparams) + IupAppend(ih, *iparams); + } + + return IUP_NOERROR; +} + +Iclass* iupSboxGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "sbox"; + ic->format = "H"; /* one optional ihandle */ + ic->nativetype = IUP_TYPEVOID; + ic->childtype = IUP_CHILDMANY; /* should be IUP_CHILDONE but has the bar (a IupCanvas) as firstchild */ + ic->is_interactive = 0; + + /* Class functions */ + ic->Create = iSboxCreateMethod; + ic->Map = iupBaseTypeVoidMapMethod; + + ic->ComputeNaturalSize = iSboxComputeNaturalSizeMethod; + ic->SetChildrenCurrentSize = iSboxSetChildrenCurrentSizeMethod; + ic->SetChildrenPosition = iSboxSetChildrenPositionMethod; + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Base Container */ + iupClassRegisterAttribute(ic, "CLIENTSIZE", iSboxGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* IupSbox only */ + iupClassRegisterAttribute(ic, "COLOR", NULL, iSboxSetColorAttrib, IUPAF_SAMEASSYSTEM, "192 192 192", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DIRECTION", NULL, iSboxSetDirectionAttrib, IUPAF_SAMEASSYSTEM, "EAST", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} + +Ihandle* IupSbox(Ihandle* child) +{ + void *params[2]; + params[0] = (void*)child; + params[1] = NULL; + return IupCreatev("sbox", params); +} diff --git a/iup/src/iup_scanf.c b/iup/src/iup_scanf.c new file mode 100755 index 0000000..f8ef97b --- /dev/null +++ b/iup/src/iup_scanf.c @@ -0,0 +1,200 @@ +/** \file + * \brief IupScanf implementation. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include "iup.h" + +#include "iup_predial.h" +#include "iup_str.h" +#include "iup_assert.h" + + +#define ALLOC(n,t) ((t *)calloc((n),sizeof(t))) +#define REQUIRE(b) {if (!(b)) goto cleanup;} + +int IupScanf (const char *format, ...) +{ + int i; + int fields_out_count=(-1); /* return code if not error (error < 0) */ + int error=(-1); /* return code if error (error >= 0) */ + int fields_in_count; + int *width=NULL; + int *scroll=NULL; + char **prompt=NULL; + char **text=NULL; + char *title=NULL; + char *s=NULL; + char *s1=NULL; + char *outf=NULL; + va_list va; + + iupASSERT(format!=NULL); + if (!format) + return 0; + + fields_in_count=iupStrCountChar(format,'\n')-1; + REQUIRE(fields_in_count>0); + width=ALLOC(fields_in_count, int); + REQUIRE(width!=NULL); + scroll=ALLOC(fields_in_count, int); + REQUIRE(scroll!=NULL); + prompt=ALLOC(fields_in_count, char *); + REQUIRE(prompt!=NULL); + text=ALLOC(fields_in_count, char *); + REQUIRE(text!=NULL); + + va_start(va,format); + REQUIRE ((s1=s=(char *)iupStrDup(format)) != NULL); + title=iupStrCopyUntil(&s,'\n'); + REQUIRE(title!=NULL); + for (i=0; i<fields_in_count; ++i) + { + int n; + prompt[i]=iupStrCopyUntil(&s,'%'); + REQUIRE(prompt[i]!=NULL); + n=sscanf(s,"%d.%d",width+i,scroll+i); + REQUIRE(n==2); + s=strchr(s,'%'); + REQUIRE(s!=NULL); + if (outf) free(outf); + outf = iupStrCopyUntil(&s, '\n'); + text[i]=ALLOC(width[i]+1,char); + REQUIRE(text[i]!=NULL); + + switch (s[-2]) + { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + if (s[-3]=='l') + sprintf(text[i],outf,*((long *)va_arg(va,long *))); + else if (s[-3]=='h') + sprintf(text[i],outf,*((short *)va_arg(va,short *))); + else + sprintf(text[i],outf,*((int *)va_arg(va,int *))); + break; + case 'e': + case 'f': + case 'g': + case 'E': + case 'G': + if (s[-3]=='l') + sprintf(text[i],outf,*((double *)va_arg(va,double *))); + else + sprintf(text[i],outf,*((float *)va_arg(va,float *))); + break; + case 's': + sprintf(text[i],outf,((char *)va_arg(va,char *))); + break; + default: + goto cleanup; + } + } + va_end(va); + + REQUIRE(iupDataEntry(fields_in_count,width,scroll,title,prompt,text)>0); + + fields_out_count=0; + va_start(va,format); + s=strchr(format,'\n')+1; + for (i=0; i<fields_in_count; ++i) + { + s=strchr(s,'\n')+1; + switch (s[-2]) + { + case 'd': + case 'u': + if (s[-3]=='l') + { + if (sscanf(text[i],"%ld",((long *)va_arg(va,long *)))!=1) + if (error < 0) error = fields_out_count; + } + else if (s[-3]=='h') + { + if (sscanf(text[i],"%hd",((short *)va_arg(va,short *)))!=1) + if (error < 0) error = fields_out_count; + } + else + { + if (sscanf(text[i],"%d",((int *)va_arg(va,int *)))!=1) + if (error < 0) error = fields_out_count; + } + break; + case 'i': + case 'o': + case 'x': + case 'X': + if (s[-3]=='l') + { + if (sscanf(text[i],"%li",((long *)va_arg(va,long *)))!=1) + if (error < 0) error = fields_out_count; + } + else if (s[-3]=='h') + { + if (sscanf(text[i],"%hi",((short *)va_arg(va,short *)))!=1) + if (error < 0) error = fields_out_count; + } + else + { + if (sscanf(text[i],"%i",((int *)va_arg(va,int *)))!=1) + if (error < 0) error = fields_out_count; + } + break; + case 'e': + case 'f': + case 'g': + case 'E': + case 'G': + if (s[-3]=='l') + { + if (sscanf(text[i],"%lg",((double *)va_arg(va,double *)))!=1) + if (error < 0) error = fields_out_count; + } + else + { + if (sscanf(text[i], "%g", ((float *)va_arg(va,float *)))!=1) + if (error < 0) error = fields_out_count; + } + break; + case 's': + { + char *s=(char *)va_arg(va,char *); + strcpy(s,text[i]); + } + break; + } + ++fields_out_count; + } + va_end(va); + +cleanup: + if (s1) free(s1); + if (title) free(title); + if (width) free(width); + if (scroll) free(scroll); + if (outf) free(outf); + if (prompt) + { + for (i=0; i<fields_in_count; ++i) + if (prompt[i]) free(prompt[i]); + free(prompt); + } + if (text) + { + for (i=0; i<fields_in_count; ++i) + if (text[i]) free(text[i]); + free(text); + } + + return (error < 0) ? fields_out_count : error; +} diff --git a/iup/src/iup_show.c b/iup/src/iup_show.c new file mode 100755 index 0000000..9ea1408 --- /dev/null +++ b/iup/src/iup_show.c @@ -0,0 +1,256 @@ +/** \file + * \brief show/popup/hide/map + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdarg.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_class.h" +#include "iup_dialog.h" +#include "iup_menu.h" +#include "iup_assert.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" + + +void IupUnmap(Ihandle *ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + /* Invalid if it is NOT mapped. */ + if (!ih->handle) + return; + + /* unmap children */ + { + Ihandle* child = ih->firstchild; + while (child) + { + IupUnmap(child); + child = child->brother; + } + } + + /* only call UNMAP_CB for controls that have a native representation */ + if (ih->iclass->nativetype != IUP_TYPEVOID) + { + Icallback unmap_cb = IupGetCallback(ih, "UNMAP_CB"); + if (unmap_cb) unmap_cb(ih); + } + + /* unmap from the native system */ + iupClassObjectUnMap(ih); + ih->handle = NULL; +} + +static char* iShowGetVisible(Ihandle* ih) +{ + char* value = iupAttribGet(ih, "VISIBLE"); /* Check on the element first */ + while (!value) + { + ih = ih->parent; /* iheritance here independs on the attribute */ + if (!ih) + return NULL; + + value = iupAttribGet(ih, "VISIBLE"); + + /* only recursive up to the native parent */ + if (ih->iclass->nativetype != IUP_TYPEVOID) + return value; /* can be NULL */ + } + + return value; +} + +static void iShowUpdateVisible(Ihandle* ih) +{ + int inherit; + /* although default is VISIBLE=YES, + when mapped the element is still hidden. + So we must manually update the visible state. */ + char* value = iShowGetVisible(ih); + iupClassObjectSetAttribute(ih, "VISIBLE", value, &inherit); +} + +int IupMap(Ihandle* ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return IUP_INVALID; + + /* calculate position and size for all children */ + if (ih->iclass->nativetype == IUP_TYPEDIALOG) + iupLayoutCompute(ih); + + /* already mapped */ + if (ih->handle) + { + if (ih->iclass->nativetype == IUP_TYPEDIALOG) + iupLayoutUpdate(ih); + + return IUP_NOERROR; + } + + /* map to the native system */ + if (iupClassObjectMap(ih) == IUP_ERROR) + { + iupERROR("Error during IupMap."); + return IUP_ERROR; + } + + /* update FONT, must be the before several others */ + if (ih->iclass->nativetype != IUP_TYPEVOID && + ih->iclass->nativetype != IUP_TYPEIMAGE && + ih->iclass->nativetype != IUP_TYPEMENU) + iupUpdateStandardFontAttrib(ih); + + /* ensure attributes default values, at this time only the ones that need to be set after map */ + iupClassObjectEnsureDefaultAttributes(ih); + + /* check visible state if not a dialog */ + if (ih->iclass->nativetype == IUP_TYPECANVAS || + ih->iclass->nativetype == IUP_TYPECONTROL) + iShowUpdateVisible(ih); + + /* updates the defined attributes in the native system. */ + iupAttribUpdate(ih); + + /* updates attributes defined in the parent tree */ + iupAttribUpdateFromParent(ih); + + /* map children */ + { + Ihandle* child = ih->firstchild; + while (child) + { + if (IupMap(child) == IUP_ERROR) + return IUP_ERROR; + + child = child->brother; + } + } + + /* moves and resizes the elements to reflect the layout computation */ + /* if the dialog is visible will be reflected in the user interface */ + if (ih->iclass->nativetype == IUP_TYPEDIALOG) + iupLayoutUpdate(ih); + + /* only call MAP_CB for controls that have a native representation */ + if (ih->iclass->nativetype != IUP_TYPEVOID) + { + Icallback map_cb = IupGetCallback(ih, "MAP_CB"); + if (map_cb) map_cb(ih); + } + + return IUP_NOERROR; +} + +int IupPopup(Ihandle *ih, int x, int y) +{ + int ret; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return IUP_INVALID; + + if (ih->iclass->nativetype != IUP_TYPEDIALOG && + ih->iclass->nativetype != IUP_TYPEMENU) + { + iupERROR("Must be a menu or dialog in IupPopup."); + return IUP_INVALID; + } + + ret = IupMap(ih); + if (ret == IUP_ERROR) + return ret; + + if (ih->iclass->nativetype == IUP_TYPEDIALOG) + ret = iupDialogPopup(ih, x, y); + else + ret = iupMenuPopup(ih, x, y); + + if (ret != IUP_NOERROR) + { + iupERROR("Error during IupPopup."); + return ret; + } + + return IUP_NOERROR; +} + +int IupShowXY(Ihandle *ih, int x, int y) +{ + int ret; + + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return IUP_INVALID; + + if (ih->iclass->nativetype != IUP_TYPEDIALOG) + { + iupERROR("Must be a dialog in IupShowXY."); + return IUP_INVALID; + } + + ret = IupMap(ih); + if (ret == IUP_ERROR) + return ret; + + ret = iupDialogShowXY(ih, x, y); + if (ret != IUP_NOERROR) + { + iupERROR("Error during IupShowXY."); + return ret; + } + + return IUP_NOERROR; +} + +int IupShow(Ihandle* ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return IUP_INVALID; + + if (ih->iclass->nativetype != IUP_TYPEDIALOG) + IupSetAttribute(ih, "VISIBLE", "YES"); + else + { + int ret = IupMap(ih); + if (ret == IUP_ERROR) + return ret; + + ret = iupDialogShowXY(ih, IUP_CURRENT, IUP_CURRENT); + if (ret != IUP_NOERROR) + { + iupERROR("Error during IupShow."); + return ret; + } + } + + return IUP_NOERROR; +} + +int IupHide(Ihandle* ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return IUP_INVALID; + + if (ih->iclass->nativetype != IUP_TYPEDIALOG) + IupSetAttribute(ih, "VISIBLE", "NO"); + else if (ih->handle) + iupDialogHide(ih); + + return IUP_NOERROR; +} diff --git a/iup/src/iup_spin.c b/iup/src/iup_spin.c new file mode 100755 index 0000000..6fadab4 --- /dev/null +++ b/iup/src/iup_spin.c @@ -0,0 +1,301 @@ +/** \file + * \brief Spin control + * + * See Copyright Notice in "iup.h" +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "iup.h" +#include "iupcbs.h" +#include "iupkey.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_stdcontrols.h" +#include "iup_childtree.h" + + +static Ihandle* spin_timer = NULL; + + +static int iSpinCallCB(Ihandle* ih, int dub, int ten, int sign) +{ + IFni cb; + + /* get the callback on the spin or on the spinbox */ + Ihandle* spinbox = (Ihandle*)iupAttribGet(ih->parent, "_IUPSPIN_BOX"); + if (spinbox) + ih = spinbox; + else + ih = ih->parent; + + cb = (IFni) IupGetCallback(ih, "SPIN_CB"); + if (cb) + { + return cb(ih, sign*(dub && ten ? 100 : + ten ? 10 : + dub ? 2 : 1)); + } + + return IUP_DEFAULT; +} + +static int iSpinTimerCB(Ihandle* ih) +{ + Ihandle* spin_button = (Ihandle*)iupAttribGet(ih, "_IUPSPIN_BUTTON"); + char* status = iupAttribGet(ih, "_IUPSPIN_STATUS"); + int spin_dir = iupAttribGetInt(ih, "_IUPSPIN_DIR"); + int count = iupAttribGetInt(ih, "_IUPSPIN_COUNT"); + char* reconfig = NULL; + + if(count == 0) /* first time */ + reconfig = "50"; + else if(count == 14) /* 300 + 14*50 = 1000 (1 second) */ + reconfig = "25"; + else if(count == 34) /* 300 + 14*50 + 20*50 = 2000 (2 seconds) */ + reconfig = "10"; + + if (reconfig) + { + IupSetAttribute(ih, "RUN", "NO"); + IupSetAttribute(ih, "TIME", reconfig); + IupSetAttribute(ih, "RUN", "YES"); + } + + iupAttribSetInt(ih, "_IUPSPIN_COUNT", count + 1); + + return iSpinCallCB(spin_button, iup_isshift(status), iup_iscontrol(status), spin_dir); +} + +static void iSpinPrepareTimer(Ihandle* ih, char* status, char* dir) +{ + (void)ih; + + iupAttribSetStr(spin_timer, "_IUPSPIN_BUTTON", (char*)ih); + + iupAttribStoreStr(spin_timer, "_IUPSPIN_STATUS", status); + + iupAttribSetStr(spin_timer, "_IUPSPIN_DIR", dir); + iupAttribSetStr(spin_timer, "_IUPSPIN_COUNT", "0"); + + IupSetAttribute(spin_timer, "TIME", "400"); + IupSetAttribute(spin_timer, "RUN", "YES"); +} + +static int iSpinK_SP(Ihandle* ih) +{ + int dir = iupAttribGetInt(ih, "_IUPSPIN_DIR"); + + return iSpinCallCB(ih, 0, 0, dir); +} + +static int iSpinK_sSP(Ihandle* ih) +{ + int dir = iupAttribGetInt(ih, "_IUPSPIN_DIR"); + + return iSpinCallCB(ih, 1, 0, dir); +} + +static int iSpinK_cSP(Ihandle* ih) +{ + int dir = iupAttribGetInt(ih, "_IUPSPIN_DIR"); + + return iSpinCallCB(ih, 0, 1, dir); +} + +static int iSpinButtonCB(Ihandle* ih, int but, int pressed, int x, int y, char* status) +{ + (void)x; + (void)y; + + if (pressed && but == IUP_BUTTON1) + { + int dir = iupAttribGetInt(ih, "_IUPSPIN_DIR"); + + iSpinPrepareTimer(ih, status, iupAttribGet(ih, "_IUPSPIN_DIR")); + + return iSpinCallCB(ih, iup_isshift(status), iup_iscontrol(status), dir); + } + else if (!pressed && but == IUP_BUTTON1) + { + IupSetAttribute(spin_timer, "RUN", "NO"); + } + + return IUP_DEFAULT; +} + +static int iSpinCreateMethod(Ihandle* ih, void** params) +{ + Ihandle* bt_up; + Ihandle* bt_down; + (void)params; + + /* Button UP */ + bt_up = IupButton(NULL, NULL); + + IupSetAttribute(bt_up, "EXPAND", "NO"); + IupSetAttribute(bt_up, "IMAGE", "IupSpinUpImage"); + IupSetAttribute(bt_up, "_IUPSPIN_DIR", "1"); + IupSetAttribute(bt_up, "CANFOCUS", "NO"); + + IupSetCallback(bt_up, "BUTTON_CB", (Icallback) iSpinButtonCB); + IupSetCallback(bt_up, "K_SP", (Icallback) iSpinK_SP); + IupSetCallback(bt_up, "K_sSP", (Icallback) iSpinK_sSP); + IupSetCallback(bt_up, "K_cSP", (Icallback) iSpinK_cSP); + + /* Button DOWN */ + bt_down = IupButton(NULL, NULL); + + IupSetAttribute(bt_down, "EXPAND", "NO"); + IupSetAttribute(bt_down, "IMAGE", "IupSpinDownImage"); + IupSetAttribute(bt_down, "_IUPSPIN_DIR", "-1"); + IupSetAttribute(bt_down, "CANFOCUS", "NO"); + + IupSetCallback(bt_down, "BUTTON_CB", (Icallback) iSpinButtonCB); + IupSetCallback(bt_down, "K_SP", (Icallback) iSpinK_SP); + IupSetCallback(bt_down, "K_sSP", (Icallback) iSpinK_sSP); + IupSetCallback(bt_down, "K_cSP", (Icallback) iSpinK_cSP); + + /* manually add the buttons as a children */ + ih->firstchild = bt_up; + bt_up->parent = ih; + bt_up->brother = bt_down; + bt_down->parent = ih; + + IupSetAttribute(ih, "GAP", "0"); + IupSetAttribute(ih, "MARGIN", "0x0"); + + return IUP_NOERROR; +} + +static int iSpinboxCreateMethod(Ihandle* ih, void** params) +{ + Ihandle *spin, *ctrl; + + if (!params || !(params[0])) + return IUP_ERROR; + + IupSetAttribute(ih, "GAP", "0"); + IupSetAttribute(ih, "MARGIN", "0x0"); + IupSetAttribute(ih, "ALIGNMENT", "ACENTER"); + + ctrl = (Ihandle*)(params[0]); + iupChildTreeAppend(ih, ctrl); + + spin = IupSpin(); + iupChildTreeAppend(ih, spin); + + iupAttribSetStr(spin, "_IUPSPIN_BOX", (char*)ih); + + return IUP_NOERROR; +} + +static void iSpinLoadImages(void) +{ + Ihandle* img; + + /* Spin UP image */ + unsigned char iupspin_up_img[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + /* Spin DOWN image */ + unsigned char iupspin_down_img[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + + img = IupImage(9, 6, iupspin_up_img); + IupSetAttribute(img, "0", "0 0 0"); + IupSetAttribute(img, "1", "BGCOLOR"); + IupSetHandle("IupSpinUpImage", img); + + img = IupImage(9, 6, iupspin_down_img); + IupSetAttribute(img, "0", "0 0 0"); + IupSetAttribute(img, "1", "BGCOLOR"); + IupSetHandle("IupSpinDownImage", img); +} + +static void iSpinReleaseMethod(Iclass* ic) +{ + (void)ic; + + if (spin_timer) + { + /* no need to destroy the images, they will be destroyed by IupClose automatically */ + IupDestroy(spin_timer); + spin_timer = NULL; + } +} + +Iclass* iupSpinboxGetClass(void) +{ + Iclass* ic = iupClassNew(iupHboxGetClass()); + + ic->name = "spinbox"; + ic->format = "h"; /* one Ihandle */ + ic->nativetype = IUP_TYPEVOID; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 0; + + iupClassRegisterCallback(ic, "SPIN_CB", "i"); + + /* Class functions */ + ic->Create = iSpinboxCreateMethod; + + return ic; +} + +Iclass* iupSpinGetClass(void) +{ + Iclass* ic = iupClassNew(iupVboxGetClass()); + + ic->name = "spin"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPEVOID; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 0; + + /* Class functions */ + ic->Create = iSpinCreateMethod; + ic->Release = iSpinReleaseMethod; + + iupClassRegisterCallback(ic, "SPIN_CB", "i"); + + if (!spin_timer) + { + iSpinLoadImages(); + + spin_timer = IupTimer(); + IupSetCallback(spin_timer, "ACTION_CB", (Icallback) iSpinTimerCB); + } + + return ic; +} + +Ihandle* IupSpin(void) +{ + return IupCreate("spin"); +} + +Ihandle* IupSpinbox(Ihandle* ctrl) +{ + void *params[2]; + params[0] = (void*)ctrl; + params[1] = NULL; /* must add NULL because spinbox inherit from Hbox */ + return IupCreatev("spinbox", params); +} diff --git a/iup/src/iup_stdcontrols.h b/iup/src/iup_stdcontrols.h new file mode 100755 index 0000000..11499ae --- /dev/null +++ b/iup/src/iup_stdcontrols.h @@ -0,0 +1,76 @@ +/** \file + * \brief Standard Controls Class Initialization functions. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_STDCONTROLS_H +#define __IUP_STDCONTROLS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +Iclass* iupDialogGetClass(void); +Iclass* iupMessageDlgGetClass(void); +Iclass* iupColorDlgGetClass(void); +Iclass* iupFontDlgGetClass(void); +Iclass* iupFileDlgGetClass(void); + +Iclass* iupLabelGetClass(void); +Iclass* iupButtonGetClass(void); +Iclass* iupToggleGetClass(void); +Iclass* iupRadioGetClass(void); +Iclass* iupCanvasGetClass(void); +Iclass* iupFrameGetClass(void); +Iclass* iupProgressBarGetClass(void); +Iclass* iupTextGetClass(void); +Iclass* iupMultilineGetClass(void); +Iclass* iupValGetClass(void); +Iclass* iupTabsGetClass(void); +Iclass* iupSpinGetClass(void); +Iclass* iupSpinboxGetClass(void); +Iclass* iupListGetClass(void); +Iclass* iupTreeGetClass(void); + +Iclass* iupMenuGetClass(void); +Iclass* iupItemGetClass(void); +Iclass* iupSeparatorGetClass(void); +Iclass* iupSubmenuGetClass(void); + +Iclass* iupFillGetClass(void); +Iclass* iupHboxGetClass(void); +Iclass* iupVboxGetClass(void); +Iclass* iupZboxGetClass(void); +Iclass* iupCboxGetClass(void); +Iclass* iupSboxGetClass(void); +Iclass* iupNormalizerGetClass(void); + +Iclass* iupTimerGetClass(void); +Iclass* iupImageGetClass(void); +Iclass* iupImageRGBGetClass(void); +Iclass* iupImageRGBAGetClass(void); +Iclass* iupUserGetClass(void); +Iclass* iupClipboardGetClass(void); + +/*************************************************/ + +void iupdrvMessageDlgInitClass(Iclass* ic); +void iupdrvColorDlgInitClass(Iclass* ic); +void iupdrvFontDlgInitClass(Iclass* ic); +void iupdrvFileDlgInitClass(Iclass* ic); + +/************************************************/ + +/* Common definition of the canvas class */ +typedef struct _iupCanvas { + int sb; /* scrollbar configuration, valid only after map, use iupBaseGetScrollbar before map */ + float posx, posy; +} iupCanvas; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_str.c b/iup/src/iup_str.c new file mode 100755 index 0000000..68976f1 --- /dev/null +++ b/iup/src/iup_str.c @@ -0,0 +1,716 @@ +/** \file + * \brief String Utilities + * + * See Copyright Notice in "iup.h" + */ + + +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> + +#include "iup_str.h" + + +/* Line breaks can be: +\n - UNIX +\r - Mac +\r\n - DOS/Windows +*/ + + +int iupStrEqual(const char* str1, const char* str2) +{ + if (str1 == str2) return 1; + if (!str1 || !str2 || *str1 != *str2) return 0; + return (strcmp(str1, str2)==0)? 1: 0; +} + +int iupStrEqualNoCase(const char* str1, const char* str2) +{ + int i = 0; + if (str1 == str2) return 1; + if (!str1 || !str2 || tolower(*str1) != tolower(*str2)) return 0; + + while (str1[i] && str2[i] && tolower(str1[i])==tolower(str2[i])) + i++; + if (str1[i] == str2[i]) return 1; + + return 0; +} + +int iupStrEqualPartial(const char* str1, const char* str2) +{ + if (str1 == str2) return 1; + if (!str1 || !str2 || *str1 != *str2) return 0; + return (strncmp(str1, str2, strlen(str2))==0)? 1: 0; +} + +int iupStrBoolean(const char* str) +{ + if (!str || str[0]==0) return 0; + if (iupStrEqualNoCase(str, "1")) return 1; + if (iupStrEqualNoCase(str, "YES")) return 1; + if (iupStrEqualNoCase(str, "ON")) return 1; + if (iupStrEqualNoCase(str, "TRUE")) return 1; + return 0; +} + +void iupStrLower(char* dstr, const char* sstr) +{ + for (; *sstr; sstr++, dstr++) + *dstr = (char)tolower(*sstr); + *dstr = 0; +} + +char *iupStrDup(const char *str) +{ + if (str) + { + int size = strlen(str)+1; + char *newstr = malloc(size); + if (newstr) memcpy(newstr, str, size); + return newstr; + } + return NULL; +} + +const char* iupStrNextLine(const char* str, int *len) +{ + *len = 0; + + while(*str!=0 && *str!='\n' && *str!='\r') + { + (*len)++; + str++; + } + + if (*str=='\r' && *(str+1)=='n') /* DOS line end */ + return str+2; + else if (*str=='\n' || *str=='\r') /* UNIX or MAC line end */ + return str+1; + else + return str; /* no next line */ +} + +int iupStrLineCount(const char* str) +{ + int num_lin = 1; + + if (!str) + return num_lin; + + while(*str != 0) + { + while(*str!=0 && *str!='\n' && *str!='\r') + str++; + + if (*str=='\r' && *(str+1)=='n') /* DOS line end */ + { + num_lin++; + str+=2; + } + else if (*str=='\n' || *str=='\r') /* UNIX or MAC line end */ + { + num_lin++; + str++; + } + } + + return num_lin; +} + +int iupStrCountChar(const char *str, int c) +{ + int n; + if (!str) return 0; + for (n=0; *str; str++) + { + if (*str==(char)c) + n++; + } + return n; +} + +void iupStrCopyN(char* dst_str, int dst_max_size, const char* src_str) +{ + int size = strlen(src_str)+1; + if (size > dst_max_size) size = dst_max_size; + memcpy(dst_str, src_str, size); +} + +char *iupStrCopyUntil(char **str, int c) +{ + char *p_str,*new_str; + if (!str || *str==NULL) + return NULL; + + p_str=strchr(*str,c); + if (!p_str) return NULL; + + { + int i; + int sl=(int)(p_str - (*str)); + + new_str = (char *) malloc (sl + 1); + if (!new_str) return NULL; + + for (i = 0; i < sl; ++i) + new_str[i] = (*str)[i]; + + new_str[sl] = 0; + } + + *str = p_str+1; + return new_str; +} + +char *iupStrCopyUntilNoCase(char **str, int c) +{ + char *p_str,*new_str; + if (!str || *str==NULL) + return NULL; + + p_str=strchr(*str,c); /* usually the lower case is enough */ + if (!p_str && isalpha(c)) + { + p_str=strchr(*str, toupper(c)); /* but check also for upper case */ + if (!p_str) return NULL; + } + + { + int i; + int sl=(int)(p_str - (*str)); + + new_str = (char *) malloc (sl + 1); + if (!new_str) return NULL; + + for (i = 0; i < sl; ++i) + new_str[i] = (*str)[i]; + + new_str[sl] = 0; + } + + *str = p_str+1; + return new_str; +} + +char *iupStrGetMemory(int size) +{ +#define MAX_BUFFERS 50 + static char* buffers[MAX_BUFFERS]; + static int buffers_sizes[MAX_BUFFERS]; + static int buffers_index = -1; + + int i; + + if (size == -1) /* Frees memory */ + { + buffers_index = -1; + for (i = 0; i < MAX_BUFFERS; i++) + { + if (buffers[i]) + { + free(buffers[i]); + buffers[i] = NULL; + } + buffers_sizes[i] = 0; + } + return NULL; + } + else + { + char* ret_str; + + if (buffers_index == -1) + { + memset(buffers, 0, sizeof(char*)*MAX_BUFFERS); + memset(buffers_sizes, 0, sizeof(int)*MAX_BUFFERS); + buffers_index = 0; + } + + if (!(buffers[buffers_index])) + { + buffers_sizes[buffers_index] = size+1; + buffers[buffers_index] = (char*)malloc(buffers_sizes[buffers_index]); + } + else if (buffers_sizes[buffers_index] < size+1) + { + buffers_sizes[buffers_index] = size+1; + buffers[buffers_index] = (char*)realloc(buffers[buffers_index], buffers_sizes[buffers_index]); + } + + memset(buffers[buffers_index], 0, buffers_sizes[buffers_index]); + ret_str = buffers[buffers_index]; + + buffers_index++; + if (buffers_index == MAX_BUFFERS) + buffers_index = 0; + + return ret_str; + } +} + +char *iupStrGetMemoryCopy(const char* str) +{ + if (str) + { + int size = strlen(str)+1; + char* ret_str = iupStrGetMemory(size); + memcpy(ret_str, str, size); + return ret_str; + } + else + return NULL; +} + +int iupStrToRGBA(const char *str, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a) +{ + unsigned int ri = 0, gi = 0, bi = 0, ai = 0, ret; + if (!str) return 0; + ret = sscanf(str, "%u %u %u %u", &ri, &gi, &bi, &ai); + if (ret < 3) return 0; + if (ri > 255 || gi > 255 || bi > 255 || ai > 255) return 0; + *r = (unsigned char)ri; + *g = (unsigned char)gi; + *b = (unsigned char)bi; + if (ret == 4) + { + *a = (unsigned char)ai; + return 4; + } + else + return 3; +} + +int iupStrToRGB(const char *str, unsigned char *r, unsigned char *g, unsigned char *b) +{ + unsigned int ri = 0, gi = 0, bi = 0; + if (!str) return 0; + if (sscanf(str, "%u %u %u", &ri, &gi, &bi) != 3) return 0; + if (ri > 255 || gi > 255 || bi > 255) return 0; + *r = (unsigned char)ri; + *g = (unsigned char)gi; + *b = (unsigned char)bi; + return 1; +} + +int iupStrToInt(const char *str, int *i) +{ + if (!str) return 0; + if (sscanf(str, "%d", i) != 1) return 0; + return 1; +} + +int iupStrToIntInt(const char *str, int *i1, int *i2, char sep) +{ + if (!str) return 0; + + if (*str == sep || (isalpha(sep) && *str == toupper(sep))) /* no first value */ + { + str++; /* skip separator */ + if (sscanf(str, "%d", i2) != 1) return 0; + return 1; + } + else + { + char* p_str = iupStrCopyUntilNoCase((char**)&str, sep); + + if (!p_str) /* no separator means no second value */ + { + if (sscanf(str, "%d", i1) != 1) return 0; + return 1; + } + else if (*str==0) /* separator exists, but second value empty, also means no second value */ + { + int ret = sscanf(p_str, "%d", i1); + free(p_str); + if (ret != 1) return 0; + return 1; + } + else + { + int ret = 0; + if (sscanf(p_str, "%d", i1) == 1) ret++; + if (sscanf(str, "%d", i2) == 1) ret++; + free(p_str); + return ret; + } + } +} + +int iupStrToFloat(const char *str, float *f) +{ + if (!str) return 0; + if (sscanf(str, "%f", f) != 1) return 0; + return 1; +} + +int iupStrToFloatFloat(const char *str, float *f1, float *f2, char sep) +{ + if (!str) return 0; + + if (*str == sep || (isalpha(sep) && *str == toupper(sep))) /* no first value */ + { + str++; /* skip separator */ + if (sscanf(str, "%f", f2) != 1) return 0; + return 1; + } + else + { + char* p_str = iupStrCopyUntilNoCase((char**)&str, sep); + + if (!p_str) /* no separator means no second value */ + { + if (sscanf(str, "%f", f1) != 1) return 0; + return 1; + } + else if (*str==0) /* separator exists, but second value empty, also means no second value */ + { + int ret = sscanf(p_str, "%f", f1); + free(p_str); + if (ret != 1) return 0; + return 1; + } + else + { + int ret = 0; + if (sscanf(p_str, "%f", f1) != 1) ret++; + if (sscanf(str, "%f", f2) != 1) ret++; + free(p_str); + return ret; + } + } +} + +int iupStrToStrStr(const char *str, char *str1, char *str2, char sep) +{ + if (!str) return 0; + + if (*str == sep || (isalpha(sep) && *str == toupper(sep))) /* no first value */ + { + str++; /* skip separator */ + strcpy(str2, str); + return 1; + } + else + { + char* p_str = iupStrCopyUntilNoCase((char**)&str, sep); + + if (!p_str) /* no separator means no second value */ + { + strcpy(str1, str); + return 1; + } + else if (*str==0) /* separator exists, but second value empty, also means no second value */ + { + strcpy(str1, p_str); + free(p_str); + return 1; + } + else + { + strcpy(str1, p_str); + strcpy(str2, str); + free(p_str); + return 2; + } + } +} + +char* iupStrFileGetPath(const char *file_name) +{ + /* Starts at the last character */ + int len = strlen(file_name) - 1; + while (len != 0) + { + if (file_name[len] == '\\' || file_name[len] == '/') + { + len++; + break; + } + + len--; + } + + if (len == 0) + return NULL; + + { + char* path = malloc(len+1); + memcpy(path, file_name, len); + path[len] = 0; + + return path; + } +} + +char* iupStrFileGetTitle(const char *file_name) +{ + /* Starts at the last character */ + int len = strlen(file_name); + int offset = len - 1; + while (offset != 0) + { + if (file_name[offset] == '\\' || file_name[offset] == '/') + { + offset++; + break; + } + + offset--; + } + + { + int title_size = len - offset + 1; + char* file_title = malloc(title_size); + memcpy(file_title, file_name + offset, title_size); + return file_title; + } +} + +char* iupStrFileGetExt(const char *file_name) +{ + /* Starts at the last character */ + int len = strlen(file_name); + int offset = len - 1; + while (offset != 0) + { + /* if found a path separator stop. */ + if (file_name[offset] == '\\' || file_name[offset] == '/') + return NULL; + + if (file_name[offset] == '.') + { + offset++; + break; + } + + offset--; + } + + if (offset == 0) + return NULL; + + { + int ext_size = len - offset + 1; + char* file_ext = (char*)malloc(ext_size); + memcpy(file_ext, file_name + offset, ext_size); + return file_ext; + } +} + +char* iupStrFileMakeFileName(const char* path, const char* title) +{ + int size_path = strlen(path); + int size_title = strlen(title); + char *filename = malloc(size_path + size_title + 2); + memcpy(filename, path, size_path); + + if (path[size_path-1] != '/') + { + filename[size_path] = '/'; + size_path++; + } + + memcpy(filename+size_path, title, size_title); + filename[size_path+size_title] = 0; + + return filename; +} + +int iupStrReplace(char* str, char src, char dst) +{ + int i = 0; + while (*str) + { + if (*str == src) + { + *str = dst; + i++; + } + str++; + } + return i; +} + +void iupStrToUnix(char* str) +{ + char* pstr = str; + + if (!str) return; + + while (*str) + { + if (*str == '\r') + { + if (*(str+1) != '\n') /* MAC line end */ + *pstr++ = '\n'; + str++; + } + else + *pstr++ = *str++; + } + + *pstr = *str; +} + +char* iupStrToMac(const char* str) +{ + int at_start = 1; + char* pstr, *new_str; + + if (!str) return NULL; + + if (iupStrLineCount(str) == 1) + return (char*)str; + + new_str = iupStrDup(str); + str = new_str; + pstr = new_str; + + while (*str) + { + if (*str == '\n') + { + if (!at_start && *(str-1) != '\r') /* UNIX line end */ + *pstr++ = '\r'; + str++; + } + else + *pstr++ = *str++; + at_start = 0; + } + + *pstr = *str; + + return new_str; +} + +char* iupStrToDos(const char* str) +{ + char *auxstr, *newstr; + int num_lin; + + if (!str) return NULL; + + num_lin = iupStrLineCount(str); + if (num_lin == 1) + return (char*)str; + + newstr = malloc(num_lin + strlen(str) + 1); + auxstr = newstr; + while(*str) + { + if (*str == '\r' && *(str+1)=='\n') /* DOS line end */ + { + *auxstr++ = *str++; + *auxstr++ = *str++; + } + else if (*str == '\r') /* MAC line end */ + { + *auxstr++ = *str++; + *auxstr++ = '\n'; + } + else if (*str == '\n') /* UNIX line end */ + { + *auxstr++ = '\r'; + *auxstr++ = *str++; + } + else + *auxstr++ = *str++; + } + *auxstr = 0; + + return newstr; +} + +void iupStrRemove(char* value, int start, int end, int dir) +{ + if (start == end) + { + if (dir==1) + end++; + else if (start == 0) /* there is nothing to remove before */ + return; + else + start--; + } + value += start; + end -= start; + while (*value) + { + *value = *(value+end); + value++; + } +} + +char* iupStrInsert(const char* value, const char* insert_value, int start, int end) +{ + char* new_value = (char*)value; + int insert_len = strlen(insert_value); + int len = strlen(value); + if (end==start || insert_len > end-start) + { + new_value = malloc(len - (end-start) + insert_len + 1); + memcpy(new_value, value, start); + memcpy(new_value+start, insert_value, insert_len); + memcpy(new_value+start+insert_len, value+end, len-end+1); + } + else + { + memcpy(new_value+start, insert_value, insert_len); + memcpy(new_value+start+insert_len, value+end, len-end+1); + } + return new_value; +} + +char* iupStrProcessMnemonic(const char* str, char *c, int action) +{ + int i = 0, found = 0; + char* new_str, *orig_str = (char*)str; + + if (!str) return NULL; + + if (!strchr(str, '&')) + return (char*)str; + + new_str = malloc(strlen(str)+1); + while (*str) + { + if (*str == '&') + { + if (*(str+1) == '&') /* remove & from the string, add next & to the string */ + { + str++; + new_str[i++] = *str; + } + else if (!found) /* mnemonic found */ + { + found = 1; + + if (action == 1) /* replace & by c */ + new_str[i++] = *c; + else if (action == -1) /* remove & and return in c */ + *c = *(str+1); /* next is mnemonic */ + /* else -- only remove & */ + } + } + else + { + new_str[i++] = *str; + } + + str++; + } + new_str[i] = 0; + + if (!found) + { + free(new_str); + return orig_str; + } + + return new_str; +} diff --git a/iup/src/iup_str.h b/iup/src/iup_str.h new file mode 100755 index 0000000..1c2e7a5 --- /dev/null +++ b/iup/src/iup_str.h @@ -0,0 +1,183 @@ +/** \file + * \brief String Utilities + * + * See Copyright Notice in "iup.h" + */ + + +#ifndef __IUP_STR_H +#define __IUP_STR_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup str String Utilities + * \par + * See \ref iup_str.h + * \ingroup util */ + +/** Returns a copy of the given string. + * If str is NULL it will return NULL. + * \ingroup str */ +char* iupStrDup(const char* str); + +/** Returns a non zero value if the two strings are equal. + * str1 or str2 can be NULL. + * \ingroup str */ +int iupStrEqual(const char* str1, const char* str2); + +/** Returns a non zero value if the two strings are equal but ignores case. + * str1 or str2 can be NULL. + * \ingroup str */ +int iupStrEqualNoCase(const char* str1, const char* str2); + +/** Returns a non zero value if the two strings are equal + * up to a number of characters defined by the strlen of the second string. + * str1 or str2 can be NULL. + * \ingroup str */ +int iupStrEqualPartial(const char* str1, const char* str2); + +/** Returns 1 if the string is "1", "YES", "ON" or "TRUE". \n + * Returns 0 if the string is "0", "NO", "OFF" or "FALSE", or the string is NULL or empty. + * \ingroup str */ +int iupStrBoolean(const char* str); + +/** Returns the number of lines in a string. + * It works for UNIX, DOS and MAC line ends. + * \ingroup str */ +int iupStrLineCount(const char* str); + +/** Returns the a pointer to the next line and the size of the current line. + * It works for UNIX, DOS and MAC line ends. The size does not includes the line end. + * If str is NULL it will return NULL. + * \ingroup str */ +const char* iupStrNextLine(const char* str, int *len); + +/** Returns the number of repetitions of the character occours in the string. + * \ingroup str */ +int iupStrCountChar(const char *str, int c); + +/** Returns a new string containing a copy of the string up to the character. + * The string is then incremented to after the position of the character. + * \ingroup str */ +char *iupStrCopyUntil(char **str, int c); + +/** Copy the string to the buffer, but limited to the max_size of the buffer. + * buffer is always porperly ended. + * \ingroup str */ +void iupStrCopyN(char* dst_str, int dst_max_size, const char* src_str); + +/** Returns a buffer with the specified size+1. \n + * The buffer is resused after 50 calls. It must NOT be freed. + * Use size=-1 to free all the internal buffers. + * \ingroup str */ +char *iupStrGetMemory(int size); + +/** Returns a buffer that contains a copy of the given buffer using \ref iupStrGetMemory. + * \ingroup str */ +char *iupStrGetMemoryCopy(const char* str); + +/** Converts a string into lower case. + * \ingroup str */ +void iupStrLower(char* dstr, const char* sstr); + +/** Extract a RGB triple from the string. Returns 0 or 1. + * \ingroup str */ +int iupStrToRGB(const char *str, unsigned char *r, unsigned char *g, unsigned char *b); + +/** Extract a RGBA quad from the string, alpha is optional. Returns 0, 3 or 4. + * \ingroup str */ +int iupStrToRGBA(const char *str, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a); + +/** Converts the string to an int. The string must contains only the integer value. + * Returns a a non zero value if sucessfull. + * \ingroup str */ +int iupStrToInt(const char *str, int *i); + +/** Converts the string to two int. The string must contains two integer values in sequence, + * separated by the given character (usually 'x' or ':'). + * Returns the number of converted values. + * Values not extracted are not changed. + * \ingroup str */ +int iupStrToIntInt(const char *str, int *i1, int *i2, char sep); + +/** Converts the string to an float. The string must contains only the real value. + * Returns a a non zero value if sucessfull. + * \ingroup str */ +int iupStrToFloat(const char *str, float *f); + +/** Converts the string to two float. The string must contains two real values in sequence, + * separated by the given character (usually 'x' or ':'). + * Returns the number of converted values. + * Values not extracted are not changed. + * \ingroup str */ +int iupStrToFloatFloat(const char *str, float *f1, float *f2, char sep); + +/** Extract two strings from the string. + * separated by the given character (usually 'x' or ':'). + * Returns the number of converted values. + * Values not extracted are not changed. + * \ingroup str */ +int iupStrToStrStr(const char *str, char *str1, char *str2, char sep); + +/** Returns the file extension of a file name. + * Supports UNIX and Windows directory separators. + * \ingroup str */ +char* iupStrFileGetExt(const char *file_name); + +/** Returns the file title of a file name. + * Supports UNIX and Windows directory separators. + * \ingroup str */ +char* iupStrFileGetTitle(const char *file_name); + +/** Returns the file path of a file name. + * Supports UNIX and Windows directory separators. + * \ingroup str */ +char* iupStrFileGetPath(const char *file_name); + +/** Concat path and title addind '/' between if path does not have it. + * \ingroup str */ +char* iupStrFileMakeFileName(const char* path, const char* title); + +/** Replace a character in a string. + * Returns the number of occurrences. + * \ingroup str */ +int iupStrReplace(char* str, char src, char dst); + +/** Convert line ends to UNIX format in place (one \n per line). + * \ingroup str */ +void iupStrToUnix(char* str); + +/** Convert line ends to MAC format (one \r per line). + * If returned pointer different than input it must be freed. + * \ingroup str */ +char* iupStrToMac(const char* str); + +/** Convert line ends to DOS/Windows format (the sequence \r\n per line). + * If returned pointer different than input it must be freed. + * \ingroup str */ +char* iupStrToDos(const char* str); + +/** Remove the interval from the string. Done in place. + * \ingroup str */ +void iupStrRemove(char* value, int start, int end, int dir); + +/** Remove the interval from the string and insert the new string at the start. + * \ingroup str */ +char* iupStrInsert(const char* value, const char* insert_value, int start, int end); + +/** Process the mnemonic in the string. If not found returns str. + * If found returns a new string. Action can be: +- 1: replace & by c +- -1: remove & and return in c +- 0: remove & + * \ingroup str */ +char* iupStrProcessMnemonic(const char* str, char *c, int action); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_strmessage.c b/iup/src/iup_strmessage.c new file mode 100755 index 0000000..5f23528 --- /dev/null +++ b/iup/src/iup_strmessage.c @@ -0,0 +1,137 @@ +/** \file + * \brief String Utilities + * + * See Copyright Notice in "iup.h" + */ + + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <limits.h> +#include <stdarg.h> + +#include "iup.h" + +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_strmessage.h" +#include "iup_table.h" + + +static Itable *istrmessage_table = NULL; /* the function hast table indexed by the name string */ + +void iupStrMessageInit(void) +{ + istrmessage_table = iupTableCreate(IUPTABLE_STRINGINDEXED); +} + +void iupStrMessageFinish(void) +{ + iupTableDestroy(istrmessage_table); + istrmessage_table = NULL; +} + +char* iupStrMessageGet(const char* message) +{ + return (char*)iupTableGet(istrmessage_table, message); +} + +static void iStrMessageSet(const char* message, const char* str) +{ + iupTableSet(istrmessage_table, message, (char*)str, IUPTABLE_POINTER); +} + +void iupStrMessageShowError(Ihandle* parent, const char* message) +{ + Ihandle* dlg = IupMessageDlg(); + char* title = NULL, *str_message; + + if (parent) + { + IupSetAttributeHandle(dlg, "PARENTDIALOG", parent); + title = IupGetAttribute(parent, "TITLE"); + } + + if (!title) + title = iupStrMessageGet("IUP_ERROR"); + + IupSetAttribute(dlg, "TITLE", title); + IupSetAttribute(dlg, "DIALOGTYPE", "ERROR"); + IupSetAttribute(dlg, "BUTTONS", "OK"); + + str_message = iupStrMessageGet(message); + if (!str_message) + str_message = (char*)message; + IupSetAttribute(dlg, "VALUE", str_message); + + IupPopup(dlg, IUP_CURRENT, IUP_CURRENT); + + IupDestroy(dlg); +} + +typedef struct _IstdMessage +{ + const char* code; + const char* lng_msg[3]; /* 2+1 for expansion */ +} IstdMessage; + +/* Edit this table to add support for more languages */ + +static IstdMessage iStdMessages[] = +{ + {"IUP_ERROR", {"Error", "Erro", NULL}}, + {"IUP_YES", {"Yes", "Sim", NULL}}, + {"IUP_NO", {"No", "Não", NULL}}, + {"IUP_INVALIDDIR", {"Invalid directory.", "Diretório inválido.", NULL}}, + {"IUP_FILEISDIR", {"The selected name is a directory.", "O nome selecionado é um diretório.", NULL}}, + {"IUP_FILENOTEXIST", {"File does not exist.", "Arquivo inexistente.", NULL}}, + {"IUP_FILEOVERWRITE", {"Overwrite existing file?", "Sobrescrever arquivo?", NULL}}, + {"IUP_CREATEFOLDER", {"Create Folder", "Criar Diretório", NULL}}, + {"IUP_NAMENEWFOLDER", {"Name of the new folder:", "Nome do novo diretório:", NULL}}, + {"IUP_SAVEAS", {"Save As", "Salvar Como", NULL}}, + {"IUP_OPEN", {"Open", "Abrir", NULL}}, + {"IUP_SELECTDIR", {"Select Directory", "Selecionar Diretório", NULL}}, + {"IUP_CANCEL", {"Cancel", "Cancela", NULL}}, + {"IUP_GETCOLOR", {"Color Selection", "Seleção de Cor", NULL}}, + {"IUP_HELP", {"Help", "Ajuda", NULL}}, + {"IUP_RED", {"&Red:", "&Vermelho:", NULL}}, + {"IUP_GREEN", {"&Green:", "V&erde:", NULL}}, + {"IUP_BLUE", {"&Blue:", "&Azul:", NULL}}, + {"IUP_HUE", {"&Hue:", "&Matiz:", NULL}}, + {"IUP_SATURATION", {"&Saturation:", "&Saturação:", NULL}}, + {"IUP_INTENSITY", {"&Intensity:", "&Intensidade:", NULL}}, + {"IUP_OPACITY", {"&Opacity:", "&Opacidade:", NULL}}, + {"IUP_PALETTE", {"&Palette:", "&Paleta:", NULL}}, + {"IUP_TRUE", {"True", "Verdadeiro", NULL}}, + {"IUP_FALSE", {"False", "Falso", NULL}}, + {NULL, {NULL, NULL, NULL}} +}; + +static void iStrRegisterInternalMessages(int lng) +{ + IstdMessage* messages = iStdMessages; + while (messages->code) + { + iStrMessageSet(messages->code, messages->lng_msg[lng]); + messages++; + } +} + +void iupStrMessageUpdateLanguage(const char* language) +{ + int lng = 0; + if (iupStrEqualNoCase(language, "PORTUGUESE")) + lng = 1; + iStrRegisterInternalMessages(lng); +} + +void IupSetLanguage(const char *language) +{ + IupStoreGlobal("LANGUAGE", language); +} + +char *IupGetLanguage(void) +{ + return IupGetGlobal("LANGUAGE"); +} diff --git a/iup/src/iup_strmessage.h b/iup/src/iup_strmessage.h new file mode 100755 index 0000000..dbd0374 --- /dev/null +++ b/iup/src/iup_strmessage.h @@ -0,0 +1,45 @@ +/** \file + * \brief Language Dependent String Messages + * + * See Copyright Notice in "iup.h" + */ + + +#ifndef __IUP_STRMESSAGE_H +#define __IUP_STRMESSAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \defgroup strmessage Language Dependent String Messages + * \par + * String database that is dependend of the selected language. + * \par + * See \ref iup_strmessage.h + * \ingroup util */ + +/** Pre-defined dialog to show an error message. Based in IupMessageDlg. + * Message can be a registered coded message or a commom string. + * \ingroup strmessage */ +void iupStrMessageShowError(Ihandle* parent, const char* message); + +/** Returns a common string from a registered coded message. + * The returned string depends on the global LANGUAGE attribute. + * \ingroup strmessage */ +char* iupStrMessageGet(const char* message); + +/* Called from iup_global */ +void iupStrMessageUpdateLanguage(const char* language); + +/* called only in IupOpen and IupClose */ +void iupStrMessageInit(void); +void iupStrMessageFinish(void); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_table.c b/iup/src/iup_table.c new file mode 100755 index 0000000..9e97ff5 --- /dev/null +++ b/iup/src/iup_table.c @@ -0,0 +1,736 @@ +/** \file + * \brief iupTable functions. + * Implementation by Danny Reinhold and Antonio Scuri. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> + +#include "iup_table.h" +#include "iup_str.h" +#include "iup_assert.h" + +/* #define DEBUGTABLE 1 */ + +/* Adjust these parameters for optimal performance and memory usage */ +static const unsigned int itable_maxTableSizeIndex = 8; +static const unsigned int itable_hashTableSize[] = { 31, 101, 401, 1601, 4001, 8009, 16001, 32003, 64007 }; +static const float itable_resizeLimit = 2; +static const unsigned int itable_itemGrow = 5; + +/* Iteration context. + */ +typedef struct ItableContext +{ + unsigned int entryIndex; /* index at the Itable::entries array */ + unsigned int itemIndex; /* index at the ItableEntry::items array */ +} ItableContext; + +/* A key of an item. + * To avoid lots of string comparisions we store + * a keyindex as an integer. + * To find a key in an item list we only have to + * do integer comparisions. + * Additionally the key itself is stored in + * keyStr. In a string indexed hashtable this is + * a duplicated string, in a pointer indexed hash table + * this is simply the pointer (in this case keyIndex + * and keyStr are equal). +*/ +typedef struct ItableKey +{ + unsigned long keyIndex; /* the secondary hash number */ + const char *keyStr; +} +ItableKey; + +/* An item in the hash table. + * Such an item is stored in the item list of + * an entry. + */ +typedef struct ItableItem +{ + Itable_Types itemType; + ItableKey key; + void *value; +} +ItableItem; + +/* An entry in the hash table. + * An entry is chosen by an index in the hash table + * and contains a list of items. + * The number of items in this list is stored + * in nextItemIndex. + * size is the current size of the items array. + */ +typedef struct ItableEntry +{ + unsigned int nextItemIndex; + unsigned int size; + ItableItem *items; +} +ItableEntry; + + +/* A hash table. + * indexType is the type of the index. + * entries is an array of entries. Select an + * entry by its index. + * size is the number of entries in the hash table... + */ +struct Itable +{ + unsigned int size; + unsigned int numberOfEntries; + unsigned int tableSizeIndex; /* index into itable_hashTableSize array */ + Itable_IndexTypes indexType; + ItableEntry *entries; + ItableContext context; +}; + + +/* Prototypes of private functions */ + +static void iTableFreeItemArray(Itable_IndexTypes indexType, unsigned int nextFreeIndex, + ItableItem *items); +static unsigned int iTableGetEntryIndex(Itable *it, const char *key, unsigned long *keyIndex); +static unsigned int iTableFindItem(Itable *it, const char *key, ItableEntry **entry, + unsigned int *itemIndex, + unsigned long *keyIndex); +static unsigned int iTableResize(Itable *it); +static void iTableAdd(Itable *it, ItableKey *key, void *value, Itable_Types itemType); +static void iTableUpdateArraySize(ItableEntry *entry); + +#ifdef DEBUGTABLE +static void iTableShowStatistics(Itable *it); +static void iTableCheckDuplicated(ItableItem *item, unsigned int nextItemIndex, + const char *key, + unsigned long keyIndex); +#endif + + +Itable *iupTableCreate(Itable_IndexTypes indexType) +{ + return iupTableCreateSized(indexType, 1); /* 101 shows to be a better start for IUP */ +} + + +Itable *iupTableCreateSized(Itable_IndexTypes indexType, unsigned int initialSizeIndex) +{ + Itable *it = (Itable *)malloc(sizeof(struct Itable)); + + iupASSERT(it!=NULL); + if (!it) + return 0; + + if (initialSizeIndex > itable_maxTableSizeIndex) + initialSizeIndex = itable_maxTableSizeIndex; + + it->size = itable_hashTableSize[initialSizeIndex]; + it->tableSizeIndex = initialSizeIndex; + it->numberOfEntries = 0; + it->indexType = indexType; + + it->entries = (ItableEntry *)malloc(it->size * sizeof(ItableEntry)); + iupASSERT(it->entries!=NULL); + if (!it->entries) + { + free(it); + return 0; + } + + memset(it->entries, 0, it->size * sizeof(ItableEntry)); + + it->context.entryIndex = (unsigned int)-1; + it->context.itemIndex = (unsigned int)-1; + + return it; +} + +void iupTableClear(Itable *it) +{ + unsigned int i; + + if (!it) + return; + + for (i = 0; i < it->size; i++) + { + ItableEntry *entry = &(it->entries[i]); + if (entry->items) + iTableFreeItemArray(it->indexType, entry->nextItemIndex, entry->items); + } + + it->numberOfEntries = 0; + + memset(it->entries, 0, it->size * sizeof(ItableEntry)); + + it->context.entryIndex = (unsigned int)-1; + it->context.itemIndex = (unsigned int)-1; +} + +void iupTableDestroy(Itable *it) +{ + if (!it) + return; + +#ifdef DEBUGTABLE + iTableShowStatistics(it); +#endif + + iupTableClear(it); + + if (it->entries) + free(it->entries); + + free(it); +} + +int iupTableCount(Itable *it) +{ + iupASSERT(it!=NULL); + if (!it) + return 0; + return it->numberOfEntries; +} + +void iupTableSetFunc(Itable *it, const char *key, Ifunc func) +{ + iupTableSet(it, key, (void*)func, IUPTABLE_FUNCPOINTER); /* type cast from function pointer to void* */ +} + +void iupTableSet(Itable *it, const char *key, void *value, Itable_Types itemType) +{ + unsigned int itemIndex, + itemFound; + unsigned long keyIndex; + ItableEntry *entry; + ItableItem *item; + void *v; + + iupASSERT(it!=NULL); + iupASSERT(key!=NULL); + if (!it || !key || !value) + return; + + itemFound = iTableFindItem(it, key, &entry, &itemIndex, &keyIndex); + +#ifdef DEBUGTABLE + if (it->indexType == IUPTABLE_STRINGINDEXED) + iTableCheckDuplicated(&(entry->items[0]), entry->nextItemIndex, key, keyIndex); +#endif + + if (!itemFound) + { + /* create a new item */ + + /* first check if the hash table has to be reorganized */ + if (iTableResize(it)) + { + /* We have to search for the entry again, since it may + * have been moved by iTableResize. */ + iTableFindItem(it, key, &entry, &itemIndex, &keyIndex); + } + + iTableUpdateArraySize(entry); + + /* add the item at the end of the item array */ + if (itemType == IUPTABLE_STRING) + v = iupStrDup(value); + else + v = value; + + item = &(entry->items[entry->nextItemIndex]); + + item->itemType = itemType; + item->key.keyIndex = keyIndex; + item->key.keyStr = it->indexType == IUPTABLE_STRINGINDEXED? iupStrDup(key) : key; + item->value = v; + + entry->nextItemIndex++; + it->numberOfEntries++; + } + else + { + /* change an existing item */ + void *v; + item = &(entry->items[itemIndex]); + + if (itemType == IUPTABLE_STRING && item->itemType == IUPTABLE_STRING) + { + /* this will avoid to free + alloc of a new pointer */ + if (iupStrEqual((char*)item->value, (char*)value)) + return; + } + + if (itemType == IUPTABLE_STRING) + v = iupStrDup(value); + else + v = value; + + if (item->itemType == IUPTABLE_STRING) + free(item->value); + + item->value = v; + item->itemType = itemType; + } +} + +static void iTableRemoveItem(Itable *it, ItableEntry *entry, unsigned int itemIndex) +{ + ItableItem *item; + unsigned int i; + + item = &(entry->items[itemIndex]); + + if (it->indexType == IUPTABLE_STRINGINDEXED) + free((void *)item->key.keyStr); + + if (item->itemType == IUPTABLE_STRING) + free(item->value); + + /* order the remaining items */ + for (i = itemIndex; i < entry->nextItemIndex-1; i++) + entry->items[i] = entry->items[i+1]; + + /* clear the non used item */ + memset(entry->items + entry->nextItemIndex, 0, sizeof (ItableItem)); + + entry->nextItemIndex--; + it->numberOfEntries--; +} + +void iupTableRemove(Itable *it, const char *key) +{ + unsigned int itemFound, + itemIndex; + unsigned long keyIndex; + ItableEntry *entry; + + iupASSERT(it!=NULL); + iupASSERT(key!=NULL); + if (!it || !key) + return; + + itemFound = iTableFindItem(it, key, &entry, &itemIndex, &keyIndex); + if (itemFound) + iTableRemoveItem(it, entry, itemIndex); +} + +void *iupTableGet(Itable *it, const char *key) +{ + unsigned int itemFound, + itemIndex; + unsigned long keyIndex; + ItableEntry *entry; + void *value = 0; + + iupASSERT(it!=NULL); + iupASSERT(key!=NULL); + if (!it || !key) + return 0; + + itemFound = iTableFindItem(it, key, &entry, &itemIndex, &keyIndex); + if (itemFound) + value = entry->items[itemIndex].value; + + return value; +} + +Ifunc iupTableGetFunc(Itable *it, const char *key, void **value) +{ + Itable_Types itemType = IUPTABLE_POINTER; + *value = iupTableGetTyped(it, key, &itemType); + if (itemType == IUPTABLE_FUNCPOINTER) + return (Ifunc)(*value); /* type cast from void* to function pointer */ + else + return (Ifunc)0; +} + +void *iupTableGetTyped(Itable *it, const char *key, Itable_Types *itemType) +{ + unsigned int itemFound, + itemIndex; + unsigned long keyIndex; + ItableEntry *entry; + void *value = 0; + + iupASSERT(it!=NULL); + iupASSERT(key!=NULL); + if (!it || !key) + return 0; + + itemFound = iTableFindItem(it, key, &entry, &itemIndex, &keyIndex); + if (itemFound) + { + value = entry->items[itemIndex].value; + if (itemType) + *itemType = entry->items[itemIndex].itemType; + } + + return value; +} + +void *iupTableGetCurr(Itable *it) +{ + iupASSERT(it!=NULL); + if (!it || it->context.entryIndex == (unsigned int)-1 + || it->context.itemIndex == (unsigned int)-1) + return 0; + + return it->entries[it->context.entryIndex].items[it->context.itemIndex].value; +} + + +char *iupTableFirst(Itable *it) +{ + unsigned int entryIndex; + + iupASSERT(it!=NULL); + if (!it) + return 0; + + it->context.entryIndex = (unsigned int)-1; + it->context.itemIndex = (unsigned int)-1; + + /* find the first used entry */ + for (entryIndex = 0; entryIndex < it->size; entryIndex++) + { + if (it->entries[entryIndex].nextItemIndex > 0) + { + it->context.entryIndex = entryIndex; + it->context.itemIndex = 0; + return (char*)it->entries[entryIndex].items[0].key.keyStr; + } + } + + return 0; +} + + +char *iupTableNext(Itable *it) +{ + unsigned int entryIndex; + + iupASSERT(it!=NULL); + if (!it || it->context.entryIndex == (unsigned int)-1 + || it->context.itemIndex == (unsigned int)-1) + return 0; + + if (it->context.itemIndex + 1 < it->entries[it->context.entryIndex].nextItemIndex) + { + /* key in the current entry */ + it->context.itemIndex++; + return (char*)it->entries[it->context.entryIndex].items[it->context.itemIndex].key.keyStr; + } + else + { + /* find the next used entry */ + for (entryIndex = it->context.entryIndex+1; entryIndex < it->size; entryIndex++) + { + if (it->entries[entryIndex].nextItemIndex > 0) + { + it->context.entryIndex = entryIndex; + it->context.itemIndex = 0; + return (char*)it->entries[entryIndex].items[0].key.keyStr; + } + } + } + + return 0; +} + +char *iupTableRemoveCurr(Itable *it) +{ + char* key; + unsigned int entryIndex; + ItableEntry *entry; + unsigned int itemIndex; + + iupASSERT(it!=NULL); + if (!it || it->context.entryIndex == (unsigned int)-1 + || it->context.itemIndex == (unsigned int)-1) + return 0; + + entry = &it->entries[it->context.entryIndex]; + itemIndex = it->context.itemIndex; + + if (it->context.itemIndex + 1 < it->entries[it->context.entryIndex].nextItemIndex) + { + /* key in the current entry */ + it->context.itemIndex++; + key = (char*)it->entries[it->context.entryIndex].items[it->context.itemIndex].key.keyStr; + + iTableRemoveItem(it, entry, itemIndex); + return key; + } + else + { + /* find the next used entry */ + for (entryIndex = it->context.entryIndex+1; entryIndex < it->size; entryIndex++) + { + if (it->entries[entryIndex].nextItemIndex > 0) + { + it->context.entryIndex = entryIndex; + it->context.itemIndex = 0; + key = (char*)it->entries[entryIndex].items[0].key.keyStr; + + iTableRemoveItem(it, entry, itemIndex); + return key; + } + } + } + + return 0; +} + + +/********************************************/ +/* Private functions */ +/********************************************/ + + +static void iTableFreeItemArray(Itable_IndexTypes indexType, unsigned int nextFreeIndex, ItableItem *items) +{ + unsigned int i; + + iupASSERT(items!=NULL); + if (!items) + return; + + if (indexType == IUPTABLE_STRINGINDEXED) + { + for (i = 0; i < nextFreeIndex; i++) + free((void *)(items[i].key.keyStr)); + } + + for (i = 0; i < nextFreeIndex; i++) + { + if (items[i].itemType == IUPTABLE_STRING) + free(items[i].value); + } + + free(items); +} + + +static unsigned int iTableGetEntryIndex(Itable *it, const char *key, unsigned long *keyIndex) +{ + if (it->indexType == IUPTABLE_STRINGINDEXED) + { + register unsigned int checksum = 0; + +/* Orignal version + unsigned int i; + for (i = 0; key[i]; i++) + checksum = checksum*31 + key[i]; +*/ + + while (*key) + { + checksum *= 31; + checksum += *key; + key++; + } + + *keyIndex = checksum; /* this could NOT be dependent from table size */ + } + else + { + /* Pointer indexed */ + *keyIndex = (unsigned long)key; /* this could NOT be dependent from table size */ + } + + return (unsigned int)((*keyIndex) % it->size); +} + +#ifdef DEBUGTABLE +static void iTableCheckDuplicated(ItableItem *item, unsigned int nextItemIndex, const char *key, + unsigned long keyIndex) +{ + unsigned int i; + for (i = 0; i < nextItemIndex; i++, item++) + { + if (!iupStrEqual((char*)item->key.keyStr, (char*)key) && + item->key.keyIndex == keyIndex) + { + fprintf(stderr, "#ERROR# Duplicated key index (%ld): %s %s \n", keyIndex, + (char*)item->key.keyStr, + (char*)key); + } + } +} +#endif + +static unsigned int iTableFindItem(Itable *it, const char *key, ItableEntry **entry, + unsigned int *itemIndex, + unsigned long *keyIndex) +{ + unsigned int entryIndex, + itemFound, + i; + ItableItem *item; + + entryIndex = iTableGetEntryIndex(it, key, keyIndex); + + *entry = &(it->entries[entryIndex]); + + item = &((*entry)->items[0]); + for (i = 0; i < (*entry)->nextItemIndex; i++, item++) + { + if (it->indexType == IUPTABLE_STRINGINDEXED) + itemFound = item->key.keyIndex == *keyIndex; +/* itemFound = iupStrEqual(item->key.keyStr, key); This is the original safe version */ + else + itemFound = item->key.keyStr == key; + + if (itemFound) + { + *itemIndex = i; + return 1; + } + } + + /* if not found "entry", "itemIndex" and "keyIndex" will have the new insert position. */ + + *itemIndex = i; + return 0; +} + +static void iTableUpdateArraySize(ItableEntry *entry) +{ + if (entry->nextItemIndex >= entry->size) + { + /* we have to expand the item array */ + unsigned int newSize; + + newSize = entry->size + itable_itemGrow; + + entry->items = (ItableItem *)realloc(entry->items, newSize * sizeof(ItableItem)); + iupASSERT(entry->items!=NULL); + if (!entry->items) + return; + + memset(entry->items + entry->size, 0, itable_itemGrow * sizeof(ItableItem)); + + entry->size = newSize; + } +} + + +static void iTableAdd(Itable *it, ItableKey *key, void *value, Itable_Types itemType) +{ + unsigned int entryIndex; + unsigned long keyIndex; + ItableEntry *entry; + ItableItem* item; + + entryIndex = iTableGetEntryIndex(it, key->keyStr, &keyIndex); + + entry = &(it->entries[entryIndex]); + iTableUpdateArraySize(entry); + + /* add a new item at the end of the item array without duplicating memory. */ + item = &(entry->items[entry->nextItemIndex]); + item->itemType = itemType; + item->key.keyIndex = keyIndex; + item->key.keyStr = key->keyStr; + item->value = value; + + entry->nextItemIndex++; + it->numberOfEntries++; +} + +static unsigned int iTableResize(Itable *it) +{ + unsigned int newSizeIndex, + entryIndex, + i; + Itable *newTable; + ItableEntry *entry; + ItableItem *item; + + /* check if we do not need to resize the hash table */ + if (it->numberOfEntries == 0 || + it->tableSizeIndex >= itable_maxTableSizeIndex || + it->size / it->numberOfEntries >= itable_resizeLimit) + return 0; + + /* create a new hash table and copy the contents of + * the current table into the new one + */ + newSizeIndex = it->tableSizeIndex + 1; + newTable = iupTableCreateSized(it->indexType, newSizeIndex); + + for (entryIndex = 0; entryIndex < it->size; entryIndex++) + { + entry = &(it->entries[entryIndex]); + + if (entry->items) + { + item = &(entry->items[0]); + + for (i = 0; i < entry->nextItemIndex; i++, item++) + { + iTableAdd(newTable, &(item->key), item->value, item->itemType); + } + + free(entry->items); + } + } + + free(it->entries); + + it->size = newTable->size; + it->tableSizeIndex = newTable->tableSizeIndex; + it->numberOfEntries = newTable->numberOfEntries; + it->entries = newTable->entries; + + free(newTable); + + return 1; +} + +#ifdef DEBUGTABLE +static void iTableShowStatistics(Itable *it) +{ + unsigned int nofSlots = 0; + unsigned int nofKeys = 0; + double optimalNofKeysPerSlot = 0.0; + unsigned int nofSlotsWithMoreKeys = 0; + unsigned int nofSlotsWithLessKeys = 0; + + unsigned int entryIndex; + fprintf(stderr, "\n--- HASH TABLE STATISTICS ---\n"); + if (!it) + { + fprintf(stderr, "no hash table...\n"); + return; + } + + nofSlots = it->size; + nofKeys = it->numberOfEntries; + optimalNofKeysPerSlot = (double)nofKeys / (double)nofSlots; + + for (entryIndex = 0; entryIndex < it->size; entryIndex++) + { + ItableEntry *entry = &(it->entries[entryIndex]); + + if (entry->nextItemIndex > optimalNofKeysPerSlot + 3) + nofSlotsWithMoreKeys++; + else if (entry->nextItemIndex < optimalNofKeysPerSlot - 3) + nofSlotsWithLessKeys++; + } + + fprintf(stderr, "Number of slots: %d\n", nofSlots); + fprintf(stderr, "Number of keys: %d\n", nofKeys); + fprintf(stderr, "Optimal number of keys per slot: %f\n", optimalNofKeysPerSlot); + fprintf(stderr, "Number of slots with much more keys: %d\n", nofSlotsWithMoreKeys); + fprintf(stderr, "Number of slots with far less keys: %d\n", nofSlotsWithLessKeys); + fprintf(stderr, "\n"); +} +#endif diff --git a/iup/src/iup_table.h b/iup/src/iup_table.h new file mode 100755 index 0000000..5222160 --- /dev/null +++ b/iup/src/iup_table.h @@ -0,0 +1,143 @@ +/** \file + * \brief Simple hash table C API. + * Does not allow 0 values for items... + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_TABLE_H +#define __IUP_TABLE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** \defgroup table Hash Table + * \par + * The hash table can be indexed by strings or pointer address, + * and each value can contain strings, pointers or function pointers. + * \par + * See \ref iup_table.h + * \ingroup util */ + + +/** How the table key is interpreted. + * \ingroup table */ +typedef enum _Itable_IndexTypes +{ + IUPTABLE_POINTERINDEXED = 10, /**< a pointer address is used as key. */ + IUPTABLE_STRINGINDEXED /**< a string as key */ +} Itable_IndexTypes; + +/** How the value is interpreted. + * \ingroup table */ +typedef enum _Itable_Types +{ + IUPTABLE_POINTER, /**< regular pointer for strings and other pointers */ + IUPTABLE_STRING, /**< string duplicated internally */ + IUPTABLE_FUNCPOINTER /**< function pointer */ +} Itable_Types; + + +typedef void (*Ifunc)(void); + +struct Itable; +typedef struct Itable Itable; + + +/** Creates a hash table with an initial default size. + * This function is equivalent to iupTableCreateSized(0); + * \ingroup table */ +Itable *iupTableCreate(Itable_IndexTypes indexType); + +/** Creates a hash table with the specified initial size. + * Use this function if you expect the table to become very large. + * initialSizeIndex is an array into the (internal) list of + * possible hash table sizes. Currently only indexes from 0 to 8 + * are supported. If you specify a higher value here, the maximum + * allowed value will be used. + * \ingroup table */ +Itable *iupTableCreateSized(Itable_IndexTypes indexType, unsigned int initialSizeIndex); + +/** Destroys the Itable. + * Calls \ref iupTableClear. + * \ingroup table */ +void iupTableDestroy(Itable *n); + +/** Removes all items in the table. + * This function does also free the memory of strings contained in the table!!!! + * \ingroup table */ +void iupTableClear(Itable *it); + +/** Returns the number of keys stored in the table. + * \ingroup table */ +int iupTableCount(Itable *it); + +/** Store an element in the table. + * \ingroup table */ +void iupTableSet(Itable *n, const char *key, void *value, Itable_Types itemType); + +/** Store a function pointer in the table. + * Type is set to IUPTABLE_FUNCPOINTER. + * \ingroup table */ +void iupTableSetFunc(Itable *n, const char *key, Ifunc func); + +/** Retrieves an element from the table. + * Returns NULL if not found. + * \ingroup table */ +void *iupTableGet(Itable *n, const char *key); + +/** Retrieves a function pointer from the table. + * If not a function or not found returns NULL. + * value always contains the element pointer. + * \ingroup table */ +Ifunc iupTableGetFunc(Itable *n, const char *key, void **value); + +/** Retrieves an element from the table and its type. + * \ingroup table */ +void *iupTableGetTyped(Itable *n, const char *key, Itable_Types *itemType); + +/** Removes the entry at the specified key from the + * hash table and frees the memory used by it if + * it is a string... + * \ingroup table */ +void iupTableRemove(Itable *n, const char *key); + +/** Key iteration function. Returns a key. + * To iterate over all keys call iupTableFirst at the first + * and call iupTableNext in a loop + * until 0 is returned... + * Do NOT change the content of the hash table during iteration. + * During an iteration you can use context with + * iupTableGetCurr() to access the value of the key + * very fast. + * \ingroup table */ +char *iupTableFirst(Itable *it); + +/** Key iteration function. See \ref iupTableNext. + * \ingroup table */ +char *iupTableNext(Itable *it); + +/** Returns the value at the current position. + * The current context is an iterator + * that is filled by iupTableNext(). + * iupTableGetCur() is faster then iupTableGet(), + * so when you want to access an item stored + * at a key returned by iupTableNext(), + * use this function instead of iupTableGet(). + * \ingroup table */ +void *iupTableGetCurr(Itable *it); + +/** Removes the current element and returns the next key. + * Use this function to remove an element during an iteration. + * \ingroup table */ +char *iupTableRemoveCurr(Itable *it); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/iup/src/iup_tabs.c b/iup/src/iup_tabs.c new file mode 100755 index 0000000..77b2cf5 --- /dev/null +++ b/iup/src/iup_tabs.c @@ -0,0 +1,471 @@ +/** \file +* \brief iuptabs control +* +* See Copyright Notice in "iup.h" +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <math.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" +#include "iup_image.h" +#include "iup_tabs.h" + + + +char* iupTabsGetPaddingAttrib(Ihandle* ih) +{ + char *str = iupStrGetMemory(50); + sprintf(str, "%dx%d", ih->data->horiz_padding, ih->data->vert_padding); + return str; +} + +char* iupTabsAttribGetStrId(Ihandle* ih, const char* name, int pos) +{ + char str[50]; + sprintf(str, "%s%d", name, pos); + return iupAttribGet(ih, str); +} + +static int iTabsGetMaxWidth(Ihandle* ih) +{ + int max_width = 0, width, pos; + char *tabtitle, *tabimage; + Ihandle* child; + + for (pos = 0, child = ih->firstchild; child; child = child->brother, pos++) + { + tabtitle = iupAttribGet(child, "TABTITLE"); + if (!tabtitle) tabtitle = iupTabsAttribGetStrId(ih, "TABTITLE", pos); + tabimage = iupAttribGet(child, "TABIMAGE"); + if (!tabimage) tabimage = iupTabsAttribGetStrId(ih, "TABIMAGE", pos); + if (!tabtitle && !tabimage) + tabtitle = " "; + + width = 0; + if (tabtitle) + width += iupdrvFontGetStringWidth(ih, tabtitle); + + if (tabimage) + { + void* img = iupImageGetImage(tabimage, ih, 0); + if (img) + { + int w; + iupdrvImageGetInfo(img, &w, NULL, NULL); + width += w; + } + } + + if (width > max_width) max_width = width; + } + + return max_width; +} + +static int iTabsGetMaxHeight(Ihandle* ih) +{ + int max_height = 0, h, pos; + char *tabimage; + Ihandle* child; + + for (pos = 0, child = ih->firstchild; child; child = child->brother, pos++) + { + tabimage = iupAttribGet(child, "TABIMAGE"); + if (!tabimage) tabimage = iupTabsAttribGetStrId(ih, "TABIMAGE", pos); + + if (tabimage) + { + void* img = iupImageGetImage(tabimage, ih, 0); + if (img) + { + iupdrvImageGetInfo(img, NULL, &h, NULL); + if (h > max_height) max_height = h; + } + } + } + + iupdrvFontGetCharSize(ih, NULL, &h); + if (h > max_height) max_height = h; + + return max_height; +} + +static void iTabsGetDecorSize(Ihandle* ih, int *width, int *height) +{ + if (ih->data->type == ITABS_LEFT || ih->data->type == ITABS_RIGHT) + { + if (ih->data->orientation == ITABS_HORIZONTAL) + { + int max_width = iTabsGetMaxWidth(ih); + *width = 4 + (3 + max_width + 3) + 2 + 4; + *height = 4 + 4; + + if (iupdrvTabsExtraDecor(ih)) + { + int h; + iupdrvFontGetCharSize(ih, NULL, &h); + *height += h + 4; + } + } + else + { + int max_height = iTabsGetMaxHeight(ih); + *width = 4 + (3 + max_height + 3) + 2 + 4; + *height = 4 + 4; + + if (ih->handle && ih->data->is_multiline) + { + int num_lin = iupdrvTabsGetLineCountAttrib(ih); + *width += (num_lin-1)*(3 + max_height + 3 + 1); + } + } + } + else /* "BOTTOM" or "TOP" */ + { + if (ih->data->orientation == ITABS_HORIZONTAL) + { + int max_height = iTabsGetMaxHeight(ih); + *width = 4 + 4; + *height = 4 + (3 + max_height + 3) + 2 + 4; + + if (ih->handle && ih->data->is_multiline) + { + int num_lin = iupdrvTabsGetLineCountAttrib(ih); + *height += (num_lin-1)*(3 + max_height + 3 + 1); + } + + if (iupdrvTabsExtraDecor(ih)) + { + int h; + iupdrvFontGetCharSize(ih, NULL, &h); + *width += h + 4; + } + } + else + { + int max_width = iTabsGetMaxWidth(ih); + *width = 4 + 4; + *height = 4 + (3 + max_width + 3) + 2 + 4; + } + } + + *width += ih->data->horiz_padding; + *height += ih->data->vert_padding; +} + + +/* ------------------------------------------------------------------------- */ +/* TABS - Sets and Gets - Accessors */ +/* ------------------------------------------------------------------------- */ + +static int iTabsSetValueHandleAttrib(Ihandle* ih, const char* value) +{ + int pos; + Ihandle *child; + + child = (Ihandle*)value; + if (!iupObjectCheck(child)) + return 0; + + pos = IupGetChildPos(ih, child); + if (pos != -1) /* found child */ + { + if (ih->handle) + iupdrvTabsSetCurrentTab(ih, pos); + else + iupAttribSetStr(ih, "_IUPTABS_VALUE_HANDLE", (char*)child); + } + + return 0; +} + +char* iupTabsGetTabTypeAttrib(Ihandle* ih) +{ + switch(ih->data->type) + { + case ITABS_BOTTOM: + return "BOTTOM"; + case ITABS_LEFT: + return "LEFT"; + case ITABS_RIGHT: + return "RIGHT"; + default: + return "TOP"; + } +} + +char* iupTabsGetTabOrientationAttrib(Ihandle* ih) +{ + if (ih->data->orientation == ITABS_HORIZONTAL) + return "HORIZONTAL"; + else + return "VERTICAL"; +} + +static char* iTabsGetValueHandleAttrib(Ihandle* ih) +{ + if (ih->handle) + { + int pos = iupdrvTabsGetCurrentTab(ih); + return (char*)IupGetChild(ih, pos); + } + else + return iupAttribGet(ih, "_IUPTABS_VALUE_HANDLE"); +} + +static int iTabsSetValuePosAttrib(Ihandle* ih, const char* value) +{ + Ihandle* child; + int pos; + + if (!iupStrToInt(value, &pos)) + return 0; + + child = IupGetChild(ih, pos); + if (child) /* found child */ + { + if (ih->handle) + iupdrvTabsSetCurrentTab(ih, pos); + else + iupAttribSetStr(ih, "_IUPTABS_VALUE_HANDLE", (char*)child); + } + + return 0; +} + +static char* iTabsGetValuePosAttrib(Ihandle* ih) +{ + if (ih->handle) + { + int pos = iupdrvTabsGetCurrentTab(ih); + char *str = iupStrGetMemory(50); + sprintf(str, "%d", pos); + return str; + } + else + { + Ihandle* child = (Ihandle*)iupAttribGet(ih, "_IUPTABS_VALUE_HANDLE"); + int pos = IupGetChildPos(ih, child); + if (pos != -1) /* found child */ + { + char *str = iupStrGetMemory(50); + sprintf(str, "%d", pos); + return str; + } + } + + return NULL; +} + +static int iTabsSetValueAttrib(Ihandle* ih, const char* value) +{ + Ihandle *child; + + if (!value) + return 0; + + child = IupGetHandle(value); + if (!child) + return 0; + + iTabsSetValueHandleAttrib(ih, (char*)child); + + return 0; +} + +static char* iTabsGetValueAttrib(Ihandle* ih) +{ + Ihandle* child = (Ihandle*)iTabsGetValueHandleAttrib(ih); + return IupGetName(child); +} + +static char* iTabsGetClientSizeAttrib(Ihandle* ih) +{ + int width, height, decorwidth, decorheight; + char* str = iupStrGetMemory(20); + width = ih->currentwidth; + height = ih->currentheight; + iTabsGetDecorSize(ih, &decorwidth, &decorheight); + width -= decorwidth; + height -= decorheight; + if (width < 0) width = 0; + if (height < 0) height = 0; + sprintf(str, "%dx%d", width, height); + return str; +} + + +/* ------------------------------------------------------------------------- */ +/* TABS - Methods */ +/* ------------------------------------------------------------------------- */ + +static void iTabsComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + Ihandle* child; + int children_expand, + children_naturalwidth, children_naturalheight; + int decorwidth, decorheight; + + /* calculate total children natural size (even for hidden children) */ + children_expand = 0; + children_naturalwidth = 0; + children_naturalheight = 0; + + for (child = ih->firstchild; child; child = child->brother) + { + /* update child natural size first */ + iupBaseComputeNaturalSize(child); + + children_expand |= child->expand; + children_naturalwidth = iupMAX(children_naturalwidth, child->naturalwidth); + children_naturalheight = iupMAX(children_naturalheight, child->naturalheight); + } + + iTabsGetDecorSize(ih, &decorwidth, &decorheight); + + *expand = children_expand; + *w = children_naturalwidth + decorwidth; + *h = children_naturalheight + decorheight; +} + +static void iTabsSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink) +{ + Ihandle* child; + int width, height, decorwidth, decorheight; + + iTabsGetDecorSize(ih, &decorwidth, &decorheight); + + width = ih->currentwidth-decorwidth; + height = ih->currentheight-decorheight; + if (width < 0) width = 0; + if (height < 0) height = 0; + + for (child = ih->firstchild; child; child = child->brother) + { + iupBaseSetCurrentSize(child, width, height, shrink); + } +} + +static void iTabsSetChildrenPositionMethod(Ihandle* ih, int x, int y) +{ + /* IupTabs is the native parent of its children, + so the position is restarted at (0,0). + In all systems, each tab is a native window covering the client area. + Child coordinates are relative to client left-top corner of the tab page. */ + Ihandle* child; + (void)x; + (void)y; + for (child = ih->firstchild; child; child = child->brother) + { + iupBaseSetPosition(child, 0, 0); + } +} + +static void* iTabsGetInnerNativeContainerHandleMethod(Ihandle* ih, Ihandle* child) +{ + while (child && child->parent != ih) + child = child->parent; + if (child) + return iupAttribGet(child, "_IUPTAB_CONTAINER"); + else + return NULL; +} + +static int iTabsCreateMethod(Ihandle* ih, void **params) +{ + ih->data = iupALLOCCTRLDATA(); + + /* add children */ + if(params) + { + Ihandle** iparams = (Ihandle**)params; + while (*iparams) + { + IupAppend(ih, *iparams); + iparams++; + } + } + return IUP_NOERROR; +} + +Iclass* iupTabsGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "tabs"; + ic->format = "g"; /* array of Ihandle */ + ic->nativetype = IUP_TYPECONTROL; + ic->childtype = IUP_CHILDMANY; + ic->is_interactive = 1; + ic->has_attrib_id = 1; + + /* Class functions */ + ic->Create = iTabsCreateMethod; + ic->GetInnerNativeContainerHandle = iTabsGetInnerNativeContainerHandleMethod; + + ic->ComputeNaturalSize = iTabsComputeNaturalSizeMethod; + ic->SetChildrenCurrentSize = iTabsSetChildrenCurrentSizeMethod; + ic->SetChildrenPosition = iTabsSetChildrenPositionMethod; + + ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* IupTabs Callbacks */ + iupClassRegisterCallback(ic, "TABCHANGE_CB", "nn"); + + /* Common Callbacks */ + iupBaseRegisterCommonCallbacks(ic); + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Visual */ + iupBaseRegisterVisualAttrib(ic); + + /* IupTabs only */ + iupClassRegisterAttribute(ic, "VALUE", iTabsGetValueAttrib, iTabsSetValueAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUEPOS", iTabsGetValuePosAttrib, iTabsSetValuePosAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE_HANDLE", iTabsGetValueHandleAttrib, iTabsSetValueHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + + /* Base Container */ + iupClassRegisterAttribute(ic, "CLIENTSIZE", iTabsGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupdrvTabsInitClass(ic); + + return ic; +} + +Ihandle* IupTabs(Ihandle* first,...) +{ + Ihandle **params; + Ihandle *ih; + + va_list arglist; + va_start(arglist, first); + params = (Ihandle**)iupObjectGetParamList(first, arglist); + va_end(arglist); + + ih = IupCreatev("tabs", (void**)params); + free(params); + + return ih; +} + +Ihandle* IupTabsv(Ihandle** params) +{ + return IupCreatev("tabs", (void**)params); +} diff --git a/iup/src/iup_tabs.h b/iup/src/iup_tabs.h new file mode 100755 index 0000000..7f5df2e --- /dev/null +++ b/iup/src/iup_tabs.h @@ -0,0 +1,50 @@ +/** \file + * \brief Tabs Control + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_TABS_H +#define __IUP_TABS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +char* iupTabsGetTabOrientationAttrib(Ihandle* ih); +char* iupTabsGetTabTypeAttrib(Ihandle* ih); +char* iupTabsAttribGetStrId(Ihandle* ih, const char* name, int pos); +char* iupTabsGetPaddingAttrib(Ihandle* ih); + +int iupdrvTabsExtraDecor(Ihandle* ih); +int iupdrvTabsGetLineCountAttrib(Ihandle* ih); +void iupdrvTabsSetCurrentTab(Ihandle* ih, int pos); +int iupdrvTabsGetCurrentTab(Ihandle* ih); +void iupdrvTabsInitClass(Iclass* ic); + +typedef enum +{ + ITABS_TOP, ITABS_BOTTOM, ITABS_LEFT, ITABS_RIGHT +} ItabsType; + +typedef enum +{ + ITABS_HORIZONTAL, ITABS_VERTICAL +} ItabsOrientation; + +/* Control context */ +struct _IcontrolData +{ + ItabsType type; + ItabsOrientation orientation; + int horiz_padding, vert_padding; /* tab title margin */ + int is_multiline; /* used only in Windows */ +}; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_text.c b/iup/src/iup_text.c new file mode 100755 index 0000000..6cd7235 --- /dev/null +++ b/iup/src/iup_text.c @@ -0,0 +1,513 @@ +/** \file + * \brief Text Control. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" +#include "iup_mask.h" +#include "iup_array.h" +#include "iup_text.h" +#include "iup_assert.h" + + +char* iupTextGetFormattingAttrib(Ihandle* ih) +{ + if (ih->data->has_formatting) + return "YES"; + else + return "NO"; +} + +int iupTextSetFormattingAttrib(Ihandle* ih, const char* value) +{ + if (ih->handle) /* only before map */ + return 0; + + ih->data->has_formatting = iupStrBoolean(value); + + return 0; +} + +static void iTextDestroyFormatTags(Ihandle* ih) +{ + /* called if the element was destroyed before it was mapped */ + int i, count = iupArrayCount(ih->data->formattags); + Ihandle** tag_array = (Ihandle**)iupArrayGetData(ih->data->formattags); + for (i = 0; i < count; i++) + IupDestroy(tag_array[i]); + iupArrayDestroy(ih->data->formattags); + ih->data->formattags = NULL; +} + +static void iTextUpdateValueAttrib(Ihandle* ih) +{ + char* value = iupAttribGet(ih, "VALUE"); + if (value) + { + int inherit; + iupClassObjectSetAttribute(ih, "VALUE", value, &inherit); + + iupAttribSetStr(ih, "VALUE", NULL); /* clear hash table */ + } +} + +char* iupTextGetNCAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(100); + sprintf(str, "%d", ih->data->nc); + return str; +} + +void iupTextUpdateFormatTags(Ihandle* ih) +{ + /* called when the element is mapped */ + int i, count = iupArrayCount(ih->data->formattags); + Ihandle** tag_array = (Ihandle**)iupArrayGetData(ih->data->formattags); + + /* must update VALUE before updating the format */ + iTextUpdateValueAttrib(ih); + + for (i = 0; i < count; i++) + { + iupdrvTextAddFormatTag(ih, tag_array[i]); + IupDestroy(tag_array[i]); + } + iupArrayDestroy(ih->data->formattags); + ih->data->formattags = NULL; +} + +int iupTextSetAddFormatTagHandleAttrib(Ihandle* ih, const char* value) +{ + Ihandle* formattag = (Ihandle*)value; + if (!iupObjectCheck(formattag)) + return 0; + + if (ih->handle) + { + /* must update VALUE before updating the format */ + iTextUpdateValueAttrib(ih); + + iupdrvTextAddFormatTag(ih, formattag); + IupDestroy(formattag); + } + else + { + Ihandle** tag_array; + int i; + + if (!ih->data->formattags) + ih->data->formattags = iupArrayCreate(10, sizeof(Ihandle*)); + + i = iupArrayCount(ih->data->formattags); + tag_array = (Ihandle**)iupArrayInc(ih->data->formattags); + tag_array[i] = formattag; + } + return 0; +} + +int iupTextSetAddFormatTagAttrib(Ihandle* ih, const char* value) +{ + return iupTextSetAddFormatTagHandleAttrib(ih, (char*)IupGetHandle(value)); +} + +static char* iTextGetMaskDataAttrib(Ihandle* ih) +{ + /* Used only by the OLD iupmask API */ + return (char*)ih->data->mask; +} + +static char* iTextGetMaskAttrib(Ihandle* ih) +{ + if (ih->data->mask) + return iupMaskGetStr(ih->data->mask); + else + return NULL; +} + +static int iTextSetMaskAttrib(Ihandle* ih, const char* value) +{ + if (!value) + { + if (ih->data->mask) + { + iupMaskDestroy(ih->data->mask); + ih->data->mask = NULL; + } + } + else + { + int casei = iupAttribGetInt(ih, "MASKCASEI"); + Imask* mask = iupMaskCreate(value,casei); + if (mask) + { + if (ih->data->mask) + iupMaskDestroy(ih->data->mask); + + ih->data->mask = mask; + return 0; + } + } + + return 0; +} + +static int iTextSetMaskIntAttrib(Ihandle* ih, const char* value) +{ + if (!value) + { + if (ih->data->mask) + { + iupMaskDestroy(ih->data->mask); + ih->data->mask = NULL; + } + } + else + { + Imask* mask; + int min, max; + + if (iupStrToIntInt(value, &min, &max, ':')!=2) + return 0; + + mask = iupMaskCreateInt(min,max); + + if (ih->data->mask) + iupMaskDestroy(ih->data->mask); + + ih->data->mask = mask; + } + + return 0; +} + +static int iTextSetMaskFloatAttrib(Ihandle* ih, const char* value) +{ + if (!value) + { + if (ih->data->mask) + { + iupMaskDestroy(ih->data->mask); + ih->data->mask = NULL; + } + } + else + { + Imask* mask; + float min, max; + + if (iupStrToFloatFloat(value, &min, &max, ':')!=2) + return 0; + + mask = iupMaskCreateFloat(min,max); + + if (ih->data->mask) + iupMaskDestroy(ih->data->mask); + + ih->data->mask = mask; + } + + return 0; +} + +static int iTextSetMultilineAttrib(Ihandle* ih, const char* value) +{ + /* valid only before map */ + if (ih->handle) + return 0; + + if (iupStrBoolean(value)) + { + ih->data->is_multiline = 1; + ih->data->sb = IUP_SB_HORIZ | IUP_SB_VERT; /* reset SCROLLBAR to YES */ + } + else + ih->data->is_multiline = 0; + + return 0; +} + +static char* iTextGetMultilineAttrib(Ihandle* ih) +{ + if (ih->data->is_multiline) + return "YES"; + else + return "NO"; +} + +static int iTextSetAppendNewlineAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + ih->data->append_newline = 1; + else + ih->data->append_newline = 0; + return 0; +} + +static char* iTextGetAppendNewlineAttrib(Ihandle* ih) +{ + if (ih->data->append_newline) + return "YES"; + else + return "NO"; +} + +static int iTextSetScrollbarAttrib(Ihandle* ih, const char* value) +{ + /* valid only before map */ + if (ih->handle || !ih->data->is_multiline) + return 0; + + if (!value) + value = "YES"; /* default, if multiline, is YES */ + + if (iupStrEqualNoCase(value, "YES")) + ih->data->sb = IUP_SB_HORIZ | IUP_SB_VERT; + else if (iupStrEqualNoCase(value, "HORIZONTAL")) + ih->data->sb = IUP_SB_HORIZ; + else if (iupStrEqualNoCase(value, "VERTICAL")) + ih->data->sb = IUP_SB_VERT; + else + ih->data->sb = IUP_SB_NONE; + + return 0; +} + +static char* iTextGetScrollbarAttrib(Ihandle* ih) +{ + if (ih->data->sb == (IUP_SB_HORIZ | IUP_SB_VERT)) + return "YES"; + if (ih->data->sb &= IUP_SB_HORIZ) + return "HORIZONTAL"; + if (ih->data->sb == IUP_SB_VERT) + return "VERTICAL"; + return "NO"; /* IUP_SB_NONE */ +} + +char* iupTextGetPaddingAttrib(Ihandle* ih) +{ + char *str = iupStrGetMemory(50); + sprintf(str, "%dx%d", ih->data->horiz_padding, ih->data->vert_padding); + return str; +} + + +/********************************************************************/ + + +static int iTextCreateMethod(Ihandle* ih, void** params) +{ + if (params) + { + if (params[0]) iupAttribStoreStr(ih, "ACTION", (char*)(params[0])); + } + ih->data = iupALLOCCTRLDATA(); + ih->data->append_newline = 1; + return IUP_NOERROR; +} + +static int iMultilineCreateMethod(Ihandle* ih, void** params) +{ + iTextCreateMethod(ih, params); + ih->data->is_multiline = 1; + ih->data->sb = IUP_SB_HORIZ | IUP_SB_VERT; + return IUP_NOERROR; +} + +static void iTextComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + int natural_w = 0, + natural_h = 0, + visiblecolumns = iupAttribGetInt(ih, "VISIBLECOLUMNS"), + visiblelines = iupAttribGetInt(ih, "VISIBLELINES"); + (void)expand; /* unset if not a container */ + + /* Since the contents can be changed by the user, the size can not be dependent on it. */ + if (ih->data->is_multiline) + { + iupdrvFontGetCharSize(ih, NULL, &natural_h); /* one line height */ + natural_w = iupdrvFontGetStringWidth(ih, "WWWWWWWWWW"); + natural_w = (visiblecolumns*natural_w)/10; + natural_h = visiblelines*natural_h; + } + else + { + iupdrvFontGetCharSize(ih, NULL, &natural_h); /* one line height */ + natural_w = iupdrvFontGetStringWidth(ih, "WWWWWWWWWW"); + natural_w = (visiblecolumns*natural_w)/10; + } + + /* compute the borders space */ + if (iupAttribGetBoolean(ih, "BORDER")) + iupdrvTextAddBorders(&natural_w, &natural_h); + + if (iupAttribGetBoolean(ih, "SPIN")) + iupdrvTextAddSpin(&natural_w, natural_h); + + natural_w += 2*ih->data->horiz_padding; + natural_h += 2*ih->data->vert_padding; + + /* add scrollbar */ + if (ih->data->is_multiline && ih->data->sb) + { + int sb_size = iupdrvGetScrollbarSize(); + if (ih->data->sb & IUP_SB_HORIZ) + natural_w += sb_size; + if (ih->data->sb & IUP_SB_VERT) + natural_h += sb_size; + } + + *w = natural_w; + *h = natural_h; +} + +static void iTextDestroyMethod(Ihandle* ih) +{ + if (ih->data->formattags) + iTextDestroyFormatTags(ih); + if (ih->data->mask) + iupMaskDestroy(ih->data->mask); +} + + +/******************************************************************************/ + + +void IupTextConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + if (!ih->handle) + return; + + if (iupStrEqual(ih->iclass->name, "text") || + iupStrEqual(ih->iclass->name, "multiline")) + { + if (ih->data->is_multiline) + iupdrvTextConvertLinColToPos(ih, lin, col, pos); + else + *pos = col - 1; /* IUP starts at 1 */ + } +} + +void IupTextConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + if (!ih->handle) + return; + + if (iupStrEqual(ih->iclass->name, "text") || + iupStrEqual(ih->iclass->name, "multiline")) + { + if (ih->data->is_multiline) + iupdrvTextConvertPosToLinCol(ih, pos, lin, col); + else + { + *col = pos + 1; /* IUP starts at 1 */ + *lin = 1; + } + } +} + +Ihandle* IupText(const char* action) +{ + void *params[2]; + params[0] = (void*)action; + params[1] = NULL; + return IupCreatev("text", params); +} + +Ihandle* IupMultiLine(const char* action) +{ + void *params[2]; + params[0] = (void*)action; + params[1] = NULL; + return IupCreatev("multiline", params); +} + +Iclass* iupTextGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "text"; + ic->format = "A"; /* one optional callback name */ + ic->nativetype = IUP_TYPECONTROL; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + + /* Class functions */ + ic->Create = iTextCreateMethod; + ic->Destroy = iTextDestroyMethod; + ic->ComputeNaturalSize = iTextComputeNaturalSizeMethod; + ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Callbacks */ + iupClassRegisterCallback(ic, "CARET_CB", "iii"); + iupClassRegisterCallback(ic, "ACTION", "is"); + iupClassRegisterCallback(ic, "DROPFILES_CB", "siii"); + iupClassRegisterCallback(ic, "BUTTON_CB", "iiiis"); + iupClassRegisterCallback(ic, "MOTION_CB", "iis"); + iupClassRegisterCallback(ic, "SPIN_CB", "i"); + iupClassRegisterCallback(ic, "VALUECHANGED_CB", ""); + + + /* Common Callbacks */ + iupBaseRegisterCommonCallbacks(ic); + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Visual */ + iupBaseRegisterVisualAttrib(ic); + + /* IupText only */ + iupClassRegisterAttribute(ic, "SCROLLBAR", iTextGetScrollbarAttrib, iTextSetScrollbarAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MULTILINE", iTextGetMultilineAttrib, iTextSetMultilineAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "APPENDNEWLINE", iTextGetAppendNewlineAttrib, iTextSetAppendNewlineAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "MASKCASEI", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MASK", iTextGetMaskAttrib, iTextSetMaskAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MASKINT", NULL, iTextSetMaskIntAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MASKFLOAT", NULL, iTextSetMaskFloatAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "OLD_MASK_DATA", iTextGetMaskDataAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "BORDER", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPIN", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINALIGN", NULL, NULL, IUPAF_SAMEASSYSTEM, "RIGHT", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINAUTO", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINWRAP", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VISIBLECOLUMNS", NULL, NULL, IUPAF_SAMEASSYSTEM, "5", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VISIBLELINES", NULL, NULL, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "WORDWRAP", NULL, NULL, NULL, NULL, IUPAF_DEFAULT); + + iupdrvTextInitClass(ic); + + return ic; +} + +Iclass* iupMultilineGetClass(void) +{ + Iclass* ic = iupTextGetClass(); + ic->Create = iMultilineCreateMethod; + ic->name = "multiline"; /* register the multiline name, so LED will work */ + return ic; +} diff --git a/iup/src/iup_text.h b/iup/src/iup_text.h new file mode 100755 index 0000000..e018961 --- /dev/null +++ b/iup/src/iup_text.h @@ -0,0 +1,48 @@ +/** \file + * \brief Text Controls Private Declarations + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_TEXT_H +#define __IUP_TEXT_H + +#ifdef __cplusplus +extern "C" { +#endif + + +void iupdrvTextInitClass(Iclass* ic); +void iupdrvTextAddBorders(int *w, int *h); +void iupdrvTextAddSpin(int *w, int h); +void iupdrvTextAddFormatTag(Ihandle* ih, Ihandle* formattag); +void iupdrvTextConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos); +void iupdrvTextConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col); + +void iupTextUpdateFormatTags(Ihandle* ih); +char* iupTextGetPaddingAttrib(Ihandle* ih); +char* iupTextGetNCAttrib(Ihandle* ih); +int iupTextSetFormattingAttrib(Ihandle* ih, const char* value); +char* iupTextGetFormattingAttrib(Ihandle* ih); +int iupTextSetAddFormatTagAttrib(Ihandle* ih, const char* value); +int iupTextSetAddFormatTagHandleAttrib(Ihandle* ih, const char* value); + +struct _IcontrolData +{ + int is_multiline, + has_formatting, + append_newline, + nc, + sb, /* scrollbar configuration, can be changed only before map */ + horiz_padding, vert_padding, /* button margin */ + last_caret_pos; + Iarray* formattags; + Imask* mask; +}; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_timer.c b/iup/src/iup_timer.c new file mode 100755 index 0000000..9a003b4 --- /dev/null +++ b/iup/src/iup_timer.c @@ -0,0 +1,80 @@ +/** \file + * \brief Timer Control. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_str.h" +#include "iup_stdcontrols.h" +#include "iup_timer.h" + + +static int iTimerSetRunAttrib(Ihandle *ih, const char *value) +{ + if (iupStrBoolean(value)) + iupdrvTimerRun(ih); + else + iupdrvTimerStop(ih); + + return 0; +} + +static char* iTimerGetRunAttrib(Ihandle *ih) +{ + if (ih->serial > 0) + return "YES"; + else + return "NO"; +} + +static char* iTimerGetWidAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(50); + sprintf(str, "%d", ih->serial); + return str; +} + +static void iTimerDestroyMethod(Ihandle* ih) +{ + iupdrvTimerStop(ih); +} + +/******************************************************************************/ + +Ihandle* IupTimer(void) +{ + return IupCreate("timer"); +} + +Iclass* iupTimerGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "timer"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPECONTROL; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 0; + + /* Class functions */ + ic->Destroy = iTimerDestroyMethod; + + /* Callbacks */ + iupClassRegisterCallback(ic, "ACTION_CB", ""); + + /* Attribute functions */ + iupClassRegisterAttribute(ic, "WID", iTimerGetWidAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "RUN", iTimerGetRunAttrib, iTimerSetRunAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TIME", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupdrvTimerInitClass(ic); + + return ic; +} diff --git a/iup/src/iup_timer.h b/iup/src/iup_timer.h new file mode 100755 index 0000000..8a61f5f --- /dev/null +++ b/iup/src/iup_timer.h @@ -0,0 +1,24 @@ +/** \file + * \brief Timer Resource Private Declarations + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_TIMER_H +#define __IUP_TIMER_H + +#ifdef __cplusplus +extern "C" { +#endif + + +void iupdrvTimerStop(Ihandle* ih); +void iupdrvTimerRun(Ihandle* ih); +void iupdrvTimerInitClass(Iclass* ic); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_toggle.c b/iup/src/iup_toggle.c new file mode 100755 index 0000000..9a09f52 --- /dev/null +++ b/iup/src/iup_toggle.c @@ -0,0 +1,140 @@ +/** \file + * \brief Toggle Control. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" +#include "iup_toggle.h" +#include "iup_image.h" + + +static char* iToggleGetRadioAttrib(Ihandle* ih) +{ + if (ih->data->radio) + return "YES"; + else + return "NO"; +} + +char* iupToggleGetPaddingAttrib(Ihandle* ih) +{ + char *str = iupStrGetMemory(50); + sprintf(str, "%dx%d", ih->data->horiz_padding, ih->data->vert_padding); + return str; +} + +static int iToggleCreateMethod(Ihandle* ih, void** params) +{ + if (params) + { + if (params[0]) iupAttribStoreStr(ih, "TITLE", (char*)(params[0])); + if (params[1]) iupAttribStoreStr(ih, "ACTION", (char*)(params[1])); + } + ih->data = iupALLOCCTRLDATA(); + return IUP_NOERROR; +} + +static void iToggleComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + int natural_w = 0, + natural_h = 0, + type = ih->data->type; + (void)expand; /* unset if not a container */ + + if (!ih->handle) + { + /* if not mapped must initialize the internal values */ + char* value = iupAttribGet(ih, "IMAGE"); + if (value) + type = IUP_TOGGLE_IMAGE; + else + type = IUP_TOGGLE_TEXT; + } + + if (type == IUP_TOGGLE_IMAGE) + { + iupImageGetInfo(iupAttribGet(ih, "IMAGE"), &natural_w, &natural_h, NULL); + + /* even when IMPRESS is set, must compute the borders space */ + iupdrvButtonAddBorders(&natural_w, &natural_h); + + natural_w += 2*ih->data->horiz_padding; + natural_h += 2*ih->data->vert_padding; + } + else /* IUP_TOGGLE_TEXT */ + { + /* must use IupGetAttribute to check from the native implementation */ + char* title = IupGetAttribute(ih, "TITLE"); + char* str = iupStrProcessMnemonic(title, NULL, 0); /* remove & */ + iupdrvFontGetMultiLineStringSize(ih, str, &natural_w, &natural_h); + if (str && str!=title) free(str); + + iupdrvToggleAddCheckBox(&natural_w, &natural_h); + } + + *w = natural_w; + *h = natural_h; +} + + +/******************************************************************************/ + + +Ihandle* IupToggle(const char* title, const char* action) +{ + void *params[3]; + params[0] = (void*)title; + params[1] = (void*)action; + params[2] = NULL; + return IupCreatev("toggle", params); +} + +Iclass* iupToggleGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "toggle"; + ic->format = "SA"; /* one optional string and one optional callback name */ + ic->nativetype = IUP_TYPECONTROL; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + + /* Class functions */ + ic->Create = iToggleCreateMethod; + ic->ComputeNaturalSize = iToggleComputeNaturalSizeMethod; + ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Callbacks */ + iupClassRegisterCallback(ic, "ACTION", "i"); + iupClassRegisterCallback(ic, "VALUECHANGED_CB", ""); + + /* Common Callbacks */ + iupBaseRegisterCommonCallbacks(ic); + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Visual */ + iupBaseRegisterVisualAttrib(ic); + + iupClassRegisterAttribute(ic, "RADIO", iToggleGetRadioAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "3STATE", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + + iupdrvToggleInitClass(ic); + + return ic; +} diff --git a/iup/src/iup_toggle.h b/iup/src/iup_toggle.h new file mode 100755 index 0000000..08e14b0 --- /dev/null +++ b/iup/src/iup_toggle.h @@ -0,0 +1,37 @@ +/** \file + * \brief Toggle Controls Private Declarations + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_TOGGLE_H +#define __IUP_TOGGLE_H + +#ifdef __cplusplus +extern "C" { +#endif + + +void iupdrvButtonAddBorders(int *x, int *y); /* reuse button borders */ + +void iupdrvToggleInitClass(Iclass* ic); +void iupdrvToggleAddCheckBox(int *x, int *y); + +Ihandle *iupRadioFindToggleParent(Ihandle* ih_toggle); +char* iupToggleGetPaddingAttrib(Ihandle* ih); + +enum {IUP_TOGGLE_IMAGE, IUP_TOGGLE_TEXT}; + +struct _IcontrolData +{ + int type, /* the 2 toggle possibilities */ + radio, + horiz_padding, vert_padding; /* toggle margin for images */ +}; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_tree.c b/iup/src/iup_tree.c new file mode 100755 index 0000000..c06e573 --- /dev/null +++ b/iup/src/iup_tree.c @@ -0,0 +1,499 @@ +/** \file + * \brief Tree control + * + * See Copyright Notice in iup.h + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" +#include "iup_tree.h" +#include "iup_assert.h" + + +#define ITREE_IMG_WIDTH 16 +#define ITREE_IMG_HEIGHT 16 + +static void iTreeInitializeImages(void) +{ + Ihandle *image_leaf, *image_blank, *image_paper; + Ihandle *image_collapsed, *image_expanded; + + unsigned char img_leaf[ITREE_IMG_WIDTH*ITREE_IMG_HEIGHT] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 4, 4, 5, 5, 5, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 5, 5, 1, 6, 1, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 4, 4, 5, 5, 1, 6, 1, 5, 0, 0, 0, 0, + 0, 0, 0, 3, 4, 4, 4, 5, 5, 1, 1, 5, 0, 0, 0, 0, + 0, 0, 0, 2, 3, 4, 4, 4, 5, 5, 5, 4, 0, 0, 0, 0, + 0, 0, 0, 2, 3, 3, 4, 4, 4, 5, 4, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 3, 3, 4, 4, 4, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + unsigned char img_collapsed[ITREE_IMG_WIDTH*ITREE_IMG_HEIGHT] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 2, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 6, 5, 5, 7, 7, 2, 3, 0, 0, 0, 0, 0, 0, 0, + 2, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 0, 0, + 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 4, 3, 0, + 2, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 4, 3, 0, + 2, 5, 7, 7, 7, 7, 7, 7, 7, 1, 7, 1, 7, 4, 3, 0, + 2, 5, 7, 7, 7, 7, 7, 7, 7, 7, 1, 7, 1, 4, 3, 0, + 2, 5, 7, 7, 7, 7, 7, 1, 7, 1, 7, 1, 7, 4, 3, 0, + 2, 5, 7, 7, 7, 7, 7, 7, 1, 7, 1, 7, 1, 4, 3, 0, + 2, 5, 7, 7, 7, 1, 7, 1, 7, 1, 7, 1, 1, 4, 3, 0, + 2, 5, 1, 7, 1, 7, 1, 7, 1, 7, 1, 1, 1, 4, 3, 0, + 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + unsigned char img_expanded[ITREE_IMG_WIDTH*ITREE_IMG_HEIGHT] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 1, 3, 3, 3, 3, 3, 1, 2, 2, 2, 2, 2, 2, 0, + 0, 2, 1, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 6, 4, + 0, 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 3, 6, 4, + 2, 1, 3, 3, 3, 3, 3, 3, 5, 3, 5, 6, 4, 6, 6, 4, + 2, 1, 3, 3, 3, 3, 5, 3, 3, 5, 3, 6, 4, 6, 6, 4, + 0, 2, 0, 3, 3, 3, 3, 3, 5, 3, 5, 5, 2, 4, 2, 4, + 0, 2, 0, 3, 3, 5, 3, 5, 3, 5, 5, 5, 6, 4, 2, 4, + 0, 0, 2, 0, 5, 3, 5, 3, 5, 5, 5, 5, 6, 2, 4, 4, + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, + 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + unsigned char img_blank[ITREE_IMG_WIDTH*ITREE_IMG_HEIGHT] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 0, 0, 0, 0, + 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 5, 4, 0, 0, 0, + 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 4, 0, 0, + 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 0, + 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0, + 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0, + 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0, + 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0, + 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0, + 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0, + 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0, + 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0, + 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0, + 0, 0, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 0, + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0 + }; + + unsigned char img_paper[ITREE_IMG_WIDTH*ITREE_IMG_HEIGHT] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 0, 0, 0, 0, + 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 5, 4, 0, 0, 0, + 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 4, 0, 0, + 0, 0, 3, 1, 4, 3, 4, 3, 4, 3, 4, 2, 2, 2, 2, 0, + 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0, + 0, 0, 3, 1, 3, 4, 3, 4, 3, 4, 3, 4, 1, 5, 2, 0, + 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0, + 0, 0, 3, 1, 4, 3, 4, 3, 4, 3, 4, 3, 1, 5, 2, 0, + 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0, + 0, 0, 3, 1, 3, 4, 3, 4, 3, 4, 3, 4, 1, 5, 2, 0, + 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0, + 0, 0, 3, 1, 4, 3, 4, 3, 4, 3, 4, 3, 1, 5, 2, 0, + 0, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 0, + 0, 0, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 0, + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0 + }; + + image_leaf = IupImage(ITREE_IMG_WIDTH, ITREE_IMG_HEIGHT, img_leaf); + image_collapsed = IupImage(ITREE_IMG_WIDTH, ITREE_IMG_HEIGHT, img_collapsed); + image_expanded = IupImage(ITREE_IMG_WIDTH, ITREE_IMG_HEIGHT, img_expanded); + image_blank = IupImage(ITREE_IMG_WIDTH, ITREE_IMG_HEIGHT, img_blank); + image_paper = IupImage(ITREE_IMG_WIDTH, ITREE_IMG_HEIGHT, img_paper); + + IupSetAttribute(image_leaf, "0", "BGCOLOR"); + IupSetAttribute(image_leaf, "1", "192 192 192"); + IupSetAttribute(image_leaf, "2", "56 56 56"); + IupSetAttribute(image_leaf, "3", "99 99 99"); + IupSetAttribute(image_leaf, "4", "128 128 128"); + IupSetAttribute(image_leaf, "5", "161 161 161"); + IupSetAttribute(image_leaf, "6", "222 222 222"); + + IupSetAttribute(image_collapsed, "0", "BGCOLOR"); + IupSetAttribute(image_collapsed, "1", "255 206 156"); + IupSetAttribute(image_collapsed, "2", "156 156 0"); + IupSetAttribute(image_collapsed, "3", "0 0 0"); + IupSetAttribute(image_collapsed, "4", "206 206 99"); + IupSetAttribute(image_collapsed, "5", "255 255 206"); + IupSetAttribute(image_collapsed, "6", "247 247 247"); + IupSetAttribute(image_collapsed, "7", "255 255 156"); + + IupSetAttribute(image_expanded, "0", "BGCOLOR"); + IupSetAttribute(image_expanded, "1", "255 255 255"); + IupSetAttribute(image_expanded, "2", "156 156 0"); + IupSetAttribute(image_expanded, "3", "255 255 156"); + IupSetAttribute(image_expanded, "4", "0 0 0"); + IupSetAttribute(image_expanded, "5", "255 206 156"); + IupSetAttribute(image_expanded, "6", "206 206 99"); + + IupSetAttribute(image_blank, "0", "BGCOLOR"); + IupSetAttribute(image_blank, "1", "255 255 255"); + IupSetAttribute(image_blank, "2", "000 000 000"); + IupSetAttribute(image_blank, "3", "119 119 119"); + IupSetAttribute(image_blank, "4", "136 136 136"); + IupSetAttribute(image_blank, "5", "187 187 187"); + + IupSetAttribute(image_paper, "0", "BGCOLOR"); + IupSetAttribute(image_paper, "1", "255 255 255"); + IupSetAttribute(image_paper, "2", "000 000 000"); + IupSetAttribute(image_paper, "3", "119 119 119"); + IupSetAttribute(image_paper, "4", "136 136 136"); + IupSetAttribute(image_paper, "5", "187 187 187"); + + IupSetHandle("IMGLEAF", image_leaf); + IupSetHandle("IMGCOLLAPSED", image_collapsed); + IupSetHandle("IMGEXPANDED", image_expanded); + IupSetHandle("IMGBLANK", image_blank); + IupSetHandle("IMGPAPER", image_paper); +} + +void iupTreeUpdateImages(Ihandle *ih) +{ + int inherit; + + char* value = iupAttribGet(ih, "IMAGELEAF"); + if (!value) value = "IMGLEAF"; + iupClassObjectSetAttribute(ih, "IMAGELEAF", value, &inherit); + + value = iupAttribGet(ih, "IMAGEBRANCHCOLLAPSED"); + if (!value) value = "IMGCOLLAPSED"; + iupClassObjectSetAttribute(ih, "IMAGEBRANCHCOLLAPSED", value, &inherit); + + value = iupAttribGet(ih, "IMAGEBRANCHEXPANDED"); + if (!value) value = "IMGEXPANDED"; + iupClassObjectSetAttribute(ih, "IMAGEBRANCHEXPANDED", value, &inherit); +} + +char* iupTreeGetSpacingAttrib(Ihandle* ih) +{ + char *str = iupStrGetMemory(50); + sprintf(str, "%d", ih->data->spacing); + return str; +} + +static char* iTreeGetMarkModeAttrib(Ihandle* ih) +{ + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + return "SINGLE"; + else + return "MULTIPLE"; +} + +static int iTreeSetMarkModeAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "MULTIPLE")) + ih->data->mark_mode = ITREE_MARK_MULTIPLE; + else + ih->data->mark_mode = ITREE_MARK_SINGLE; + if (ih->handle) + iupdrvTreeUpdateMarkMode(ih); + return 0; +} + +static int iTreeSetShiftAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value) && iupAttribGetBoolean(ih, "CTRL")) + iTreeSetMarkModeAttrib(ih, "MULTIPLE"); + else + iTreeSetMarkModeAttrib(ih, "SINGLE"); + return 1; +} + +static int iTreeSetCtrlAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value) && iupAttribGetBoolean(ih, "SHIFT")) + iTreeSetMarkModeAttrib(ih, "MULTIPLE"); + else + iTreeSetMarkModeAttrib(ih, "SINGLE"); + return 1; +} + +static char* iTreeGetShowRenameAttrib(Ihandle* ih) +{ + if (ih->data->show_rename) + return "YES"; + else + return "NO"; +} + +static int iTreeSetShowRenameAttrib(Ihandle* ih, const char* value) +{ + /* valid only before map */ + if (ih->handle) + return 0; + + if (iupStrBoolean(value)) + ih->data->show_rename = 1; + else + ih->data->show_rename = 0; + + return 0; +} + +static char* iTreeGetShowDragDropAttrib(Ihandle* ih) +{ + if (ih->data->show_dragdrop) + return "YES"; + else + return "NO"; +} + +static int iTreeSetShowDragDropAttrib(Ihandle* ih, const char* value) +{ + /* valid only before map */ + if (ih->handle) + return 0; + + if (iupStrBoolean(value)) + ih->data->show_dragdrop = 1; + else + ih->data->show_dragdrop = 0; + + return 0; +} + +static int iTreeSetAddLeafAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + iupdrvTreeAddNode(ih, name_id, ITREE_LEAF, value, 1); + return 0; +} + +static int iTreeSetAddBranchAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + iupdrvTreeAddNode(ih, name_id, ITREE_BRANCH, value, 1); + return 0; +} + +static int iTreeSetInsertLeafAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + iupdrvTreeAddNode(ih, name_id, ITREE_LEAF, value, 0); + return 0; +} + +static int iTreeSetInsertBranchAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + iupdrvTreeAddNode(ih, name_id, ITREE_BRANCH, value, 0); + return 0; +} + +static char* iTreeGetAddExpandedAttrib(Ihandle* ih) +{ + if (ih->data->add_expanded) + return "YES"; + else + return "NO"; +} + +static int iTreeSetAddExpandedAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + ih->data->add_expanded = 1; + else + ih->data->add_expanded = 0; + + return 0; +} + +static int iTreeCreateMethod(Ihandle* ih, void **params) +{ + (void)params; + + ih->data = iupALLOCCTRLDATA(); + + IupSetAttribute(ih, "RASTERSIZE", "400x200"); + IupSetAttribute(ih, "EXPAND", "YES"); + + ih->data->add_expanded = 1; + + return IUP_NOERROR; +} + +Ihandle* IupTree(void) +{ + return IupCreate("tree"); +} + +Iclass* iupTreeGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "tree"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPECONTROL; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + ic->has_attrib_id = 1; /* has attributes with IDs that must be parsed */ + + /* Class functions */ + ic->Create = iTreeCreateMethod; + ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Callbacks */ + iupClassRegisterCallback(ic, "SELECTION_CB", "ii"); + iupClassRegisterCallback(ic, "MULTISELECTION_CB", "Ii"); + iupClassRegisterCallback(ic, "BRANCHOPEN_CB", "i"); + iupClassRegisterCallback(ic, "BRANCHCLOSE_CB", "i"); + iupClassRegisterCallback(ic, "EXECUTELEAF_CB", "i"); + iupClassRegisterCallback(ic, "RENAMENODE_CB", "is"); + iupClassRegisterCallback(ic, "SHOWRENAME_CB", "i"); + iupClassRegisterCallback(ic, "RENAME_CB", "is"); + iupClassRegisterCallback(ic, "DRAGDROP_CB", "iiii"); + iupClassRegisterCallback(ic, "RIGHTCLICK_CB", "i"); + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Visual */ + iupBaseRegisterVisualAttrib(ic); + + /* IupTree Attributes - GENERAL */ + iupClassRegisterAttribute(ic, "SHOWDRAGDROP", iTreeGetShowDragDropAttrib, iTreeSetShowDragDropAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWRENAME", iTreeGetShowRenameAttrib, iTreeSetShowRenameAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ADDEXPANDED", iTreeGetAddExpandedAttrib, iTreeSetAddExpandedAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* IupTree Attributes - MARKS */ + iupClassRegisterAttribute(ic, "CTRL", NULL, iTreeSetCtrlAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "SHIFT", NULL, iTreeSetShiftAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "MARKMODE", iTreeGetMarkModeAttrib, iTreeSetMarkModeAttrib, IUPAF_SAMEASSYSTEM, "SINGLE", IUPAF_NOT_MAPPED); + + /* IupTree Attributes - ACTION */ + iupClassRegisterAttributeId(ic, "ADDLEAF", NULL, iTreeSetAddLeafAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "ADDBRANCH", NULL, iTreeSetAddBranchAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "INSERTLEAF", NULL, iTreeSetInsertLeafAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "INSERTBRANCH", NULL, iTreeSetInsertBranchAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + + /* Default node images */ + iTreeInitializeImages(); + + iupdrvTreeInitClass(ic); + + return ic; +} + + +/********************************************************************************************/ + + +void IupTreeSetAttribute(Ihandle* ih, const char* a, int id, char* v) +{ + char* attr = iupStrGetMemory(50); + sprintf(attr, "%s%d", a, id); + IupSetAttribute(ih, attr, v); +} + +void IupTreeStoreAttribute(Ihandle* ih, const char* a, int id, char* v) +{ + char* attr = iupStrGetMemory(50); + sprintf(attr, "%s%d", a, id); + IupStoreAttribute(ih, attr, v); +} + +char* IupTreeGetAttribute(Ihandle* ih, const char* a, int id) +{ + char* attr = iupStrGetMemory(50); + sprintf(attr, "%s%d", a, id); + return IupGetAttribute(ih, attr); +} + +int IupTreeGetInt(Ihandle* ih, const char* a, int id) +{ + char* attr = iupStrGetMemory(50); + sprintf(attr, "%s%d", a, id); + return IupGetInt(ih, attr); +} + +float IupTreeGetFloat(Ihandle* ih, const char* a, int id) +{ + char* attr = iupStrGetMemory(50); + sprintf(attr, "%s%d", a, id); + return IupGetFloat(ih, attr); +} + +void IupTreeSetfAttribute(Ihandle* ih, const char* a, int id, char* f, ...) +{ + static char v[SHRT_MAX]; + char* attr = iupStrGetMemory(50); + va_list arglist; + sprintf(attr, "%s%d", a, id); + va_start(arglist, f); + vsprintf(v, f, arglist); + va_end(arglist); + IupStoreAttribute(ih, attr, v); +} + + +/************************************************************************************/ + + +int IupTreeSetUserId(Ihandle* ih, int id, void* userdata) +{ + char attr[30]; + sprintf(attr,"USERDATA%d",id); + IupSetAttribute(ih, attr, userdata); + return IupGetAttribute(ih, attr)? 1: 0; +} + +int IupTreeGetId(Ihandle* ih, void *userdata) +{ + int id = -1; + char* value; + char attr[30]; + sprintf(attr,"FINDUSERDATA:%p",userdata); + value = IupGetAttribute(ih, attr); + if (!value) return -1; + + iupStrToInt(value, &id); + return id; +} + +void* IupTreeGetUserId(Ihandle* ih, int id) +{ + char attr[30]; + sprintf(attr,"USERDATA%d",id); + return IupGetAttribute(ih, attr); +} diff --git a/iup/src/iup_tree.h b/iup/src/iup_tree.h new file mode 100755 index 0000000..f96a698 --- /dev/null +++ b/iup/src/iup_tree.h @@ -0,0 +1,57 @@ +/** \file + * \brief iuptree control internal definitions. + * + * See Copyright Notice in iup.h + */ + +#ifndef __IUP_TREE_H +#define __IUP_TREE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Kinds of node */ +#define ITREE_BRANCH 0 +#define ITREE_LEAF 1 + +#define ITREE_MARK_SINGLE 0 +#define ITREE_MARK_MULTIPLE 1 + +#define ITREE_UPDATEIMAGE_LEAF 1 +#define ITREE_UPDATEIMAGE_COLLAPSED 2 +#define ITREE_UPDATEIMAGE_EXPANDED 3 + +void iupdrvTreeInitClass(Iclass* ic); +void iupTreeUpdateImages(Ihandle *ih); +void iupdrvTreeAddNode(Ihandle* ih, const char* id_string, int kind, const char* title, int add); +void iupdrvTreeUpdateMarkMode(Ihandle *ih); + +char* iupTreeGetSpacingAttrib(Ihandle* ih); + +/* Structure of the tree */ +struct _IcontrolData +{ + int mark_mode, + add_expanded, + show_dragdrop, + show_rename, + spacing; + + void* def_image_leaf; /* Default image leaf */ + void* def_image_collapsed; /* Default image collapsed */ + void* def_image_expanded; /* Default image expanded */ + + void* def_image_leaf_mask; /* Motif Only */ + void* def_image_collapsed_mask; + void* def_image_expanded_mask; + + int id_control; /* auxiliary variable for computing or finding the id of a node */ +}; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_user.c b/iup/src/iup_user.c new file mode 100755 index 0000000..842f436 --- /dev/null +++ b/iup/src/iup_user.c @@ -0,0 +1,41 @@ +/** \file + * \brief User Element. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_stdcontrols.h" + + +static int iUserSetClearAttributesAttrib(Ihandle* ih, const char* value) +{ + (void)value; + iupTableClear(ih->attrib); + return 0; +} + +Ihandle* IupUser(void) +{ + return IupCreate("user"); +} + +Iclass* iupUserGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "user"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPEVOID; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 0; + + iupClassRegisterAttribute(ic, "CLEARATTRIBUTES", NULL, iUserSetClearAttributesAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} diff --git a/iup/src/iup_val.c b/iup/src/iup_val.c new file mode 100755 index 0000000..521e35a --- /dev/null +++ b/iup/src/iup_val.c @@ -0,0 +1,209 @@ +/** \file + * \brief Valuator Control + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "iup.h" +#include "iupcbs.h" +#include "iupkey.h" +#include "iupcontrols.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" +#include "iup_val.h" + + +void iupValCropValue(Ihandle* ih) +{ + if (ih->data->val > ih->data->vmax) + ih->data->val = ih->data->vmax; + else if (ih->data->val < ih->data->vmin) + ih->data->val = ih->data->vmin; +} + +char* iupValGetShowTicksAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(30); + sprintf(str, "%d", ih->data->show_ticks); + return str; +} + +char* iupValGetValueAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(30); + sprintf(str, "%g", ih->data->val); + return str; +} + +char* iupValGetStepAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(30); + sprintf(str, "%g", ih->data->step); + return str; +} + +char* iupValGetPageStepAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(30); + sprintf(str, "%g", ih->data->pagestep); + return str; +} + +static int iValSetMaxAttrib(Ihandle* ih, const char* value) +{ + ih->data->vmax = atof(value); + iupValCropValue(ih); + return 0; /* do not store value in hash table */ +} + +static char* iValGetMaxAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(30); + sprintf(str, "%g", ih->data->vmax); + return str; +} + +static int iValSetMinAttrib(Ihandle* ih, const char* value) +{ + ih->data->vmin = atof(value); + iupValCropValue(ih); + return 0; /* do not store value in hash table */ +} + +static char* iValGetMinAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(30); + sprintf(str, "%g", ih->data->vmin); + return str; +} + +static int iValSetTypeAttrib(Ihandle* ih, const char *value) +{ + int min_w, min_h; + + /* valid only before map */ + if (ih->handle) + return 0; + + iupdrvValGetMinSize(ih, &min_w, &min_h); + + if (iupStrEqualNoCase(value, "VERTICAL")) + { + /* val natural vertical size is MinWx100 */ + IupSetfAttribute(ih, "RASTERSIZE", "%dx%d", min_w, 100); + ih->data->type = IVAL_VERTICAL; + } + else /* "HORIZONTAL" */ + { + /* val natural horizontal size is 100xMinH */ + IupSetfAttribute(ih, "RASTERSIZE", "%dx%d", 100, min_h); + ih->data->type = IVAL_HORIZONTAL; + } + + return 0; /* do not store value in hash table */ +} + +static char* iValGetTypeAttrib(Ihandle* ih) +{ + if (ih->data->type == IVAL_HORIZONTAL) + return "HORIZONTAL"; + else /* (ih->data->type == IVAL_VERTICAL) */ + return "VERTICAL"; +} + +static int iValSetInvertedAttrib(Ihandle* ih, const char *value) +{ + /* valid only before map */ + if (ih->handle) + return 0; + + if (iupStrBoolean(value)) + ih->data->inverted = 1; + else + ih->data->inverted = 0; + + return 0; /* do not store value in hash table */ +} + +static char* iValGetInvertedAttrib(Ihandle* ih) +{ + if (ih->data->inverted) + return "YES"; + else + return "NO"; +} + +static int iValCreateMethod(Ihandle* ih, void **params) +{ + char* type = "HORIZONTAL"; + if (params && params[0]) + type = params[0]; + + ih->data = iupALLOCCTRLDATA(); + + iValSetTypeAttrib(ih, type); + if (ih->data->type == IVAL_VERTICAL) + ih->data->inverted = 1; /* default is YES when vertical */ + + ih->data->vmax = 1.00; + ih->data->step = 0.01; + ih->data->pagestep = 0.10; + + return IUP_NOERROR; +} + +Iclass* iupValGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "val"; + ic->format = "S"; /* one optional string */ + ic->nativetype = IUP_TYPECONTROL; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + + /* Class functions */ + ic->Create = iValCreateMethod; + ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Callbacks */ + iupClassRegisterCallback(ic, "VALUECHANGED_CB", ""); + + /* Common Callbacks */ + iupBaseRegisterCommonCallbacks(ic); + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Visual */ + iupBaseRegisterVisualAttrib(ic); + + /* IupVal only */ + iupClassRegisterAttribute(ic, "MAX", iValGetMaxAttrib, iValSetMaxAttrib, IUPAF_SAMEASSYSTEM, "1.0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "MIN", iValGetMinAttrib, iValSetMinAttrib, IUPAF_SAMEASSYSTEM, "0.0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "TYPE", iValGetTypeAttrib, iValSetTypeAttrib, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INVERTED", iValGetInvertedAttrib, iValSetInvertedAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupdrvValInitClass(ic); + + return ic; +} + +Ihandle *IupVal(const char *type) +{ + void *params[2]; + params[0] = (void*)type; + params[1] = NULL; + return IupCreatev("val", params); +} diff --git a/iup/src/iup_val.h b/iup/src/iup_val.h new file mode 100755 index 0000000..dea8df4 --- /dev/null +++ b/iup/src/iup_val.h @@ -0,0 +1,42 @@ +/** \file + * \brief Valuator Control + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_VAL_H +#define __IUP_VAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum {IVAL_VERTICAL, IVAL_HORIZONTAL}; + +struct _IcontrolData +{ + int type; + int show_ticks; /* Windows and Motif only - can be used only after map */ + int inverted; + double val; + double step; + double pagestep; + double vmin; + double vmax; +}; + +void iupValCropValue(Ihandle* ih); +char* iupValGetValueAttrib(Ihandle* ih); +char* iupValGetStepAttrib(Ihandle* ih); +char* iupValGetPageStepAttrib(Ihandle* ih); +char* iupValGetShowTicksAttrib(Ihandle* ih); + +void iupdrvValInitClass(Iclass* ic); +void iupdrvValGetMinSize(Ihandle* ih, int *w, int *h); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/iup_vbox.c b/iup/src/iup_vbox.c new file mode 100755 index 0000000..f71aa51 --- /dev/null +++ b/iup/src/iup_vbox.c @@ -0,0 +1,311 @@ +/** \file + * \brief Vbox Control. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" +#include "iup_box.h" + + +static int iVboxSetRasterSizeAttrib(Ihandle* ih, const char* value) +{ + if (!value) + { + ih->userwidth = 0; + ih->userheight = 0; + } + else + { + int s = 0; + iupStrToInt(value, &s); + if (s > 0) + { + ih->userheight = s; + ih->userwidth = 0; + } + } + iupAttribSetStr(ih, "SIZE", NULL); /* clear SIZE in hash table */ + return 0; +} + +static int iVboxSetSizeAttrib(Ihandle* ih, const char* value) +{ + if (!value) + { + ih->userwidth = 0; + ih->userheight = 0; + } + else + { + int s = 0; + iupStrToInt(value, &s); + if (s > 0) + { + int charwidth, charheight; + iupdrvFontGetCharSize(ih, &charwidth, &charheight); + ih->userheight = iupHEIGHT2RASTER(s, charheight); + ih->userwidth = 0; + } + } + return 1; +} + +static int iVboxSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "ARIGHT")) + ih->data->alignment = IUP_ALIGN_ARIGHT; + else if (iupStrEqualNoCase(value, "ACENTER")) + ih->data->alignment = IUP_ALIGN_ACENTER; + else if (iupStrEqualNoCase(value, "ALEFT")) + ih->data->alignment = IUP_ALIGN_ALEFT; + return 0; +} + +static char* iVboxGetAlignmentAttrib(Ihandle* ih) +{ + char* align2str[3] = {"ALEFT", "ACENTER", "ARIGHT"}; + char *str = iupStrGetMemory(50); + sprintf(str, "%s", align2str[ih->data->alignment]); + return str; +} + +static void iVboxComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + Ihandle* child; + int children_naturalwidth, children_naturalheight; + + /* calculate total children natural size */ + int children_expand = 0; + int children_count = 0; + int children_natural_maxwidth = 0; + int children_natural_maxheight = 0; + int children_natural_totalheight = 0; + + for (child = ih->firstchild; child; child = child->brother) + { + /* update child natural size first */ + iupBaseComputeNaturalSize(child); + + if (!child->is_floating) + { + children_expand |= child->expand; + children_natural_maxwidth = iupMAX(children_natural_maxwidth, child->naturalwidth); + children_natural_maxheight = iupMAX(children_natural_maxheight, child->naturalheight); + children_count++; + } + } + + /* reset to max natural width and/or height if NORMALIZESIZE is defined */ + if (ih->data->normalize_size) + iupNormalizeSizeBoxChild(ih, ih->data->normalize_size, children_natural_maxwidth, children_natural_maxheight); + + for (child = ih->firstchild; child; child = child->brother) + { + if (!child->is_floating) + children_natural_totalheight += child->naturalheight; + } + + /* leave room at the element for the maximum natural size of the children when is_homogeneous */ + if (ih->data->is_homogeneous) + children_natural_totalheight = children_natural_maxheight*children_count; + + /* compute the Vbox contents natural size */ + children_naturalwidth = children_natural_maxwidth + 2*ih->data->margin_x; + children_naturalheight = children_natural_totalheight + (children_count-1)*ih->data->gap + 2*ih->data->margin_y; + + /* Store to be used in iVboxCalcEmptyHeight */ + ih->data->children_naturalsize = children_naturalheight; + + *expand = children_expand; + *w = children_naturalwidth; + *h = children_naturalheight; +} + +static int iHboxCalcHomogeneousHeight(Ihandle *ih) +{ + /* This is the space that the child can be expanded. */ + Ihandle* child; + int homogeneous_height; + + int children_count=0; + for (child = ih->firstchild; child; child = child->brother) + { + if (!child->is_floating) + children_count++; + } + if (children_count == 0) + return 0; + + /* equal spaces for all elements */ + homogeneous_height = (ih->currentheight - (children_count-1)*ih->data->gap - 2*ih->data->margin_y)/children_count; + if (homogeneous_height < 0) homogeneous_height = 0; + return homogeneous_height; +} + +static int iVboxCalcEmptyHeight(Ihandle *ih, int expand) +{ + /* This is the space that the child can be expanded. */ + Ihandle* child; + int empty_height; + + int expand_count=0; + for (child = ih->firstchild; child; child = child->brother) + { + if (!child->is_floating && child->expand & expand) + expand_count++; + } + if (expand_count == 0) + return 0; + + /* equal spaces for all expandable elements */ + empty_height = (ih->currentheight - ih->data->children_naturalsize)/expand_count; + if (empty_height < 0) empty_height = 0; + return empty_height; +} + +static void iVboxSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink) +{ + Ihandle* child; + int empty_h0 = 0, empty_h1 = 0, client_width; + + if (ih->data->expand_children) + ih->expand |= ih->data->expand_children; + + if (ih->data->is_homogeneous) + ih->data->homogeneous_size = iHboxCalcHomogeneousHeight(ih); + else + { + ih->data->homogeneous_size = 0; + + /* must calculate the space left for each control to grow inside the container */ + /* H1 means there is an EXPAND enabled inside */ + if (ih->expand & IUP_EXPAND_H1) + empty_h1 = iVboxCalcEmptyHeight(ih, IUP_EXPAND_H1); + /* Not H1 and H0 means that EXPAND is not enabled, but there are some IupFill inside */ + else if (ih->expand & IUP_EXPAND_H0) + empty_h0 = iVboxCalcEmptyHeight(ih, IUP_EXPAND_H0); + } + + client_width = ih->currentwidth - 2*ih->data->margin_x; + if (client_width<0) client_width=0; + + for (child = ih->firstchild; child; child = child->brother) + { + if (!child->is_floating) + { + int old_expand = child->expand; + if (ih->data->expand_children) + child->expand |= ih->data->expand_children; + + if (ih->data->homogeneous_size) + iupBaseSetCurrentSize(child, client_width, ih->data->homogeneous_size, shrink); + else + { + int empty = (child->expand & IUP_EXPAND_H1)? empty_h1: ((child->expand & IUP_EXPAND_H0)? empty_h0: 0); + iupBaseSetCurrentSize(child, client_width, child->naturalheight+empty, shrink); + } + + if (ih->data->expand_children) + child->expand = old_expand; + } + else + { + /* update children to their own natural size */ + iupBaseSetCurrentSize(child, child->naturalwidth, child->naturalheight, shrink); + } + } +} + +static void iVboxSetChildrenPositionMethod(Ihandle* ih, int x, int y) +{ + int dx, client_width; + Ihandle* child; + + x += ih->data->margin_x; + y += ih->data->margin_y; + + client_width = ih->currentwidth - 2*ih->data->margin_x; + if (client_width<0) client_width=0; + + for (child = ih->firstchild; child; child = child->brother) + { + if (!child->is_floating) + { + if (ih->data->alignment == IUP_ALIGN_ACENTER) + dx = (client_width - child->currentwidth)/2; + else if (ih->data->alignment == IUP_ALIGN_ARIGHT) + dx = client_width - child->currentwidth; + else /* IUP_ALIGN_ALEFT */ + dx = 0; + if (dx<0) dx = 0; + + /* update child */ + iupBaseSetPosition(child, x+dx, y); + + /* calculate next */ + if (ih->data->homogeneous_size) + y += ih->data->homogeneous_size + ih->data->gap; + else + y += child->currentheight + ih->data->gap; + } + } +} + + +/******************************************************************************/ + + +Ihandle *IupVboxv(Ihandle **children) +{ + return IupCreatev("vbox", (void**)children); +} + +Ihandle *IupVbox(Ihandle* child, ...) +{ + Ihandle **children; + Ihandle *ih; + + va_list arglist; + va_start(arglist, child); + children = (Ihandle **)iupObjectGetParamList(child, arglist); + va_end(arglist); + + ih = IupCreatev("vbox", (void**)children); + free(children); + + return ih; +} + +Iclass* iupVboxGetClass(void) +{ + Iclass* ic = iupBoxClassBase(); + + ic->name = "vbox"; + + /* Class functions */ + ic->ComputeNaturalSize = iVboxComputeNaturalSizeMethod; + ic->SetChildrenCurrentSize = iVboxSetChildrenCurrentSizeMethod; + ic->SetChildrenPosition = iVboxSetChildrenPositionMethod; + + /* Overwrite Common */ + iupClassRegisterAttribute(ic, "SIZE", iupBaseGetSizeAttrib, iVboxSetSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "RASTERSIZE", iupBaseGetRasterSizeAttrib, iVboxSetRasterSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* Vbox only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", iVboxGetAlignmentAttrib, iVboxSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ALEFT", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} diff --git a/iup/src/iup_zbox.c b/iup/src/iup_zbox.c new file mode 100755 index 0000000..3f79892 --- /dev/null +++ b/iup/src/iup_zbox.c @@ -0,0 +1,375 @@ +/** \file + * \brief Zbox Control. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_layout.h" + + +enum{IZBOX_ALIGN_NORTH, IZBOX_ALIGN_SOUTH, IZBOX_ALIGN_WEST, IZBOX_ALIGN_EAST, + IZBOX_ALIGN_NE, IZBOX_ALIGN_SE, IZBOX_ALIGN_NW, IZBOX_ALIGN_SW, + IZBOX_ALIGN_ACENTER}; + +struct _IcontrolData +{ + int alignment; + Ihandle* value_handle; +}; + +static int iZboxCreateMethod(Ihandle* ih, void** params) +{ + ih->data = iupALLOCCTRLDATA(); + + ih->data->alignment = IZBOX_ALIGN_NW; + + if (params) + { + Ihandle** iparams = (Ihandle**)params; + while (*iparams) + { + IupAppend(ih, *iparams); + iparams++; + } + } + + return IUP_NOERROR; +} + +static void iZboxChildAddedMethod(Ihandle* ih, Ihandle* child) +{ + if (!ih->data->value_handle) + { + IupSetAttribute(child, "VISIBLE", "YES"); + ih->data->value_handle = child; + } + else + IupSetAttribute(child, "VISIBLE", "NO"); +} + +static void iZboxChildRemovedMethod(Ihandle* ih, Ihandle* child) +{ + if (child == ih->data->value_handle) + { + /* reset to the first child, even if it is NULL */ + if (ih->firstchild) + IupSetAttribute(ih->firstchild, "VISIBLE", "YES"); + ih->data->value_handle = ih->firstchild; + } +} + +static int iZboxSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "NORTH") || iupStrEqualNoCase(value, "ATOP")) + ih->data->alignment = IZBOX_ALIGN_NORTH; + else if (iupStrEqualNoCase(value, "SOUTH") || iupStrEqualNoCase(value, "ABOTTOM")) + ih->data->alignment = IZBOX_ALIGN_SOUTH; + else if (iupStrEqualNoCase(value, "WEST") || iupStrEqualNoCase(value, "ALEFT")) + ih->data->alignment = IZBOX_ALIGN_WEST; + else if (iupStrEqualNoCase(value, "EAST") || iupStrEqualNoCase(value, "ARIGHT")) + ih->data->alignment = IZBOX_ALIGN_EAST; + else if (iupStrEqualNoCase(value, "NE")) + ih->data->alignment = IZBOX_ALIGN_NE; + else if (iupStrEqualNoCase(value, "SE")) + ih->data->alignment = IZBOX_ALIGN_SE; + else if (iupStrEqualNoCase(value, "NW")) + ih->data->alignment = IZBOX_ALIGN_NW; + else if (iupStrEqualNoCase(value, "SW")) + ih->data->alignment = IZBOX_ALIGN_SW; + else if (iupStrEqualNoCase(value, "ACENTER")) + ih->data->alignment = IZBOX_ALIGN_ACENTER; + return 0; +} + +static char* iZboxGetAlignmentAttrib(Ihandle* ih) +{ + static char* align2str[9] = {"NORTH", "SOUTH", "WEST", "EAST", + "NE", "SE", "NW", "SW", + "ACENTER"}; + return align2str[ih->data->alignment]; +} + +static int iZboxSetValueHandleAttrib(Ihandle* ih, const char* value) +{ + Ihandle* old_handle, *new_handle, *child; + + new_handle = (Ihandle*)value; + if (!iupObjectCheck(new_handle)) + return 0; + + old_handle = ih->data->value_handle; + if (!iupObjectCheck(old_handle)) + old_handle = NULL; + + if (old_handle == new_handle) + return 0; + + for (child = ih->firstchild; child; child = child->brother) + { + if (child == new_handle) /* found child */ + { + if (old_handle && old_handle != new_handle) + IupSetAttribute(old_handle, "VISIBLE", "NO"); + + IupSetAttribute(new_handle, "VISIBLE", "YES"); + ih->data->value_handle = new_handle; + return 0; + } + } + + return 0; +} + +static int iZboxSetValuePosAttrib(Ihandle* ih, const char* value) +{ + Ihandle* child; + int pos, i; + + if (!iupStrToInt(value, &pos)) + return 0; + + for (i=0, child=ih->firstchild; child; child = child->brother, i++) + { + if (i == pos) /* found child */ + { + iZboxSetValueHandleAttrib(ih, (char*)child); + return 0; + } + } + + return 0; +} + +static char* iZboxGetValuePosAttrib(Ihandle* ih) +{ + Ihandle* child; + int pos; + + if (!iupObjectCheck(ih->data->value_handle)) + return NULL; + + for (pos=0, child = ih->firstchild; child; child = child->brother, pos++) + { + if (child == ih->data->value_handle) /* found child */ + { + char *str = iupStrGetMemory(50); + sprintf(str, "%d", pos); + return str; + } + } + + return NULL; +} + +static int iZboxSetValueAttrib(Ihandle* ih, const char* value) +{ + Ihandle *new_handle; + + if (!value) + return 0; + + new_handle = IupGetHandle(value); + if (!new_handle) + return 0; + + iZboxSetValueHandleAttrib(ih, (char*)new_handle); + + return 0; +} + +static char* iZboxGetValueAttrib(Ihandle* ih) +{ + Ihandle* child; + int pos; + + if (!iupObjectCheck(ih->data->value_handle)) + return NULL; + + for (pos=0, child = ih->firstchild; child; child = child->brother, pos++) + { + if (child == ih->data->value_handle) /* found child, just cheking */ + return IupGetName(ih->data->value_handle); + } + + return NULL; +} + +static int iZboxSetVisibleAttrib(Ihandle* ih, const char* value) +{ + if (iupObjectCheck(ih->data->value_handle)) + IupSetAttribute(ih->data->value_handle, "VISIBLE", (char*)value); + return 0; +} + +static void iZboxComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + Ihandle* child; + int children_expand, + children_naturalwidth, children_naturalheight; + + /* calculate total children natural size (even for hidden children) */ + children_expand = 0; + children_naturalwidth = 0; + children_naturalheight = 0; + + for (child = ih->firstchild; child; child = child->brother) + { + /* update child natural size first */ + iupBaseComputeNaturalSize(child); + + if (!child->is_floating) + { + children_expand |= child->expand; + children_naturalwidth = iupMAX(children_naturalwidth, child->naturalwidth); + children_naturalheight = iupMAX(children_naturalheight, child->naturalheight); + } + } + + *expand = children_expand; + *w = children_naturalwidth; + *h = children_naturalheight; +} + +static void iZboxSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink) +{ + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + { + if (!child->is_floating) + iupBaseSetCurrentSize(child, ih->currentwidth, ih->currentheight, shrink); + } +} + +static void iZboxSetChildrenPositionMethod(Ihandle* ih, int x, int y) +{ + int dx = 0, dy = 0; + Ihandle* child; + + for (child = ih->firstchild; child; child = child->brother) + { + if (!child->is_floating) + { + switch (ih->data->alignment) + { + case IZBOX_ALIGN_ACENTER: + dx=(ih->currentwidth-child->currentwidth)/2; + dy=(ih->currentheight-child->currentheight)/2; + break; + case IZBOX_ALIGN_NORTH: + dx=(ih->currentwidth-child->currentwidth)/2; + dy=0; + break; + case IZBOX_ALIGN_SOUTH: + dx=(ih->currentwidth-child->currentwidth)/2; + dy=ih->currentheight-child->currentheight; + break; + case IZBOX_ALIGN_WEST: + dx=0; + dy=(ih->currentheight-child->currentheight)/2; + break; + case IZBOX_ALIGN_EAST: + dx=ih->currentwidth-child->currentwidth; + dy=(ih->currentheight-child->currentheight)/2; + break; + case IZBOX_ALIGN_NE: + dx=ih->currentwidth-child->currentwidth; + dy=0; + break; + case IZBOX_ALIGN_SE: + dx=ih->currentwidth-child->currentwidth; + dy=ih->currentheight-child->currentheight; + break; + case IZBOX_ALIGN_SW: + dx=0; + dy=ih->currentheight-child->currentheight; + break; + case IZBOX_ALIGN_NW: + default: + dx=0; + dy=0; + break; + } + if (dx<0) dx = 0; + if (dy<0) dy = 0; + + /* update child */ + iupBaseSetPosition(child, x+dx, y+dy); + } + } +} + + +/******************************************************************************/ + + +Ihandle *IupZboxv(Ihandle **children) +{ + return IupCreatev("zbox", (void**)children); +} + +Ihandle *IupZbox(Ihandle* child, ...) +{ + Ihandle **children; + Ihandle *ih; + + va_list arglist; + va_start(arglist, child); + children = (Ihandle **)iupObjectGetParamList(child, arglist); + va_end(arglist); + + ih = IupCreatev("zbox", (void**)children); + free(children); + + return ih; +} + +Iclass* iupZboxGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "zbox"; + ic->format = "g"; /* array of Ihandle */ + ic->nativetype = IUP_TYPEVOID; + ic->childtype = IUP_CHILDMANY; + ic->is_interactive = 0; + + /* Class functions */ + ic->Create = iZboxCreateMethod; + ic->Map = iupBaseTypeVoidMapMethod; + ic->ChildAdded = iZboxChildAddedMethod; + ic->ChildRemoved = iZboxChildRemovedMethod; + + ic->ComputeNaturalSize = iZboxComputeNaturalSizeMethod; + ic->SetChildrenCurrentSize = iZboxSetChildrenCurrentSizeMethod; + ic->SetChildrenPosition = iZboxSetChildrenPositionMethod; + + /* Common */ + iupBaseRegisterCommonAttrib(ic); + + /* Base Container */ + iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CLIENTSIZE", iupBaseGetRasterSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* Zbox only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", iZboxGetAlignmentAttrib, iZboxSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "NW", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE", iZboxGetValueAttrib, iZboxSetValueAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUEPOS", iZboxGetValuePosAttrib, iZboxSetValuePosAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE_HANDLE", NULL, iZboxSetValueHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + + /* Intercept VISIBLE since ZBOX works showing and hidding its children */ + iupClassRegisterAttribute(ic, "VISIBLE", NULL, iZboxSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} diff --git a/iup/src/iupgtk.dep b/iup/src/iupgtk.dep new file mode 100644 index 0000000..4e2bb45 --- /dev/null +++ b/iup/src/iupgtk.dep @@ -0,0 +1,259 @@ +$(OBJDIR)/iup_array.o: iup_array.c iup_array.h iup_assert.h +$(OBJDIR)/iup_callback.o: iup_callback.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_assert.h +$(OBJDIR)/iup_dlglist.o: iup_dlglist.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_dlglist.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_assert.h +$(OBJDIR)/iup_attrib.o: iup_attrib.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_childtree.h iup_str.h iup_ledlex.h iup_attrib.h \ + iup_assert.h +$(OBJDIR)/iup_focus.o: iup_focus.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_focus.h iup_assert.h iup_attrib.h \ + iup_str.h iup_drv.h +$(OBJDIR)/iup_font.o: iup_font.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_str.h iup_drvfont.h iup_assert.h iup_attrib.h \ + iup_class.h iup_table.h iup_classbase.h +$(OBJDIR)/iup_globalattrib.o: iup_globalattrib.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h iup_table.h iup_globalattrib.h \ + iup_drv.h iup_drvfont.h iup_assert.h iup_str.h +$(OBJDIR)/iup_object.o: iup_object.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_assert.h iup_register.h iup_names.h +$(OBJDIR)/iup_key.o: iup_key.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_key.h iup_str.h \ + iup_object.h iup_class.h iup_table.h iup_classbase.h iup_drv.h \ + iup_focus.h +$(OBJDIR)/iup_layout.o: iup_layout.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_drv.h iup_attrib.h iup_str.h iup_layout.h \ + iup_assert.h +$(OBJDIR)/iup_ledlex.o: iup_ledlex.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_class.h iup_table.h iup_classbase.h \ + iup_ledlex.h iup_str.h iup_register.h +$(OBJDIR)/iup_names.o: iup_names.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_str.h iup_table.h iup_names.h iup_object.h \ + iup_class.h iup_classbase.h iup_assert.h +$(OBJDIR)/iup_open.o: iup_open.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_str.h iup_globalattrib.h iup_names.h iup_func.h \ + iup_drv.h iup_drvinfo.h iup_drvfont.h iup_predial.h iup_class.h \ + iup_table.h iup_classbase.h iup_register.h iup_key.h iup_image.h \ + iup_dlglist.h iup_assert.h iup_strmessage.h +$(OBJDIR)/iup_ledparse.o: iup_ledparse.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_ledlex.h iup_str.h iup_assert.h +$(OBJDIR)/iup_predial.o: iup_predial.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_predial.h iup_attrib.h iup_str.h \ + iup_strmessage.h +$(OBJDIR)/iup_register.o: iup_register.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_register.h iup_stdcontrols.h +$(OBJDIR)/iup_scanf.o: iup_scanf.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_predial.h iup_str.h iup_assert.h +$(OBJDIR)/iup_show.o: iup_show.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_layout.h iup_attrib.h iup_dialog.h iup_menu.h \ + iup_assert.h iup_str.h iup_drv.h iup_drvfont.h +$(OBJDIR)/iup_str.o: iup_str.c iup_str.h +$(OBJDIR)/iup_table.o: iup_table.c iup_table.h iup_str.h iup_assert.h +$(OBJDIR)/iup_func.o: iup_func.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_str.h iup_table.h iup_func.h iup_drv.h \ + iup_assert.h +$(OBJDIR)/iup_childtree.o: iup_childtree.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_dlglist.h iup_childtree.h iup_attrib.h iup_assert.h \ + iup_str.h iup_drv.h +$(OBJDIR)/iup.o: iup.c ../include/iup.h ../include/iupkey.h ../include/iupdef.h +$(OBJDIR)/iup_classattrib.o: iup_classattrib.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_drv.h iup_drvfont.h iup_str.h iup_attrib.h \ + iup_assert.h iup_register.h iup_globalattrib.h +$(OBJDIR)/iup_dialog.o: iup_dialog.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_class.h iup_table.h \ + iup_classbase.h iup_object.h iup_dlglist.h iup_layout.h iup_attrib.h \ + iup_drv.h iup_drvinfo.h iup_drvfont.h iup_focus.h iup_str.h \ + iup_dialog.h +$(OBJDIR)/iup_assert.o: iup_assert.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_assert.h iup_attrib.h iup_str.h \ + iup_strmessage.h +$(OBJDIR)/iup_canvas.o: iup_canvas.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_canvas.h +$(OBJDIR)/iup_messagedlg.o: iup_messagedlg.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_stdcontrols.h +$(OBJDIR)/iup_timer.o: iup_timer.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_str.h iup_stdcontrols.h iup_timer.h +$(OBJDIR)/iup_image.o: iup_image.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_attrib.h iup_str.h iup_image.h iup_assert.h \ + iup_stdcontrols.h +$(OBJDIR)/iup_label.o: iup_label.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_label.h iup_image.h +$(OBJDIR)/iup_fill.o: iup_fill.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h +$(OBJDIR)/iup_zbox.o: iup_zbox.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h +$(OBJDIR)/iup_colordlg.o: iup_colordlg.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h +$(OBJDIR)/iup_fontdlg.o: iup_fontdlg.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h +$(OBJDIR)/iup_filedlg.o: iup_filedlg.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h +$(OBJDIR)/iup_strmessage.o: iup_strmessage.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_attrib.h iup_str.h iup_strmessage.h iup_table.h +$(OBJDIR)/iup_menu.o: iup_menu.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_attrib.h iup_dialog.h iup_str.h iup_assert.h \ + iup_key.h iup_stdcontrols.h iup_drvinfo.h iup_menu.h +$(OBJDIR)/iup_frame.o: iup_frame.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_frame.h +$(OBJDIR)/iup_user.o: iup_user.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_stdcontrols.h +$(OBJDIR)/iup_button.o: iup_button.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_button.h iup_image.h +$(OBJDIR)/iup_radio.o: iup_radio.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h +$(OBJDIR)/iup_toggle.o: iup_toggle.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_toggle.h iup_image.h +$(OBJDIR)/iup_progressbar.o: iup_progressbar.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_progressbar.h +$(OBJDIR)/iup_text.o: iup_text.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_mask.h iup_array.h \ + iup_text.h iup_assert.h +$(OBJDIR)/iup_val.o: iup_val.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h ../include/iupcontrols.h \ + iup_object.h iup_class.h iup_table.h iup_classbase.h iup_attrib.h \ + iup_str.h iup_drv.h iup_stdcontrols.h iup_layout.h iup_val.h +$(OBJDIR)/iup_box.o: iup_box.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_box.h +$(OBJDIR)/iup_hbox.o: iup_hbox.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_box.h +$(OBJDIR)/iup_vbox.o: iup_vbox.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_box.h +$(OBJDIR)/iup_cbox.o: iup_cbox.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h +$(OBJDIR)/iup_class.o: iup_class.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_drv.h iup_drvfont.h iup_str.h iup_attrib.h \ + iup_assert.h +$(OBJDIR)/iup_classbase.o: iup_classbase.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_drv.h iup_drvfont.h iup_str.h \ + iup_attrib.h iup_assert.h +$(OBJDIR)/iup_maskmatch.o: iup_maskmatch.c iup_maskparse.h iup_maskmatch.h +$(OBJDIR)/iup_mask.o: iup_mask.c iup_maskparse.h iup_mask.h iup_str.h +$(OBJDIR)/iup_maskparse.o: iup_maskparse.c iup_maskparse.h iup_maskmatch.h +$(OBJDIR)/iup_tabs.o: iup_tabs.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_image.h iup_tabs.h +$(OBJDIR)/iup_spin.o: iup_spin.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_stdcontrols.h \ + iup_childtree.h +$(OBJDIR)/iup_list.o: iup_list.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_assert.h iup_object.h \ + iup_class.h iup_table.h iup_classbase.h iup_attrib.h iup_str.h \ + iup_drv.h iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_mask.h \ + iup_list.h +$(OBJDIR)/iup_getparam.o: iup_getparam.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_attrib.h iup_str.h iup_strmessage.h \ + iup_drvfont.h +$(OBJDIR)/iup_sbox.o: iup_sbox.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_stdcontrols.h iup_layout.h iup_childtree.h +$(OBJDIR)/iup_normalizer.o: iup_normalizer.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_attrib.h iup_str.h iup_array.h iup_stdcontrols.h +$(OBJDIR)/iup_tree.o: iup_tree.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_drv.h \ + iup_drvfont.h iup_stdcontrols.h iup_layout.h iup_tree.h iup_assert.h +$(OBJDIR)/iupgtk_focus.o: gtk/iupgtk_focus.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_focus.h iup_attrib.h iup_drv.h iup_assert.h \ + gtk/iupgtk_drv.h +$(OBJDIR)/iupgtk_font.o: gtk/iupgtk_font.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_str.h iup_attrib.h iup_array.h iup_object.h \ + iup_class.h iup_table.h iup_classbase.h iup_drv.h iup_drvfont.h \ + iup_assert.h gtk/iupgtk_drv.h +$(OBJDIR)/iupgtk_key.o: gtk/iupgtk_key.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_key.h gtk/iupgtk_drv.h +$(OBJDIR)/iupgtk_loop.o: gtk/iupgtk_loop.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h +$(OBJDIR)/iupgtk_open.o: gtk/iupgtk_open.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_str.h iup_drv.h iup_drvinfo.h iup_object.h \ + iup_class.h iup_table.h iup_classbase.h iup_globalattrib.h \ + gtk/iupgtk_drv.h +$(OBJDIR)/iupgtk_messagedlg.o: gtk/iupgtk_messagedlg.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_dialog.h \ + gtk/iupgtk_drv.h +$(OBJDIR)/iupgtk_timer.o: gtk/iupgtk_timer.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_attrib.h iup_str.h iup_assert.h iup_timer.h +$(OBJDIR)/iupgtk_colordlg.o: gtk/iupgtk_colordlg.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_dialog.h \ + gtk/iupgtk_drv.h +$(OBJDIR)/iupgtk_fontdlg.o: gtk/iupgtk_fontdlg.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_attrib.h iup_str.h iup_dialog.h \ + gtk/iupgtk_drv.h +$(OBJDIR)/iupgtk_progressbar.o: gtk/iupgtk_progressbar.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h ../include/iupcbs.h \ + iup_object.h iup_class.h iup_table.h iup_classbase.h iup_layout.h \ + iup_attrib.h iup_str.h iup_progressbar.h iup_drv.h gtk/iupgtk_drv.h +$(OBJDIR)/iupgtk_val.o: gtk/iupgtk_val.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_layout.h iup_attrib.h iup_str.h \ + iup_val.h iup_drv.h iup_drvfont.h iup_key.h gtk/iupgtk_drv.h +$(OBJDIR)/iupgtk_frame.o: gtk/iupgtk_frame.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_object.h iup_class.h iup_table.h \ + iup_classbase.h iup_layout.h iup_attrib.h iup_str.h iup_dialog.h \ + iup_drv.h iup_drvfont.h iup_stdcontrols.h gtk/iupgtk_drv.h +$(OBJDIR)/iupgtk_menu.o: gtk/iupgtk_menu.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h iup_object.h iup_class.h \ + iup_table.h iup_classbase.h iup_childtree.h iup_attrib.h iup_dialog.h \ + iup_str.h iup_label.h iup_drv.h iup_drvfont.h iup_image.h iup_menu.h \ + gtk/iupgtk_drv.h +$(OBJDIR)/iupgtk_help.o: gtk/iupgtk_help.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h iup_str.h +$(OBJDIR)/iupunix_info.o: mot/iupunix_info.c iup_str.h iup_drvinfo.h diff --git a/iup/src/iupstub.mak b/iup/src/iupstub.mak new file mode 100755 index 0000000..9ca920f --- /dev/null +++ b/iup/src/iupstub.mak @@ -0,0 +1,12 @@ +PROJNAME = iup +LIBNAME = iupstub +OPT = YES + +USE_DLL = Yes + +INCLUDES = ../include + +SRC = win/iupwindows_main.c + +iupstup-dll: + @move /y ..\lib\vc6\iupstub.lib ..\lib\dll diff --git a/iup/src/make_uname b/iup/src/make_uname new file mode 100755 index 0000000..7fec9f8 --- /dev/null +++ b/iup/src/make_uname @@ -0,0 +1,4 @@ +#This builds all the libraries of the folder for 1 uname + +tecmake $1 $2 $3 $4 $5 $6 $7 +tecmake USE_GTK=Yes $1 $2 $3 $4 $5 $6 $7 diff --git a/iup/src/make_uname.bat b/iup/src/make_uname.bat new file mode 100755 index 0000000..1a79780 --- /dev/null +++ b/iup/src/make_uname.bat @@ -0,0 +1,55 @@ +@echo off +REM This builds all the libraries of the folder for 1 uname + +call tecmake %1 %2 %3 %4 %5 %6 +call tecmake %1 "USE_GTK=Yes" %2 %3 %4 %5 %6 + +if "%1"=="dll" goto stub_dll +if "%1"=="dll7" goto stub_dll7 +if "%1"=="dll8" goto stub_dll8 +if "%1"=="dll8_64" goto stub_dll8_64 +if "%1"=="dll9" goto stub_dll9 +if "%1"=="dll9_64" goto stub_dll9_64 +if "%1"=="all" goto all_dll +goto fim + +:stub_dll +call tecmake vc6 "MF=iupstub" %2 %3 %4 %5 %6 %7 +move /y ..\lib\vc6\iupstub.lib ..\lib\dll +goto fim + +:stub_dll7 +call tecmake vc7 "MF=iupstub" %2 %3 %4 %5 %6 %7 +move /y ..\lib\vc7\iupstub.lib ..\lib\dll7 +goto fim + +:stub_dll8 +call tecmake vc8 "MF=iupstub" %2 %3 %4 %5 %6 %7 +move /y ..\lib\vc8\iupstub.lib ..\lib\dll8 +goto fim + +:stub_dll8_64 +call tecmake vc8_64 "MF=iupstub" %2 %3 %4 %5 %6 %7 +move /y ..\lib\vc8_64\iupstub.lib ..\lib\dll8_64 +goto fim + +:stub_dll9 +call tecmake vc9 "MF=iupstub" %2 %3 %4 %5 %6 %7 +move /y ..\lib\vc9\iupstub.lib ..\lib\dll9 +goto fim + +:stub_dll9_64 +call tecmake vc9_64 "MF=iupstub" %2 %3 %4 %5 %6 %7 +move /y ..\lib\vc9_64\iupstub.lib ..\lib\dll9_64 +goto fim + +:all_dll +call make_uname dll %2 %3 %4 %5 %6 +call make_uname dll7 %2 %3 %4 %5 %6 +call make_uname dll8 %2 %3 %4 %5 %6 +call make_uname dll8_64 %2 %3 %4 %5 %6 +call make_uname dll9 %2 %3 %4 %5 %6 +call make_uname dll9_64 %2 %3 %4 %5 %6 +goto fim + +:fim diff --git a/iup/src/mot/iupmot_button.c b/iup/src/mot/iupmot_button.c new file mode 100755 index 0000000..2d93588 --- /dev/null +++ b/iup/src/mot/iupmot_button.c @@ -0,0 +1,301 @@ +/** \file + * \brief Button Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/PushB.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_button.h" +#include "iup_drv.h" +#include "iup_image.h" +#include "iup_key.h" + +#include "iupmot_drv.h" + + +void iupdrvButtonAddBorders(int *x, int *y) +{ + int border_size = 2*5; + (*x) += border_size; + (*y) += border_size; +} + +static int motButtonSetTitleAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_BUTTON_TEXT) + { + iupmotSetMnemonicTitle(ih, value); + return 1; + } + + return 0; +} + +static int motButtonSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + unsigned char align; + char value1[30]="", value2[30]=""; + + iupStrToStrStr(value, value1, value2, ':'); /* value2 is ignored, NOT supported in Motif */ + + if (iupStrEqualNoCase(value1, "ARIGHT")) + align = XmALIGNMENT_END; + else if (iupStrEqualNoCase(value1, "ACENTER")) + align = XmALIGNMENT_CENTER; + else /* "ALEFT" */ + align = XmALIGNMENT_BEGINNING; + + XtVaSetValues (ih->handle, XmNalignment, align, NULL); + return 1; +} + +static int motButtonSetImageAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_BUTTON_IMAGE) + { + iupmotSetPixmap(ih, value, XmNlabelPixmap, 0); + + if (!iupAttribGet(ih, "IMINACTIVE")) + { + /* if not active and IMINACTIVE is not defined + then automaticaly create one based on IMAGE */ + iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 1); /* make_inactive */ + } + return 1; + } + else + return 0; +} + +static int motButtonSetImInactiveAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_BUTTON_IMAGE) + { + iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 0); + return 1; + } + else + return 0; +} + +static int motButtonSetImPressAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_BUTTON_IMAGE) + { + iupmotSetPixmap(ih, value, XmNarmPixmap, 0); + return 1; + } + else + return 0; +} + +static int motButtonSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle) + { + XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); + } + return 0; +} + +static int motButtonSetBgColorAttrib(Ihandle* ih, const char* value) +{ + if (iupAttribGet(ih, "IMPRESS") || iupAttribGetBoolean(ih, "FLAT")) + { + /* ignore given value, must use only from parent */ + value = iupBaseNativeParentGetBgColor(ih); + + if (iupdrvBaseSetBgColorAttrib(ih, value)) + return 1; + } + + return iupdrvBaseSetBgColorAttrib(ih, value); +} + +static int motButtonSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + if (iupAttribGet(ih, "IMPRESS") || iupAttribGetBoolean(ih, "FLAT")) + { + /* ignore given value, must use only from parent */ + value = iupAttribGetInheritNativeParent(ih, "BACKGROUND"); + + if (iupdrvBaseSetBgColorAttrib(ih, value)) + return 1; + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + if (pixmap) + { + XtVaSetValues(ih->handle, XmNbackgroundPixmap, pixmap, NULL); + return 1; + } + } + } + return 0; +} + +static void motButtonActivateCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + Icallback cb; + + /* Must manually hide the tip if the button is pressed. */ + iupmotTipLeaveNotify(); + + cb = IupGetCallback(ih, "ACTION"); + if (cb) + { + if (cb(ih) == IUP_CLOSE) + IupExitLoop(); + } + (void)w; + (void)call_data; +} + +static void motButtonEnterLeaveWindowEvent(Widget w, Ihandle* ih, XEvent *evt, Boolean *cont) +{ + iupmotEnterLeaveWindowEvent(w, ih, evt, cont); + + if (evt->type == EnterNotify) + XtVaSetValues(ih->handle, XmNshadowThickness, 2, NULL); + else if (evt->type == LeaveNotify) + XtVaSetValues(ih->handle, XmNshadowThickness, 0, NULL); +} + +static int motButtonMapMethod(Ihandle* ih) +{ + char* value; + int num_args = 0; + Arg args[30]; + + value = iupAttribGet(ih, "IMAGE"); + if (value) + { + ih->data->type = IUP_BUTTON_IMAGE; + iupmotSetArg(args, num_args, XmNlabelType, XmPIXMAP); + } + else + { + ih->data->type = IUP_BUTTON_TEXT; + iupmotSetArg(args, num_args, XmNlabelType, XmSTRING); + } + + /* Core */ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Label */ + iupmotSetArg(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNmarginTop, 0); /* no extra margins */ + iupmotSetArg(args, num_args, XmNmarginLeft, 0); + iupmotSetArg(args, num_args, XmNmarginBottom, 0); + iupmotSetArg(args, num_args, XmNmarginRight, 0); + /* PushButton */ + iupmotSetArg(args, num_args, XmNfillOnArm, False); + + /* Primitive */ + if (iupAttribGetBoolean(ih, "FOCUSONCLICK")) + { + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + } + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupmotSetArg(args, num_args, XmNhighlightThickness, 2); + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + xmPushButtonWidgetClass, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + + value = iupAttribGet(ih, "IMPRESS"); + if (iupAttribGetBoolean(ih, "FLAT") && !value) + { + XtVaSetValues(ih->handle, XmNshadowThickness, 0, NULL); + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)motButtonEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)motButtonEnterLeaveWindowEvent, (XtPointer)ih); + } + else + { + if (value && !iupAttribGetStr(ih, "IMPRESSBORDER")) + XtVaSetValues(ih->handle, XmNshadowThickness, 0, NULL); + else + XtVaSetValues(ih->handle, XmNshadowThickness, 2, NULL); + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + } + + XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + + XtAddCallback(ih->handle, XmNactivateCallback, (XtCallbackProc)motButtonActivateCallback, (XtPointer)ih); + XtAddEventHandler(ih->handle, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)iupmotButtonPressReleaseEvent, (XtPointer)ih); + + /* Disable Drag Source */ + iupmotDisableDragSource(ih->handle); + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + if (ih->data->type == IUP_BUTTON_TEXT) + iupmotSetString(ih->handle, XmNlabelString, ""); + + return IUP_NOERROR; +} + +void iupdrvButtonInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motButtonMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", iupmotGetBgColorAttrib, motButtonSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motButtonSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "TITLE", NULL, motButtonSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupButton only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, motButtonSetAlignmentAttrib, "ACENTER:ACENTER", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "IMAGE", NULL, motButtonSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, motButtonSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMPRESS", NULL, motButtonSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FOCUSONCLICK", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "PADDING", iupButtonGetPaddingAttrib, motButtonSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); +} diff --git a/iup/src/mot/iupmot_canvas.c b/iup/src/mot/iupmot_canvas.c new file mode 100755 index 0000000..7777cf3 --- /dev/null +++ b/iup/src/mot/iupmot_canvas.c @@ -0,0 +1,639 @@ +/** \file + * \brief Canvas Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/ScrolledW.h> +#include <Xm/DrawingA.h> +#include <Xm/ScrollBar.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_canvas.h" +#include "iup_key.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + + +static void motDialogScrollbarCallback(Widget w, XtPointer client_data, XtPointer call_data) +{ + int op = (int)client_data, ipage, ipos; + Ihandle *ih; + IFniff cb; + double posx, posy; + (void)call_data; + + XtVaGetValues(w, XmNuserData, &ih, NULL); + if (!ih) return; + + XtVaGetValues(w, + XmNvalue, &ipos, + XmNpageIncrement, &ipage, + NULL); + + if (op > IUP_SBDRAGV) + { + iupCanvasCalcScrollRealPos(iupAttribGetFloat(ih,"XMIN"), iupAttribGetFloat(ih,"XMAX"), &posx, + IUP_SB_MIN, IUP_SB_MAX, ipage, &ipos); + ih->data->posx = (float)posx; + posy = ih->data->posy; + } + else + { + iupCanvasCalcScrollRealPos(iupAttribGetFloat(ih,"YMIN"), iupAttribGetFloat(ih,"YMAX"), &posy, + IUP_SB_MIN, IUP_SB_MAX, ipage, &ipos); + ih->data->posy = (float)posy; + posx = ih->data->posx; + } + + cb = (IFniff)IupGetCallback(ih,"SCROLL_CB"); + if (cb) + cb(ih, op, (float)posx, (float)posy); + else + { + IFnff cb = (IFnff)IupGetCallback(ih,"ACTION"); + if (cb) + cb (ih, (float)posx, (float)posy); + } +} + +static void motCanvasResizeCallback(Widget w, Ihandle *ih, XtPointer call_data) +{ + Dimension width, height; + IFnii cb; + (void)call_data; + + if (!XtWindow(w) || !ih) return; + + /* client size */ + XtVaGetValues(w, XmNwidth, &width, + XmNheight, &height, + NULL); + + cb = (IFnii)IupGetCallback(ih,"RESIZE_CB"); + if (cb) + cb(ih,width,height); +} + +static int motCanvasSetBgColorAttrib(Ihandle* ih, const char* value); + +static void motCanvasExposeCallback(Widget w, Ihandle *ih, XtPointer call_data) +{ + IFnff cb; + (void)call_data; + + if (!XtWindow(w) || !ih) return; + + cb = (IFnff)IupGetCallback(ih,"ACTION"); + if (cb) + { + if (!iupAttribGet(ih, "_IUPMOT_NO_BGCOLOR")) + motCanvasSetBgColorAttrib(ih, iupAttribGetStr(ih, "BGCOLOR")); /* reset to update window attributes */ + + cb (ih, ih->data->posx, ih->data->posy); + } +} + +static void motCanvasInputCallback(Widget w, Ihandle *ih, XtPointer call_data) +{ + XEvent *evt = ((XmDrawingAreaCallbackStruct*)call_data)->event; + + if (!XtWindow(w) || !ih) return; + + switch (evt->type) + { + case ButtonPress: + /* Force focus on canvas click */ + if (iupAttribGetBoolean(ih, "CANFOCUS")) + XmProcessTraversal(w, XmTRAVERSE_CURRENT); + /* break missing on purpose... */ + case ButtonRelease: + { + XButtonEvent *but_evt = (XButtonEvent*)evt; + Boolean cont = True; + iupmotButtonPressReleaseEvent(w, ih, evt, &cont); + if (cont == False) + return; + + if ((evt->type==ButtonPress) && (but_evt->button==Button4 || but_evt->button==Button5)) + { + IFnfiis wcb = (IFnfiis)IupGetCallback(ih, "WHEEL_CB"); + if (wcb) + { + char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; + int delta = but_evt->button==Button4? 1: -1; + iupmotButtonKeySetStatus(but_evt->state, but_evt->button, status, 0); + + wcb(ih, (float)delta, but_evt->x, but_evt->y, status); + } + else + { + IFniff scb = (IFniff)IupGetCallback(ih,"SCROLL_CB"); + float posy = ih->data->posy; + int delta = but_evt->button==Button4? 1: -1; + int op = but_evt->button==Button4? IUP_SBUP: IUP_SBDN; + posy -= delta*iupAttribGetFloat(ih, "DY")/10.0f; + IupSetfAttribute(ih, "POSY", "%g", posy); + if (scb) + scb(ih,op,ih->data->posx,ih->data->posy); + } + } + } + break; + } +} + +static void motCanvasSetScrollInfo(Widget sb, int imin, int imax, int ipos, int ipage, int iline) +{ + XtVaSetValues(sb, + XmNminimum, imin, + XmNmaximum, imax, + XmNvalue, ipos, + XmNincrement, iline, + XmNpageIncrement, ipage, + XmNsliderSize, ipage, /* to make the thumb proportional */ + NULL); +} + +static int motCanvasSetDXAttrib(Ihandle* ih, const char *value) +{ + if (ih->data->sb & IUP_SB_HORIZ) + { + double posx, xmin, xmax, linex; + float dx; + int iposx, ipagex, ilinex; + Widget sb_horiz, sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb_horiz, NULL); + if (!sb_horiz) return 1; + + if (!iupStrToFloat(value, &dx)) + return 1; + + xmin = iupAttribGetFloat(ih, "XMIN"); + xmax = iupAttribGetFloat(ih, "XMAX"); + posx = ih->data->posx; + + iupCanvasCalcScrollIntPos(xmin, xmax, dx, posx, + IUP_SB_MIN, IUP_SB_MAX, &ipagex, &iposx); + + if (!iupAttribGet(ih,"LINEX")) + { + ilinex = ipagex/10; + if (!ilinex) + ilinex = 1; + } + else + { + /* line and page convertions are the same */ + linex = iupAttribGetFloat(ih,"LINEX"); + iupCanvasCalcScrollIntPos(xmin, xmax, linex, 0, + IUP_SB_MIN, IUP_SB_MAX, &ilinex, NULL); + } + + if (dx >= (xmax-xmin)) + { + if (iupAttribGetBoolean(ih, "XAUTOHIDE")) + XtUnmanageChild(sb_horiz); + else + XtSetSensitive(sb_horiz, 0); + return 1; + } + else + { + if (!XtIsManaged(sb_horiz)) + XtManageChild(sb_horiz); + XtSetSensitive(sb_horiz, 1); + } + + motCanvasSetScrollInfo(sb_horiz, IUP_SB_MIN, IUP_SB_MAX, iposx, ipagex, ilinex); + + /* update position because it could be corrected */ + iupCanvasCalcScrollRealPos(xmin, xmax, &posx, + IUP_SB_MIN, IUP_SB_MAX, ipagex, &iposx); + + ih->data->posx = (float)posx; + } + return 1; +} + +static int motCanvasSetPosXAttrib(Ihandle* ih, const char *value) +{ + if (ih->data->sb & IUP_SB_HORIZ) + { + double xmin, xmax, dx; + float posx; + int iposx, ipagex; + Widget sb_horiz, sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb_horiz, NULL); + if (!sb_horiz) return 1; + + if (!iupStrToFloat(value, &posx)) + return 1; + + xmin = iupAttribGetFloat(ih, "XMIN"); + xmax = iupAttribGetFloat(ih, "XMAX"); + dx = iupAttribGetFloat(ih, "DX"); + + if (posx < xmin) posx = (float)xmin; + if (posx > (xmax - dx)) posx = (float)(xmax - dx); + ih->data->posx = posx; + + iupCanvasCalcScrollIntPos(xmin, xmax, dx, posx, + IUP_SB_MIN, IUP_SB_MAX, &ipagex, &iposx); + + XtVaSetValues(sb_horiz, XmNvalue, iposx, NULL); + } + return 1; +} + +static int motCanvasSetDYAttrib(Ihandle* ih, const char *value) +{ + if (ih->data->sb & IUP_SB_VERT) + { + double posy, ymin, ymax, liney; + float dy; + int iposy, ipagey, iliney; + Widget sb_vert, sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + XtVaGetValues(sb_win, XmNverticalScrollBar, &sb_vert, NULL); + if (!sb_vert) return 1; + + if (!iupStrToFloat(value, &dy)) + return 1; + + ymin = iupAttribGetFloat(ih, "YMIN"); + ymax = iupAttribGetFloat(ih, "YMAX"); + posy = ih->data->posy; + + iupCanvasCalcScrollIntPos(ymin, ymax, dy, posy, + IUP_SB_MIN, IUP_SB_MAX, &ipagey, &iposy); + + if (!iupAttribGet(ih,"LINEY")) + { + iliney = ipagey/10; + if (!iliney) + iliney = 1; + } + else + { + /* line and page convertions are the same */ + liney = iupAttribGetFloat(ih,"LINEY"); + iupCanvasCalcScrollIntPos(ymin, ymax, liney, 0, + IUP_SB_MIN, IUP_SB_MAX, &iliney, NULL); + } + + if (dy >= (ymax-ymin)) + { + if (iupAttribGetBoolean(ih, "YAUTOHIDE")) + XtUnmanageChild(sb_vert); + else + XtSetSensitive(sb_vert, 0); + return 1; + } + else + { + if (!XtIsManaged(sb_vert)) + XtManageChild(sb_vert); + XtSetSensitive(sb_vert, 1); + } + + motCanvasSetScrollInfo(sb_vert, IUP_SB_MIN, IUP_SB_MAX, iposy, ipagey, iliney); + + /* update position because it could be corrected */ + iupCanvasCalcScrollRealPos(ymin, ymax, &posy, + IUP_SB_MIN, IUP_SB_MAX, ipagey, &iposy); + + ih->data->posy = (float)posy; + } + return 1; +} + +static int motCanvasSetPosYAttrib(Ihandle* ih, const char *value) +{ + if (ih->data->sb & IUP_SB_VERT) + { + double ymin, ymax, dy; + float posy; + int iposy, ipagey; + Widget sb_vert, sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + XtVaGetValues(sb_win, XmNverticalScrollBar, &sb_vert, NULL); + if (!sb_vert) return 1; + + if (!iupStrToFloat(value, &posy)) + return 1; + + ymin = iupAttribGetFloat(ih, "YMIN"); + ymax = iupAttribGetFloat(ih, "YMAX"); + dy = iupAttribGetFloat(ih, "DY"); + + if (posy < ymin) posy = (float)ymin; + if (posy > (ymax - dy)) posy = (float)(ymax - dy); + ih->data->posy = posy; + + iupCanvasCalcScrollIntPos(ymin, ymax, dy, posy, + IUP_SB_MIN, IUP_SB_MAX, &ipagey, &iposy); + + XtVaSetValues(sb_vert, XmNvalue, iposy, NULL); + } + return 1; +} + +static char* motCanvasGetXDisplayAttrib(Ihandle *ih) +{ + (void)ih; + return (char*)iupmot_display; +} + +static char* motCanvasGetXScreenAttrib(Ihandle *ih) +{ + (void)ih; + return (char*)iupmot_screen; +} + +static char* motCanvasGetXWindowAttrib(Ihandle *ih) +{ + return (char*)XtWindow(ih->handle); +} + +static char* motCanvasGetClientSizeAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(20); + + Dimension width, height; + XtVaGetValues(ih->handle, XmNwidth, &width, + XmNheight, &height, + NULL); + + sprintf(str, "%dx%d", (int)width, (int)height); + return str; +} + +static int motCanvasSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color; + + /* ignore given value, must use only from parent for the scrollbars */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + color = iupmotColorGetPixelStr(parent_value); + if (color != (Pixel)-1) + { + Widget sb; + Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + + iupmotSetBgColor(sb_win, color); + + XtVaGetValues(sb_win, XmNverticalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + + XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + } + + if (!IupGetCallback(ih, "ACTION")) + iupdrvBaseSetBgColorAttrib(ih, value); /* Use the given value only here */ + else + { + XSetWindowAttributes attrs; + attrs.background_pixmap = None; + XChangeWindowAttributes(iupmot_display, XtWindow(ih->handle), CWBackPixmap, &attrs); + iupAttribSetStr(ih, "_IUPMOT_NO_BGCOLOR", "1"); + } + + return 1; +} + +static void motCanvasLayoutUpdateMethod(Ihandle *ih) +{ + Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + Dimension border; + + /* IMPORTANT: + The ScrolledWindow border, added by the Core, is NOT included in the Motif size. + So when setting the size, we must compensate the border, + so the actual size will be the size we expect. + */ + + XtVaGetValues(sb_win, XmNborderWidth, &border, NULL); + + XtVaSetValues(sb_win, + XmNx, (XtArgVal)ih->x, + XmNy, (XtArgVal)ih->y, + XmNwidth, (XtArgVal)(ih->currentwidth-2*border), + XmNheight, (XtArgVal)(ih->currentheight-2*border), + NULL); +} + +static int motCanvasMapMethod(Ihandle* ih) +{ + Widget sb_win; + char *visual; + int num_args = 0; + Arg args[20]; + + if (!ih->parent) + return IUP_ERROR; + + ih->data->sb = iupBaseGetScrollbar(ih); + + /******************************/ + /* Create the scrolled window */ + /******************************/ + + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); + iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE); + iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and draw area */ + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + + if (iupAttribGetBoolean(ih, "BORDER")) + { + iupmotSetArg(args, num_args, XmNborderWidth, 1); + iupmotSetArg(args, num_args, XmNborderColor, iupmotColorGetPixelStr("0 0 0")); + } + else + iupmotSetArg(args, num_args, XmNborderWidth, 0); + + sb_win = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + xmScrolledWindowWidgetClass, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!sb_win) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + /****************************/ + /* Create the drawing area */ + /****************************/ + + num_args = 0; + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* no shadow margins */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); /* no shadow margins */ + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupmotSetArg(args, num_args, XmNresizePolicy, XmRESIZE_NONE); /* no automatic resize of children */ + if (ih->iclass->is_interactive) + { + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); /* include in navigation */ + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + } + else + { + iupmotSetArg(args, num_args, XmNnavigationType, XmNONE); + iupmotSetArg(args, num_args, XmNtraversalOn, False); + } + + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + + visual = IupGetAttribute(ih, "VISUAL"); /* defined by the OpenGL Canvas or NULL */ + if (visual) + { + Colormap colormap = (Colormap)iupAttribGet(ih, "COLORMAP"); + if (colormap) + iupmotSetArg(args, num_args, XmNcolormap,colormap); + + iupmotDialogSetVisual(ih, visual); + } + + ih->handle = XtCreateManagedWidget( + "draw_area", /* child identifier */ + xmDrawingAreaWidgetClass, /* widget class */ + sb_win, /* widget parent */ + args, num_args); + + if (!ih->handle) + { + XtDestroyWidget(sb_win); + return IUP_ERROR; + } + + if (visual) + iupmotDialogResetVisual(ih); + + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)sb_win); + XtVaSetValues(sb_win, XmNworkWindow, ih->handle, NULL); + + { + XSetWindowAttributes attrs; + attrs.bit_gravity = ForgetGravity; /* For the DrawingArea widget gets Expose events when you resize it to be smaller. */ + + if (iupAttribGetBoolean(ih, "BACKINGSTORE")) + attrs.backing_store = WhenMapped; + else + attrs.backing_store = NotUseful; + + XChangeWindowAttributes(iupmot_display, XtWindow(ih->handle), CWBitGravity|CWBackingStore, &attrs); + } + + if (ih->data->sb & IUP_SB_HORIZ) + { + Widget sb_horiz = XtVaCreateManagedWidget("sb_horiz", + xmScrollBarWidgetClass, sb_win, + XmNorientation, XmHORIZONTAL, + XmNsliderMark, XmTHUMB_MARK, + XmNuserData, ih, + NULL); + + XtAddCallback(sb_horiz, XmNvalueChangedCallback, motDialogScrollbarCallback, (void*)IUP_SBPOSH); + XtAddCallback(sb_horiz, XmNdragCallback, motDialogScrollbarCallback, (void*)IUP_SBDRAGH); + XtAddCallback(sb_horiz, XmNdecrementCallback, motDialogScrollbarCallback, (void*)IUP_SBLEFT); + XtAddCallback(sb_horiz, XmNincrementCallback, motDialogScrollbarCallback, (void*)IUP_SBRIGHT); + XtAddCallback(sb_horiz, XmNpageDecrementCallback, motDialogScrollbarCallback, (void*)IUP_SBPGLEFT); + XtAddCallback(sb_horiz, XmNpageIncrementCallback, motDialogScrollbarCallback, (void*)IUP_SBPGRIGHT); + + XtVaSetValues(sb_win, XmNhorizontalScrollBar, sb_horiz, NULL); + } + + if (ih->data->sb & IUP_SB_VERT) + { + Widget sb_vert = XtVaCreateManagedWidget("sb_vert", + xmScrollBarWidgetClass, sb_win, + XmNorientation, XmVERTICAL, + XmNsliderMark, XmTHUMB_MARK, + XmNuserData, ih, + NULL); + + XtAddCallback(sb_vert, XmNvalueChangedCallback, motDialogScrollbarCallback, (void*)IUP_SBPOSV); + XtAddCallback(sb_vert, XmNdragCallback, motDialogScrollbarCallback, (void*)IUP_SBDRAGV); + XtAddCallback(sb_vert, XmNdecrementCallback, motDialogScrollbarCallback, (void*)IUP_SBUP); + XtAddCallback(sb_vert, XmNincrementCallback, motDialogScrollbarCallback, (void*)IUP_SBDN); + XtAddCallback(sb_vert, XmNpageDecrementCallback, motDialogScrollbarCallback, (void*)IUP_SBPGUP); + XtAddCallback(sb_vert, XmNpageIncrementCallback, motDialogScrollbarCallback, (void*)IUP_SBPGDN); + + XtVaSetValues(sb_win, XmNverticalScrollBar, sb_vert, NULL); + } + + XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNexposeCallback, (XtCallbackProc)motCanvasExposeCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNresizeCallback, (XtCallbackProc)motCanvasResizeCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNinputCallback, (XtCallbackProc)motCanvasInputCallback, (XtPointer)ih); + + XtAddEventHandler(ih->handle, EnterWindowMask, False,(XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False,(XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + + XtAddEventHandler(ih->handle, FocusChangeMask, False,(XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyReleaseMask, False, (XtEventHandler)iupmotCanvasKeyReleaseEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, PointerMotionMask, False, (XtEventHandler)iupmotPointerMotionEvent, (XtPointer)ih); + + /* initialize the widget */ + XtRealizeWidget(sb_win); + + return IUP_NOERROR; +} + +void iupdrvCanvasInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motCanvasMapMethod; + ic->LayoutUpdate = motCanvasLayoutUpdateMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motCanvasSetBgColorAttrib, "255 255 255", NULL, IUPAF_DEFAULT); /* force new default value */ + + /* IupCanvas only */ + iupClassRegisterAttribute(ic, "DRAWSIZE", motCanvasGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CURSOR", NULL, iupdrvBaseSetCursorAttrib, IUPAF_SAMEASSYSTEM, "ARROW", IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "DX", NULL, motCanvasSetDXAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "DY", NULL, motCanvasSetDYAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "POSX", iupCanvasGetPosXAttrib, motCanvasSetPosXAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "POSY", iupCanvasGetPosYAttrib, motCanvasSetPosYAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "YAUTOHIDE", NULL, NULL, "YES", NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "XAUTOHIDE", NULL, NULL, "YES", NULL, IUPAF_NOT_MAPPED); + + /* IupCanvas X only */ + iupClassRegisterAttribute(ic, "XWINDOW", motCanvasGetXWindowAttrib, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "XDISPLAY", motCanvasGetXDisplayAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "XSCREEN", motCanvasGetXScreenAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "BACKINGSTORE", NULL, NULL, "YES", NULL, IUPAF_NOT_MAPPED); +} diff --git a/iup/src/mot/iupmot_clipboard.c b/iup/src/mot/iupmot_clipboard.c new file mode 100755 index 0000000..43a0087 --- /dev/null +++ b/iup/src/mot/iupmot_clipboard.c @@ -0,0 +1,208 @@ +/** \file + * \brief Clipboard for the Motif Driver. + * + * See Copyright Notice in "iup.h" + */ + + +#include <stdio.h> +#include <stdlib.h> + +#include <Xm/Xm.h> +#include <Xm/CutPaste.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_image.h" + +#include "iupmot_drv.h" + + +static Window motClipboardGetWindow(void) +{ + Ihandle* focus = IupGetFocus(); + Ihandle* dlg; + if (!focus) return (Window)NULL; + dlg = IupGetDialog(focus); + if (dlg) + return XtWindow(dlg->handle); + else + return (Window)NULL; +} + +static int motClipboardSetTextAttrib(Ihandle *ih, const char *value) +{ + long item_id = 0; + Window window = motClipboardGetWindow(); + XmString clip_label = XmStringCreateLocalized ("IupClipboard"); + (void)ih; + + if (XmClipboardStartCopy(iupmot_display, window, clip_label, CurrentTime, NULL, NULL, &item_id)!=ClipboardSuccess) + { + XmStringFree(clip_label); + return 0; + } + + XmStringFree(clip_label); + + XmClipboardCopy(iupmot_display, window, item_id, "STRING", (char*)value, (long)strlen(value)+1, 0, NULL); + XmClipboardEndCopy(iupmot_display, window, item_id); + return 0; +} + +static char* motClipboardGetTextAttrib(Ihandle *ih) +{ + unsigned long size; + char* str; + Window window = motClipboardGetWindow(); + (void)ih; + + if (XmClipboardInquireLength(iupmot_display, window, "STRING", &size)!=ClipboardSuccess) + return NULL; + + str = iupStrGetMemory(size+1); + + if (XmClipboardRetrieve(iupmot_display, window, "STRING", str, size+1, NULL, NULL)!=ClipboardSuccess) + return NULL; + + return str; +} + +static int motClipboardSetImageAttrib(Ihandle *ih, const char *value) +{ + Pixmap pixmap; + long item_id = 0; + Window window = motClipboardGetWindow(); + XmString clip_label = XmStringCreateLocalized ("IupClipboard"); + + if (XmClipboardStartCopy(iupmot_display, window, clip_label, CurrentTime, NULL, NULL, &item_id)!=ClipboardSuccess) + { + XmStringFree(clip_label); + return 0; + } + + XmStringFree(clip_label); + + pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + + XmClipboardCopy(iupmot_display, window, item_id, "PIXMAP", (char*)&pixmap, sizeof(Pixmap), 0, NULL); + XmClipboardEndCopy(iupmot_display, window, item_id); + + (void)ih; + return 0; +} + +static int motClipboardSetNativeImageAttrib(Ihandle *ih, const char *value) +{ + long item_id = 0; + Window window = motClipboardGetWindow(); + XmString clip_label = XmStringCreateLocalized ("IupClipboard"); + Pixmap pixmap = (Pixmap)value; + + if (XmClipboardStartCopy(iupmot_display, window, clip_label, CurrentTime, NULL, NULL, &item_id)!=ClipboardSuccess) + { + XmStringFree(clip_label); + return 0; + } + + XmStringFree(clip_label); + + XmClipboardCopy(iupmot_display, window, item_id, "PIXMAP", (char*)&pixmap, sizeof(Pixmap), 0, NULL); + XmClipboardEndCopy(iupmot_display, window, item_id); + + (void)ih; + return 0; +} + +static char* motClipboardGetNativeImageAttrib(Ihandle *ih) +{ + unsigned long size; + void* data; + Pixmap pixmap; + Window window = motClipboardGetWindow(); + (void)ih; + + if (XmClipboardInquireLength(iupmot_display, window, "PIXMAP", &size)!=ClipboardSuccess) + return NULL; + + data = XtMalloc(size); + + if (XmClipboardRetrieve(iupmot_display, window, "PIXMAP", data, size, NULL, NULL)!=ClipboardSuccess) + return NULL; + + pixmap = *((Pixmap*)data); + XtFree(data); + return (char*)pixmap; +} + +static int motClipboardIsAvailable(const char* format_name) +{ + Window window = motClipboardGetWindow(); + int count, i; + unsigned long max_length, length; + char* str; + + if (XmClipboardInquireCount(iupmot_display, window, &count, &max_length) != ClipboardSuccess) + return 0; + + str = iupStrGetMemory(max_length+1); + + for (i = 1; i<=count; i++) + { + if (XmClipboardInquireFormat(iupmot_display, window, i, str, max_length+1, &length)==ClipboardSuccess) + { + if (iupStrEqualNoCase(str, format_name)) + return 1; + } + } + + return 0; +} + +static char* motClipboardGetTextAvailableAttrib(Ihandle *ih) +{ + (void)ih; + if (motClipboardIsAvailable("STRING")) + return "YES"; + else + return "NO"; +} + +static char* motClipboardGetImageAvailableAttrib(Ihandle *ih) +{ + (void)ih; + if (motClipboardIsAvailable("PIXMAP")) + return "YES"; + else + return "NO"; +} + +/******************************************************************************/ + +Ihandle* IupClipboard(void) +{ + return IupCreate("clipboard"); +} + +Iclass* iupClipboardGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "clipboard"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPECONTROL; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 0; + + /* Attribute functions */ + iupClassRegisterAttribute(ic, "TEXT", motClipboardGetTextAttrib, motClipboardSetTextAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NATIVEIMAGE", motClipboardGetNativeImageAttrib, motClipboardSetNativeImageAttrib, NULL, NULL, IUPAF_NO_STRING|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE", NULL, motClipboardSetImageAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TEXTAVAILABLE", motClipboardGetTextAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGEAVAILABLE", motClipboardGetImageAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} diff --git a/iup/src/mot/iupmot_color.c b/iup/src/mot/iupmot_color.c new file mode 100755 index 0000000..276bccc --- /dev/null +++ b/iup/src/mot/iupmot_color.c @@ -0,0 +1,380 @@ +/** \file + * \brief Motif Driver color management + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> + +#include <Xm/Xm.h> +#include <X11/Xproto.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drvinfo.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + + +/* local variables */ + +typedef struct _Icolor +{ + Colormap colormap; /* colormap for all canvas, dialogs and menus */ + XColor color_table[256]; /* colormap colors */ + int num_colors; /* number of colors in colormap */ + + int rshift; /* red shift for truecolor */ + int gshift; /* green shift for truecolor */ + int bshift; /* blue shift for truecolor */ + + int direct_conv[256]; /* used with directColor visuals */ +} Icolor; + +static Icolor mot_color; + + +/******************************************* + NOT TrueColor Functions +*******************************************/ + +static int motColor8BppErrorHandler(Display* dpy, XErrorEvent *err) +{ + char msg[80]; + + /* BadAcess in XFreeColors is OK */ + if (err->request_code==X_FreeColors && err->error_code==BadAccess) + return 0; + + XGetErrorText(dpy, err->error_code, msg, 80 ); + fprintf(stderr,"IUP Motif error handler: Xlib request %d: %s\n", err->request_code, msg); + + return 0; +} + +static unsigned long motColorNearestRGB(XColor* xc1) +{ + static int nearest_try = 0; + + int pos = 0, i; + unsigned long min_dist = ULONG_MAX, this_dist; + int dr, dg, db; + XColor* xc2; + + for (i=0; i<mot_color.num_colors; i++) + { + xc2 = &(mot_color.color_table[i]); + + dr = (xc1->red - xc2->red) / 850; /* 0.30 / 255 */ + dg = (xc1->green - xc2->green) / 432; /* 0.59 / 255 */ + db = (xc1->blue - xc2->blue) / 2318; /* 0.11 / 255 */ + + this_dist = dr*dr + dg*dg + db*db; + + if (this_dist < min_dist) + { + min_dist = this_dist; + pos = i; + } + } + + /* verifico se a cor ainda esta alocada */ + /* Try to allocate the closest match color. This should only + fail if the cell is read/write. Otherwise, we're incrementing + the cell's reference count. (comentario extraido da biblioteca Mesa) */ + if (!XAllocColor(iupmot_display, mot_color.colormap, + &(mot_color.color_table[pos]))) + { + /* nao esta, preciso atualizar a tabela e procurar novamente */ + /* isto acontece porque a cor encontrada pode ter sido de uma aplicacao que nao existe mais */ + /* uma vez atualizada, o problema nao ocorrera' na nova procura */ + /* ou a celula e' read write */ + + if (nearest_try == 1) + { + nearest_try = 0; + return mot_color.color_table[pos].pixel; + } + + XQueryColors(iupmot_display, mot_color.colormap, mot_color.color_table, mot_color.num_colors); + + nearest_try = 1; /* garante que so' vai tentar isso uma vez */ + return motColorNearestRGB(xc1); + } + + return mot_color.color_table[pos].pixel; +} + +static unsigned long motColorGetPixel_NotTrueColor(unsigned char cr, unsigned char cg, unsigned char cb) +{ + unsigned long pixel; + XColor xc; + xc.red = iupCOLOR8TO16(cr); + xc.green = iupCOLOR8TO16(cg); + xc.blue = iupCOLOR8TO16(cb); + xc.flags = DoRed | DoGreen | DoBlue; + + /* verificamos se a nova cor ja' esta' disponivel */ + if (!XAllocColor(iupmot_display, mot_color.colormap, &xc)) + { + /* nao estava disponivel, procuro pela mais proxima na tabela de cores */ + pixel = motColorNearestRGB(&xc); + } + else + { + /* ja' estava disponivel */ + /* atualizo a tabela de cores */ + mot_color.color_table[xc.pixel] = xc; + pixel = xc.pixel; + } + + return pixel; +} + +static void motColorGetRGB_NotTrueColor(unsigned long pixel, unsigned char* red, unsigned char* green, unsigned char* blue) +{ + XColor xc; + xc.pixel = pixel; + XQueryColor(iupmot_display, mot_color.colormap, &xc); + *red = (unsigned char)xc.red; + *green = (unsigned char)xc.green; + *blue = (unsigned char)xc.blue; +} + +static void motColorReserveColors(void) +{ + unsigned char r, g, b; + unsigned long background, foreground, shadow, highlight, selection; + XtVaGetValues(iupmot_appshell, XmNbackground, &background, NULL); + XmGetColors(DefaultScreenOfDisplay(iupmot_display), mot_color.colormap, + background, &foreground, &highlight, &shadow, &selection); + motColorGetRGB_NotTrueColor(background, &r, &g, &b); + motColorGetPixel_NotTrueColor(r, g, b); + motColorGetRGB_NotTrueColor(foreground, &r, &g, &b); + motColorGetPixel_NotTrueColor(r, g, b); + motColorGetRGB_NotTrueColor(shadow, &r, &g, &b); + motColorGetPixel_NotTrueColor(r, g, b); + motColorGetRGB_NotTrueColor(highlight, &r, &g, &b); + motColorGetPixel_NotTrueColor(r, g, b); + motColorGetRGB_NotTrueColor(selection, &r, &g, &b); + motColorGetPixel_NotTrueColor(r, g, b); +} + + +/******************************************* + TrueColor Functions +*******************************************/ + + +static void motColorGetRGB_TrueColor(unsigned long pixel, unsigned char* red, unsigned char* green, unsigned char* blue) +{ + unsigned long r = pixel & iupmot_visual->red_mask; + unsigned long g = pixel & iupmot_visual->green_mask; + unsigned long b = pixel & iupmot_visual->blue_mask; + if (mot_color.rshift<0) r = r >> (-mot_color.rshift); + else r = r << mot_color.rshift; + if (mot_color.gshift<0) g = g >> (-mot_color.gshift); + else g = g << mot_color.gshift; + if (mot_color.bshift<0) b = b >> (-mot_color.bshift); + else b = b << mot_color.bshift; + *red = iupCOLOR16TO8(r); + *green = iupCOLOR16TO8(g); + *blue = iupCOLOR16TO8(b); +} + +static unsigned long motColorGetPixel_TrueColor(unsigned char cr, unsigned char cg, unsigned char cb) +{ + unsigned long r = iupCOLOR8TO16(cr); + unsigned long g = iupCOLOR8TO16(cg); + unsigned long b = iupCOLOR8TO16(cb); + + if (mot_color.rshift<0) + r = r << (-mot_color.rshift); + else + r = r >> mot_color.rshift; + + if (mot_color.gshift<0) + g = g << (-mot_color.gshift); + else + g = g >> mot_color.gshift; + + if (mot_color.bshift<0) + b = b << (-mot_color.bshift); + else + b = b >> mot_color.bshift; + + r = r & iupmot_visual->red_mask; + g = g & iupmot_visual->green_mask; + b = b & iupmot_visual->blue_mask; + + return r | g | b; +} + +static int motColorHighBit(unsigned long ul) +{ +/* returns position of highest set bit in 'ul' as an integer (0-31), + or -1 if none */ + int i; unsigned long hb; + + hb = 0x80; hb = hb << 24; /* hb = 0x80000000UL */ + for (i=31; ((ul & hb) == 0) && i>=0; i--, ul<<=1); + return i; +} + +static void motColorMakeDirectCmap(Colormap cmap) +{ + int i, cmaplen, numgot; + unsigned char origgot[256]; + XColor c; + unsigned long rmask, gmask, bmask; + int rshift, gshift, bshift; + + rmask = iupmot_visual->red_mask; + gmask = iupmot_visual->green_mask; + bmask = iupmot_visual->blue_mask; + + rshift = motColorHighBit(rmask) - 15; + gshift = motColorHighBit(gmask) - 15; + bshift = motColorHighBit(bmask) - 15; + + if (rshift<0) rmask = rmask << (-rshift); + else rmask = rmask >> rshift; + + if (gshift<0) gmask = gmask << (-gshift); + else gmask = gmask >> gshift; + + if (bshift<0) bmask = bmask << (-bshift); + else bmask = bmask >> bshift; + + cmaplen = iupmot_visual->map_entries; + if (cmaplen>256) cmaplen=256; + + /* try to alloc a 'cmaplen' long grayscale colormap. May not get all + entries for whatever reason. Build table 'mot_color.direct_conv[]' that + maps range [0..(cmaplen-1)] into set of colors we did get */ + + for (i=0; i<256; i++) { origgot[i] = 0; mot_color.direct_conv[i] = i; } + + for (i=numgot=0; i<cmaplen; i++) + { + c.red = c.green = c.blue = (unsigned short)((i * 0xffff) / (cmaplen - 1)); + c.red = (unsigned short)(c.red & rmask); + c.green = (unsigned short)(c.green & gmask); + c.blue = (unsigned short)(c.blue & bmask); + c.flags = DoRed | DoGreen | DoBlue; + + if (XAllocColor(iupmot_display, cmap, &c)) + { + origgot[i] = 1; + numgot++; + } + } + + if (numgot == 0) + return; + + /* mot_color.direct_conv may or may not have holes in it. */ + for (i=0; i<cmaplen; i++) + { + if (!origgot[i]) + { + int numbak, numfwd; + numbak = numfwd = 0; + while ((i - numbak) >= 0 && !origgot[i-numbak]) numbak++; + while ((i + numfwd) < cmaplen && !origgot[i+numfwd]) numfwd++; + + if (i-numbak<0 || !origgot[i-numbak]) numbak = 999; + if (i+numfwd>=cmaplen || !origgot[i+numfwd]) numfwd = 999; + + if (numbak<numfwd) mot_color.direct_conv[i] = mot_color.direct_conv[i-numbak]; + else if (numfwd<999) mot_color.direct_conv[i] = mot_color.direct_conv[i+numfwd]; + } + } +} + + +/******************************************* + Exported Functions +*******************************************/ + +unsigned long (* iupmotColorGetPixel)(unsigned char r, unsigned char g, unsigned char b) = 0; +void (* iupmotColorGetRGB)(unsigned long pixel, unsigned char* red, unsigned char* green, unsigned char* blue) = 0; + +void iupmotColorInit(void) +{ + int depth = iupdrvGetScreenDepth(); + + if (depth > 8) + { + iupmotColorGetRGB = motColorGetRGB_TrueColor; + iupmotColorGetPixel = motColorGetPixel_TrueColor; + + /* make linear colormap for DirectColor visual */ + if (iupmot_visual->class == DirectColor) + motColorMakeDirectCmap(DefaultColormap(iupmot_display, iupmot_screen)); + + mot_color.rshift = 15 - motColorHighBit(iupmot_visual->red_mask); + mot_color.gshift = 15 - motColorHighBit(iupmot_visual->green_mask); + mot_color.bshift = 15 - motColorHighBit(iupmot_visual->blue_mask); + + mot_color.num_colors = 0; + mot_color.colormap = 0; + } + else + { + int i; + iupmotColorGetRGB = motColorGetRGB_NotTrueColor; + iupmotColorGetPixel = motColorGetPixel_NotTrueColor; + + mot_color.colormap = DefaultColormap(iupmot_display, iupmot_screen); + mot_color.num_colors = 1L << depth; + + for (i=0; i<mot_color.num_colors; i++) + mot_color.color_table[i].pixel = i; + + XQueryColors(iupmot_display, mot_color.colormap, mot_color.color_table, mot_color.num_colors); + XSetErrorHandler(motColor8BppErrorHandler); + + motColorReserveColors(); + } +} + +void iupmotColorFinish(void) +{ + if (mot_color.colormap) + { + unsigned long pixels[256]; + int i; + + /* release colors */ + for (i = 0; i < mot_color.num_colors; i++) + pixels[i] = mot_color.color_table[i].pixel; + + XFreeColors(iupmot_display, mot_color.colormap, pixels, mot_color.num_colors, 0); + + /* release palette */ + if (mot_color.colormap != DefaultColormap(iupmot_display, iupmot_screen)) + XFreeColormap(iupmot_display, mot_color.colormap); + } +} + +Colormap iupmotColorMap(void) +{ + return mot_color.colormap; +} + +unsigned long iupmotColorGetPixelStr(const char* color) +{ + unsigned char r, g, b; + if (!iupStrToRGB(color, &r, &g, &b)) + return (unsigned long)-1; + + return iupmotColorGetPixel(r, g, b); +} diff --git a/iup/src/mot/iupmot_color.h b/iup/src/mot/iupmot_color.h new file mode 100755 index 0000000..a306fd3 --- /dev/null +++ b/iup/src/mot/iupmot_color.h @@ -0,0 +1,36 @@ +/** \file + * \brief Motif Color Management + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMOT_COLOR_H +#define __IUPMOT_COLOR_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Returns a pixel value from a RGB triple. */ +extern unsigned long (* iupmotColorGetPixel)(unsigned char r, unsigned char g, unsigned char b); + +/* Returns a RGB triple from a pixel value. */ +extern void (* iupmotColorGetRGB)(unsigned long pixel, unsigned char *r, unsigned char *g, unsigned char *b); + +/* initialize the toplevel colormap and the iupmotColorGet* functions */ +void iupmotColorInit(void); +void iupmotColorFinish(void); + +/* returns the toplevel colormap */ +Colormap iupmotColorMap(void); + +/* Returns a pixel value from a IUP color description. */ +unsigned long iupmotColorGetPixelStr(const char* color); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/mot/iupmot_colordlg.c b/iup/src/mot/iupmot_colordlg.c new file mode 100755 index 0000000..7a949bf --- /dev/null +++ b/iup/src/mot/iupmot_colordlg.c @@ -0,0 +1,31 @@ +/** \file + * \brief IupColorDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drvinfo.h" +#include "iup_dialog.h" + +#include "iupmot_drv.h" + + +static int motColorDlgPopup(Ihandle* ih, int x, int y) +{ + (void)ih; + (void)x; + (void)y; + return IUP_ERROR; +} + +void iupdrvColorDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = motColorDlgPopup; +} diff --git a/iup/src/mot/iupmot_common.c b/iup/src/mot/iupmot_common.c new file mode 100755 index 0000000..7b3f8b7 --- /dev/null +++ b/iup/src/mot/iupmot_common.c @@ -0,0 +1,630 @@ +/** \file + * \brief Motif Base Functions + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include <Xm/Xm.h> +#include <Xm/ScrollBar.h> +#include <X11/cursorfont.h> + +#include "iup.h" +#include "iupkey.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_key.h" +#include "iup_str.h" +#include "iup_class.h" +#include "iup_attrib.h" +#include "iup_focus.h" +#include "iup_key.h" +#include "iup_drv.h" +#include "iup_image.h" +#include "iup_drv.h" + +#include "iupmot_color.h" +#include "iupmot_drv.h" + + + +void iupdrvActivate(Ihandle* ih) +{ + if (iupStrEqual(ih->iclass->name, "text") || iupStrEqual(ih->iclass->name, "multiline")) + XmProcessTraversal(ih->handle, XmTRAVERSE_CURRENT); + else + XtCallActionProc(ih->handle, "ArmAndActivate", 0, 0, 0 ); +} + +static int motActivateMnemonic(Ihandle *dialog, int c) +{ + Ihandle *ih; + char attrib[19] = "_IUPMOT_MNEMONIC_ "; + attrib[17] = (char)c; + ih = (Ihandle*)iupAttribGet(dialog, attrib); + if (iupObjectCheck(ih)) + { + iupdrvActivate(ih); + return IUP_IGNORE; + } + return IUP_CONTINUE; +} + +void iupmotSetMnemonicTitle(Ihandle *ih, const char* value) +{ + char c; + char* str; + + if (!value) + value = ""; + + str = iupStrProcessMnemonic(value, &c, -1); /* remove & and return in c */ + if (str != value) + { + KeySym keysym = iupmotKeyCharToKeySym(c); + XtVaSetValues(ih->handle, XmNmnemonic, keysym, NULL); /* works only for menus, but underlines the letter */ + + if (ih->iclass->nativetype != IUP_TYPEMENU) + { + Ihandle* dialog = IupGetDialog(ih); + char attrib[22] = "_IUPMOT_MNEMONIC_ \0CB"; + attrib[17] = (char)toupper(c); + + /* used by motActivateMnemonic */ + if (iupStrEqual(ih->iclass->name, "label")) + iupAttribSetStr(dialog, attrib, (char*)iupFocusNextInteractive(ih)); + else + iupAttribSetStr(dialog, attrib, (char*)ih); + + /* used by iupmotKeyPressEvent */ + attrib[18] = '_'; + IupSetCallback(dialog, attrib, (Icallback)motActivateMnemonic); + } + + iupmotSetString(ih->handle, XmNlabelString, str); + free(str); + } + else + { + XtVaSetValues (ih->handle, XmNmnemonic, NULL, NULL); + iupmotSetString(ih->handle, XmNlabelString, str); + } +} + +void iupmotSetString(Widget w, const char *resource, const char* value) +{ + XmString xm_str = XmStringCreateLocalized((String)value); + XtVaSetValues(w, resource, xm_str, NULL); + XmStringFree(xm_str); +} + +char* iupmotConvertString(XmString str) +{ + char* text = (char*)XmStringUnparse(str, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); + char* buf = iupStrGetMemoryCopy(text); + XtFree(text); + return buf; +} + +#ifdef OLD_CONVERT +char* iupmotConvertString(XmString str) +{ + XmStringContext context; + char *text, *p, *buf; + unsigned int length; + XmStringComponentType type; + + if (!XmStringInitContext (&context, str)) + return NULL; + + buf = iupStrGetMemory(XmStringLength(str)); /* always greatter than strlen */ + + /* p keeps a running pointer through buf as text is read */ + p = buf; + while ((type = XmStringGetNextTriple(context, &length, (XtPointer)&text)) != XmSTRING_COMPONENT_END) + { + switch (type) + { + case XmSTRING_COMPONENT_TEXT: + memcpy(p, text, length); + p += length; + *p = 0; + break; + case XmSTRING_COMPONENT_TAB: + *p++ = '\t'; + *p = 0; + break; + case XmSTRING_COMPONENT_SEPARATOR: + *p++ = '\n'; + *p = 0; + break; + } + XtFree(text); + } + + XmStringFreeContext(context); + + return buf; +} +#endif + +void iupdrvReparent(Ihandle* ih) +{ + Widget native_parent = iupChildTreeGetNativeParentHandle(ih); + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + XReparentWindow(iupmot_display, XtWindow(widget), XtWindow(native_parent), 0, 0); +} + +void iupdrvBaseLayoutUpdateMethod(Ihandle *ih) +{ + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + + XtVaSetValues(widget, + XmNx, (XtArgVal)ih->x, + XmNy, (XtArgVal)ih->y, + XmNwidth, (XtArgVal)ih->currentwidth, + XmNheight, (XtArgVal)ih->currentheight, + NULL); +} + +void iupdrvBaseUnMapMethod(Ihandle* ih) +{ + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + + XtUnrealizeWidget(widget); /* To match the call to XtRealizeWidget */ + XtDestroyWidget(widget); /* To match the call to XtCreateManagedWidget */ +} + +void iupdrvDisplayUpdate(Ihandle *ih) +{ + XExposeEvent evt; + Dimension w, h; + + XtVaGetValues(ih->handle, XmNwidth, &w, + XmNheight, &h, + NULL); + + evt.type = Expose; + evt.display = iupmot_display; + evt.send_event = True; + evt.window = XtWindow(ih->handle); + + evt.x = 0; + evt.y = 0; + evt.width = w; + evt.height = h; + + evt.count = 0; + + /* POST a Redraw */ + XSendEvent(iupmot_display, XtWindow(ih->handle), False, ExposureMask, (XEvent*)&evt); +} + +void iupdrvDisplayRedraw(Ihandle *ih) +{ + Widget w; + + /* POST a Redraw */ + iupdrvDisplayUpdate(ih); + + /* if this element has an inner native parent (like IupTabs), + then redraw that native parent if different from the element. */ + w = (Widget)iupClassObjectGetInnerNativeContainerHandle(ih, (Ihandle*)IupGetAttribute(ih, "VALUE_HANDLE")); + if (w && w != ih->handle) + { + Widget handle = ih->handle; + ih->handle = w; + iupdrvDisplayUpdate(ih); + ih->handle = handle; + } + + /* flush exposure events. */ + XmUpdateDisplay(ih->handle); +} + +void iupdrvScreenToClient(Ihandle* ih, int *x, int *y) +{ + Window child; + XTranslateCoordinates(iupmot_display, RootWindow(iupmot_display, iupmot_screen), + XtWindow(ih->handle), + *x, *y, x, y, &child); +} + +void iupmotHelpCallback(Widget w, Ihandle *ih, XtPointer call_data) +{ + Icallback cb = IupGetCallback(ih, "HELP_CB"); + if (cb && cb(ih) == IUP_CLOSE) + IupExitLoop(); + + (void)call_data; + (void)w; +} + +void iupmotEnterLeaveWindowEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + Icallback cb = NULL; + (void)cont; + (void)w; + + if (evt->type == EnterNotify) + { + iupmotTipEnterNotify(ih); + + cb = IupGetCallback(ih, "ENTERWINDOW_CB"); + } + else if (evt->type == LeaveNotify) + { + iupmotTipLeaveNotify(); + + cb = IupGetCallback(ih, "LEAVEWINDOW_CB"); + } + + if (cb) + cb(ih); +} + +int iupdrvBaseSetZorderAttrib(Ihandle* ih, const char* value) +{ + if (iupdrvIsVisible(ih)) + { + if (iupStrEqualNoCase(value, "TOP")) + XRaiseWindow(iupmot_display, XtWindow(ih->handle)); + else + XLowerWindow(iupmot_display, XtWindow(ih->handle)); + } + + return 0; +} + +void iupdrvSetVisible(Ihandle* ih, int visible) +{ + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + + if (visible) + XtMapWidget(widget); + else + XtUnmapWidget(widget); +} + +int iupdrvIsVisible(Ihandle* ih) +{ + XWindowAttributes wa; + XGetWindowAttributes(iupmot_display, XtWindow(ih->handle), &wa); + return (wa.map_state == IsViewable); +} + +int iupdrvIsActive(Ihandle* ih) +{ + return XtIsSensitive(ih->handle); +} + +void iupdrvSetActive(Ihandle* ih, int enable) +{ + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + + XtSetSensitive(widget, enable); +} + +char* iupmotGetXWindowAttrib(Ihandle *ih) +{ + return (char*)XtWindow(ih->handle); +} + +char* iupdrvBaseGetXAttrib(Ihandle *ih) +{ + int x, y; + Window child; + char* str = iupStrGetMemory(20); + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + + /* Translating to absolute screen coordinates */ + /* source destination */ + XTranslateCoordinates(iupmot_display, + XtWindow(widget), RootWindow(iupmot_display, iupmot_screen), + 0, 0, &x, &y, + &child); + + sprintf(str, "%d", x); + return str; +} + +char* iupdrvBaseGetYAttrib(Ihandle *ih) +{ + int x, y; + Window child; + char* str = iupStrGetMemory(20); + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + + /* Translating to absolute screen coordinates */ + /* source destination */ + XTranslateCoordinates(iupmot_display, + XtWindow(widget), RootWindow(iupmot_display, iupmot_screen), + 0, 0, &x, &y, + &child); + + sprintf(str, "%d", y); + return str; +} + +void iupmotSetBgColor(Widget w, Pixel color) +{ + Pixel fgcolor; + XtVaGetValues(w, XmNforeground, &fgcolor, NULL); + XmChangeColor(w, color); + /* XmChangeColor also sets the XmNforeground color, so we must reset to the previous one. */ + XtVaSetValues(w, XmNforeground, fgcolor, NULL); + XtVaSetValues(w, XmNbackgroundPixmap, XmUNSPECIFIED_PIXMAP, NULL); +} + +int iupdrvBaseSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + iupmotSetBgColor(ih->handle, color); + + /* update internal image cache for controls that have the IMAGE attribute */ + iupImageUpdateParent(ih); + } + return 1; +} + +char* iupmotGetBgColorAttrib(Ihandle* ih) +{ + unsigned char r, g, b; + Pixel color; + char* str = iupStrGetMemory(20); + XtVaGetValues(ih->handle, XmNbackground, &color, NULL); + iupmotColorGetRGB(color, &r, &g, &b); + sprintf(str, "%d %d %d", (int)r, (int)g, (int)b); + return str; +} + +int iupdrvBaseSetFgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + XtVaSetValues(ih->handle, XmNforeground, color, NULL); + return 1; +} + +void iupmotGetWindowSize(Ihandle *ih, int *width, int *height) +{ + Dimension w, h; + XtVaGetValues(ih->handle, XmNwidth, &w, + XmNheight, &h, + NULL); + *width = w; + *height = h; +} + +static Cursor motEmptyCursor(Ihandle* ih) +{ + /* creates an empty cursor */ + XColor cursor_color = {0L,0,0,0,0,0}; + char bitsnull[1] = {0x00}; + Pixmap pixmapnull; + Cursor cur; + + pixmapnull = XCreateBitmapFromData(iupmot_display, + XtWindow(ih->handle), + bitsnull, + 1,1); + + cur = XCreatePixmapCursor(iupmot_display, + pixmapnull, + pixmapnull, + &cursor_color, + &cursor_color, + 0,0); + + XFreePixmap(iupmot_display, pixmapnull); + + return cur; +} + +static Cursor motGetCursor(Ihandle* ih, const char* name) +{ + static struct { + const char* iupname; + int sysname; + } table[] = { + { "NONE", 0}, + { "NULL", 0}, + { "ARROW", XC_left_ptr}, + { "BUSY", XC_watch}, + { "CROSS", XC_crosshair}, + { "HAND", XC_hand2}, + { "HELP", XC_question_arrow}, + { "IUP", XC_question_arrow}, + { "MOVE", XC_fleur}, + { "PEN", XC_pencil}, + { "RESIZE_N", XC_top_side}, + { "RESIZE_S", XC_bottom_side}, + { "RESIZE_NS", XC_sb_v_double_arrow}, + { "RESIZE_W", XC_left_side}, + { "RESIZE_E", XC_right_side}, + { "RESIZE_WE", XC_sb_h_double_arrow}, + { "RESIZE_NE", XC_top_right_corner}, + { "RESIZE_SE", XC_bottom_right_corner}, + { "RESIZE_NW", XC_top_left_corner}, + { "RESIZE_SW", XC_bottom_left_corner}, + { "TEXT", XC_xterm}, + { "UPARROW", XC_center_ptr} + }; + + Cursor cur; + char str[50]; + int i, count = sizeof(table)/sizeof(table[0]); + + /* check the cursor cache first (per control)*/ + sprintf(str, "_IUPMOT_CURSOR_%s", name); + cur = (Cursor)iupAttribGet(ih, str); + if (cur) + return cur; + + /* check the pre-defined IUP names first */ + for (i = 0; i < count; i++) + { + if (iupStrEqualNoCase(name, table[i].iupname)) + { + if (table[i].sysname) + cur = XCreateFontCursor(iupmot_display, table[i].sysname); + else + cur = motEmptyCursor(ih); + + break; + } + } + + if (i == count) + { + /* check for a name defined cursor */ + cur = (Cursor)iupImageGetCursor(name); + } + + iupAttribSetStr(ih, str, (char*)cur); + return cur; +} + +int iupdrvBaseSetCursorAttrib(Ihandle* ih, const char* value) +{ + Cursor cur = motGetCursor(ih, value); + if (cur) + { + XDefineCursor(iupmot_display, XtWindow(ih->handle), cur); + return 1; + } + return 0; +} + +#include <Xm/XmP.h> +#include <Xm/DrawP.h> + +void iupdrvDrawFocusRect(Ihandle* ih, void* _gc, int x, int y, int w, int h) +{ + Drawable wnd = (Drawable)IupGetAttribute(ih, "XWINDOW"); /* Use IupGetAttribute to consult the native implemetation */ + GC gc = (GC)_gc; + XmeDrawHighlight(iupmot_display, wnd, gc, x, y, w, h, 1); +} + +void iupdrvBaseRegisterCommonAttrib(Iclass* ic) +{ + iupClassRegisterAttribute(ic, "XMFONTLIST", iupmotGetFontListAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "XFONTSTRUCT", iupmotGetFontStructAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "XFONTID", iupmotGetFontIdAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); +} + +static void motDoNothing(Widget w, XEvent* evt, String* params, Cardinal* num_params) +{ + (void)w; + (void)evt; + (void)params; + (void)num_params; +} + +void iupmotDisableDragSource(Widget w) +{ + char dragTranslations[] = "#override <Btn2Down>: iupDoNothing()"; + static int do_nothing_rec = 0; + if (!do_nothing_rec) + { + XtActionsRec rec = {"iupDoNothing", (XtActionProc)motDoNothing}; + XtAppAddActions(iupmot_appcontext, &rec, 1); + do_nothing_rec = 1; + } + XtOverrideTranslations(w, XtParseTranslationTable(dragTranslations)); +} + +int iupdrvGetScrollbarSize(void) +{ + return 15; +} + +void iupmotSetPixmap(Ihandle* ih, const char* name, const char* prop, int make_inactive) +{ + if (name) + { + Pixmap old_pixmap; + Pixmap pixmap = (Pixmap)iupImageGetImage(name, ih, make_inactive); + if (!pixmap) + pixmap = XmUNSPECIFIED_PIXMAP; + XtVaGetValues(ih->handle, prop, &old_pixmap, NULL); + if (pixmap != old_pixmap) + XtVaSetValues(ih->handle, prop, pixmap, NULL); + return; + } + + /* if not defined */ + XtVaSetValues(ih->handle, prop, XmUNSPECIFIED_PIXMAP, NULL); +} + +void iupmotButtonPressReleaseEvent(Widget w, Ihandle* ih, XEvent* evt, Boolean* cont) +{ + unsigned long elapsed; + static Time last = 0; + char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; + IFniiiis cb; + + XButtonEvent *but_evt = (XButtonEvent*)evt; + if (but_evt->button!=Button1 && + but_evt->button!=Button2 && + but_evt->button!=Button3 && + but_evt->button!=Button4 && + but_evt->button!=Button5) + return; + + cb = (IFniiiis) IupGetCallback(ih,"BUTTON_CB"); + if (cb) + { + int ret, doubleclick = 0; + int b = IUP_BUTTON1+(but_evt->button-1); + + /* Double/Single Click */ + if (but_evt->type==ButtonPress) + { + elapsed = but_evt->time - last; + last = but_evt->time; + if ((int)elapsed <= XtGetMultiClickTime(iupmot_display)) + doubleclick = 1; + } + + iupmotButtonKeySetStatus(but_evt->state, but_evt->button, status, doubleclick); + + ret = cb(ih, b, (but_evt->type==ButtonPress), but_evt->x, but_evt->y, status); + if (ret==IUP_CLOSE) + IupExitLoop(); + else if (ret==IUP_IGNORE) + *cont=False; + } + + (void)w; +} + +void iupmotPointerMotionEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + IFniis cb = (IFniis)IupGetCallback(ih,"MOTION_CB"); + if (cb) + { + XMotionEvent *motion_evt = (XMotionEvent*)evt; + char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; + iupmotButtonKeySetStatus(motion_evt->state, 0, status, 0); + cb(ih, motion_evt->x, motion_evt->y, status); + } + + (void)w; + (void)cont; +} diff --git a/iup/src/mot/iupmot_dialog.c b/iup/src/mot/iupmot_dialog.c new file mode 100755 index 0000000..4eeb834 --- /dev/null +++ b/iup/src/mot/iupmot_dialog.c @@ -0,0 +1,1069 @@ +/** \file + * \brief IupDialog class + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/BulletinB.h> +#include <Xm/MwmUtil.h> +#include <Xm/AtomMgr.h> +#include <Xm/Protocols.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_class.h" +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_dlglist.h" +#include "iup_attrib.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_drvinfo.h" +#include "iup_focus.h" +#include "iup_str.h" +#define _IUPDLG_PRIVATE +#include "iup_dialog.h" +#include "iup_image.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +Atom iupmot_wm_deletewindow = 0; /* used also by IupMessageDlg */ + +static int motDialogSetBgColorAttrib(Ihandle* ih, const char* value); + +/**************************************************************** + Utilities +****************************************************************/ + + +int iupdrvDialogIsVisible(Ihandle* ih) +{ + return iupdrvIsVisible(ih) || ih->data->show_state == IUP_MINIMIZE; +} + +void iupdrvDialogUpdateSize(Ihandle* ih) +{ + Dimension width, height; + XtVaGetValues(ih->handle, XmNwidth, &width, XmNheight, &height, NULL); + ih->currentwidth = width; + ih->currentheight = height; +} + +void iupdrvDialogGetSize(InativeHandle* handle, int *w, int *h) +{ + Dimension width, height; + XtVaGetValues(handle, XmNwidth, &width, XmNheight, &height, NULL); + if (w) *w = width; + if (h) *h = height; +} + +void iupmotDialogSetVisual(Ihandle* ih, void* visual) +{ + Ihandle *dialog = IupGetDialog(ih); + XtVaSetValues(dialog->handle, XmNvisual, visual, NULL); +} + +void iupmotDialogResetVisual(Ihandle* ih) +{ + Ihandle *dialog = IupGetDialog(ih); + XtVaSetValues(dialog->handle, XmNvisual, iupmot_visual, NULL); +} + +void iupdrvDialogSetVisible(Ihandle* ih, int visible) +{ + if (visible) + { + XtMapWidget(ih->handle); + XRaiseWindow(iupmot_display, XtWindow(ih->handle)); + while (!iupdrvDialogIsVisible(ih)); /* waits until window get mapped */ + } + else + { + /* if iupdrvIsVisible reports hidden, then it should be minimized */ + if (!iupdrvIsVisible(ih)) /* can NOT hide a minimized window, so map it first. */ + { + XtMapWidget(ih->handle); + XRaiseWindow(iupmot_display, XtWindow(ih->handle)); + while (!iupdrvDialogIsVisible(ih)); /* waits until window get mapped */ + } + + XtUnmapWidget(ih->handle); + while (iupdrvDialogIsVisible(ih)); /* waits until window gets unmapped */ + } +} + +void iupdrvDialogGetPosition(InativeHandle* handle, int *x, int *y) +{ + Dimension cur_x, cur_y; + XtVaGetValues(handle, XmNx, &cur_x, + XmNy, &cur_y, + NULL); + if (x) *x = cur_x; + if (y) *y = cur_y; +} + +void iupdrvDialogSetPosition(Ihandle *ih, int x, int y) +{ + XtVaSetValues(ih->handle, + XmNx, (XtArgVal)x, + XmNy, (XtArgVal)y, + NULL); +} + +static int motDialogGetMenuSize(Ihandle* ih) +{ + if (ih->data->menu) + return iupdrvMenuGetMenuBarSize(ih->data->menu); + else + return 0; +} + +void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu) +{ + static int native_border = 0; + static int native_caption = 0; + + int has_caption = iupAttribGetBoolean(ih, "MAXBOX") || + iupAttribGetBoolean(ih, "MINBOX") || + iupAttribGetBoolean(ih, "MENUBOX") || + IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ + + int has_border = has_caption || + iupAttribGetBoolean(ih, "RESIZE") || + iupAttribGetBoolean(ih, "BORDER"); + + *menu = motDialogGetMenuSize(ih); + + if (ih->handle && iupdrvDialogIsVisible(ih)) + { + int win_border, win_caption; + if (iupdrvGetWindowDecor((void*)XtWindow(ih->handle), &win_border, &win_caption)) + { + *border = 0; + if (has_border) + *border = win_border; + + *caption = 0; + if (has_caption) + *caption = win_caption; + + if (!native_border && *border) + native_border = win_border; + + if (!native_caption && *caption) + native_caption = win_caption; + + return; + } + } + + /* I could not set the size of the window including the decorations when the dialog is hidden */ + /* So we have to estimate the size of borders and caption when the dialog is hidden */ + + *border = 0; + if (has_border) + { + if (native_border) + *border = native_border; + else + *border = 5; + } + + *caption = 0; + if (has_caption) + { + if (native_caption) + *caption = native_caption; + else + *caption = 20; + } +} + +static int motDialogQueryWMspecSupport(Atom feature) +{ + static Atom netsuppport = 0; + Atom type; + Atom *atoms; + int format; + unsigned long after, natoms, i; + + if (!netsuppport) + netsuppport = XmInternAtom(iupmot_display, "_NET_SUPPORTED", False); + + /* get all the features */ + XGetWindowProperty(iupmot_display, RootWindow(iupmot_display, iupmot_screen), + netsuppport, 0, LONG_MAX, False, XA_ATOM, &type, &format, &natoms, + &after, (unsigned char **)&atoms); + if (type != XA_ATOM || atoms == NULL) + { + if (atoms) XFree(atoms); + return 0; + } + + /* Lookup the feature we want */ + for (i = 0; i < natoms; i++) + { + if (atoms[i] == feature) + { + XFree(atoms); + return 1; + } + } + + XFree(atoms); + return 0; +} + +static void motDialogSetWindowManagerStyle(Ihandle* ih) +{ + MwmHints hints; + static Atom xwmhint = 0; + if (!xwmhint) + xwmhint = XmInternAtom(iupmot_display, "_MOTIF_WM_HINTS", False); + + hints.flags = (MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS); + hints.functions = 0; + hints.decorations = 0; + hints.input_mode = 0; + hints.status = 0; + + if (IupGetAttribute(ih, "TITLE")) { /* must use IupGetAttribute to check from the native implementation */ + hints.functions |= MWM_FUNC_MOVE; + hints.decorations |= MWM_DECOR_TITLE; + } + + if (iupAttribGetBoolean(ih, "MENUBOX")) { + hints.functions |= MWM_FUNC_CLOSE; + hints.decorations |= MWM_DECOR_MENU; + } + + if (iupAttribGetBoolean(ih, "MINBOX")) { + hints.functions |= MWM_FUNC_MINIMIZE; + hints.decorations |= MWM_DECOR_MINIMIZE; + } + + if (iupAttribGetBoolean(ih, "MAXBOX")) { + hints.functions |= MWM_FUNC_MAXIMIZE; + hints.decorations |= MWM_DECOR_MAXIMIZE; + } + + if (iupAttribGetBoolean(ih, "RESIZE")) { + hints.functions |= MWM_FUNC_RESIZE; + hints.decorations |= MWM_DECOR_RESIZEH; + } + + if (iupAttribGetBoolean(ih, "BORDER")) + hints.decorations |= MWM_DECOR_BORDER; + + XChangeProperty(iupmot_display, XtWindow(ih->handle), + xwmhint, xwmhint, + 32, PropModeReplace, + (const unsigned char *) &hints, + PROP_MOTIF_WM_HINTS_ELEMENTS); +} + +static void motDialogChangeWMState(Ihandle* ih, Atom state1, Atom state2, int operation) +{ + static Atom wmstate = 0; + if (!wmstate) + wmstate = XmInternAtom(iupmot_display, "_NET_WM_STATE", False); + + if (iupdrvDialogIsVisible(ih)) + { + XEvent evt; + evt.type = ClientMessage; + evt.xclient.type = ClientMessage; + evt.xclient.serial = 0; + evt.xclient.send_event = True; + evt.xclient.display = iupmot_display; + evt.xclient.window = XtWindow(ih->handle); + evt.xclient.message_type = wmstate; + evt.xclient.format = 32; + evt.xclient.data.l[0] = operation; + evt.xclient.data.l[1] = state1; + evt.xclient.data.l[2] = state2; + evt.xclient.data.l[3] = 0; + evt.xclient.data.l[4] = 0; + + XSendEvent(iupmot_display, RootWindow(iupmot_display, iupmot_screen), False, + SubstructureRedirectMask | SubstructureNotifyMask, &evt); + } + else + { + if (operation) + { + if (state1 && state2) + { + Atom atoms[2]; + atoms[0] = state1; + atoms[0] = state2; + + XChangeProperty(iupmot_display, XtWindow(ih->handle), + wmstate, XA_ATOM, + 32, PropModeReplace, + (const unsigned char *)&atoms, 2); + } + else + { + XChangeProperty(iupmot_display, XtWindow(ih->handle), + wmstate, XA_ATOM, + 32, PropModeReplace, + (const unsigned char *)&state1, 1); + } + } + else + { + /* TODO: This is not working. The property is not correctly removed. */ + /* XDeleteProperty(iupmot_display, XtWindow(ih->handle), wmstate); */ + + /* Maybe the right way to do it is to retrieve all the atoms */ + /* and change again with all atoms except the one to remove */ + } + } +} + +static int motDialogSetFullScreen(Ihandle* ih, int fullscreen) +{ + static int support_fullscreen = -1; /* WARNING: The WM can be changed dinamically */ + + static Atom xwmfs = 0; + if (!xwmfs) + xwmfs = XmInternAtom(iupmot_display, "_NET_WM_STATE_FULLSCREEN", False); + + if (support_fullscreen == -1) + support_fullscreen = motDialogQueryWMspecSupport(xwmfs); + + if (support_fullscreen) + { + motDialogChangeWMState(ih, xwmfs, 0, fullscreen); + return 1; + } + + return 0; +} + +int iupdrvDialogSetPlacement(Ihandle* ih) +{ + char* placement; + ih->data->show_state = IUP_SHOW; + + if (iupAttribGetBoolean(ih, "FULLSCREEN")) + return 1; + + placement = iupAttribGet(ih, "PLACEMENT"); + if (!placement) + return 0; + + if (iupStrEqualNoCase(placement, "MINIMIZED")) + { + if (iupdrvDialogIsVisible(ih)) + XIconifyWindow(iupmot_display, XtWindow(ih->handle), iupmot_screen); + else + { + /* TODO: This is not working, so force a minimize after visible. */ + /*XWMHints wm_hints; */ + /*wm_hints.flags = StateHint; */ + /*wm_hints.initial_state = IconicState; */ + /*XSetWMHints(iupmot_display, XtWindow(ih->handle), &wm_hints); */ + + XtMapWidget(ih->handle); + XIconifyWindow(iupmot_display, XtWindow(ih->handle), iupmot_screen); + } + } + else if (iupStrEqualNoCase(placement, "MAXIMIZED")) + { + static Atom maxatoms[2] = {0, 0}; + if (!(maxatoms[0])) + { + maxatoms[0] = XmInternAtom(iupmot_display, "_NET_WM_STATE_MAXIMIZED_VERT", False); + maxatoms[1] = XmInternAtom(iupmot_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); + } + + motDialogChangeWMState(ih, maxatoms[0], maxatoms[1], 1); + } + else if (iupStrEqualNoCase(placement, "FULL")) + { + int width, height, x, y; + int border, caption, menu; + iupdrvDialogGetDecoration(ih, &border, &caption, &menu); + + /* position the decoration outside the screen */ + x = -(border); + y = -(border+caption+menu); + + /* the dialog client area will cover the task bar */ + iupdrvGetFullSize(&width, &height); + + height += menu; /* the menu is included in the client area size in Motif. */ + + /* set the new size and position */ + /* The resize event will update the layout */ + XtVaSetValues(ih->handle, + XmNx, (XtArgVal)x, /* outside border */ + XmNy, (XtArgVal)y, + XmNwidth, (XtArgVal)width, /* client size */ + XmNheight, (XtArgVal)height, + NULL); + } + + iupAttribSetStr(ih, "PLACEMENT", NULL); /* reset to NORMAL */ + + return 1; +} + +/**************************************************************************** + Attributes +****************************************************************************/ + + +static int motDialogSetMinSizeAttrib(Ihandle* ih, const char* value) +{ + int decorwidth = 0, decorheight = 0; + int min_w = 1, min_h = 1; /* MINSIZE default value */ + iupStrToIntInt(value, &min_w, &min_h, 'x'); + + /* The minmax size restricts the client area */ + iupDialogGetDecorSize(ih, &decorwidth, &decorheight); + + if (min_w > decorwidth) + XtVaSetValues(ih->handle, XmNminWidth, min_w-decorwidth, NULL); + if (min_h > decorheight) + XtVaSetValues(ih->handle, XmNminHeight, min_h-decorheight, NULL); + + return 1; +} + +static int motDialogSetMaxSizeAttrib(Ihandle* ih, const char* value) +{ + int decorwidth = 0, decorheight = 0; + int max_w = 65535, max_h = 65535; /* MAXSIZE default value */ + iupStrToIntInt(value, &max_w, &max_h, 'x'); + + /* The minmax size restricts the client area */ + iupDialogGetDecorSize(ih, &decorwidth, &decorheight); + + if (max_w > decorwidth) + XtVaSetValues(ih->handle, XmNmaxWidth, max_w-decorwidth, NULL); + if (max_h > decorheight) + XtVaSetValues(ih->handle, XmNmaxHeight, max_h-decorheight, NULL); + + return 1; +} + +static char* motDialogGetXAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(20); + + int x; + iupdrvDialogGetPosition(ih->handle, &x, NULL); + + sprintf(str, "%d", x); + return str; +} + +static char* motDialogGetYAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(20); + + int y; + iupdrvDialogGetPosition(ih->handle, &y, NULL); + + sprintf(str, "%d", y); + return str; +} + +static int motDialogSetTitleAttrib(Ihandle* ih, const char* value) +{ + if (!value) + value = ""; + + XtVaSetValues(ih->handle, XmNtitle, value, + XmNiconName, value, + NULL); + return 0; +} + +static char* motDialogGetTitleAttrib(Ihandle* ih) +{ + char* title; + XtVaGetValues(ih->handle, XmNtitle, &title, NULL); + + if (!title || title[0] == 0) + return NULL; + else + { + char* str = iupStrGetMemory(200); + strcpy(str, title); + return str; + } +} + +static char* motDialogGetClientSizeAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(20); + + Dimension manager_width, manager_height; + Widget dialog_manager = XtNameToWidget(ih->handle, "*dialog_manager"); + XtVaGetValues(dialog_manager, XmNwidth, &manager_width, + XmNheight, &manager_height, + NULL); + + sprintf(str, "%dx%d", (int)manager_width, (int)manager_height - motDialogGetMenuSize(ih)); + return str; +} + +static int motDialogSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + Widget dialog_manager = XtNameToWidget(ih->handle, "*dialog_manager"); + XtVaSetValues(dialog_manager, XmNbackground, color, NULL); + XtVaSetValues(dialog_manager, XmNbackgroundPixmap, XmUNSPECIFIED_PIXMAP, NULL); + return 1; + } + return 0; +} + +static int motDialogSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + if (motDialogSetBgColorAttrib(ih, value)) + return 1; + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + if (pixmap) + { + Widget dialog_manager = XtNameToWidget(ih->handle, "*dialog_manager"); + XtVaSetValues(dialog_manager, XmNbackgroundPixmap, pixmap, NULL); + return 1; + } + } + return 0; +} + +static int motDialogSetFullScreenAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + { + if (!iupAttribGet(ih, "_IUPMOT_FS_STYLE")) + { + int visible = iupdrvDialogIsVisible(ih); + if (visible) + iupAttribSetStr(ih, "_IUPMOT_FS_STYLE", "VISIBLE"); + else + iupAttribSetStr(ih, "_IUPMOT_FS_STYLE", "HIDDEN"); + + /* save the previous decoration attributes */ + /* during fullscreen these attributes can be consulted by the application */ + iupAttribStoreStr(ih, "_IUPMOT_FS_MAXBOX", iupAttribGet(ih, "MAXBOX")); + iupAttribStoreStr(ih, "_IUPMOT_FS_MINBOX", iupAttribGet(ih, "MINBOX")); + iupAttribStoreStr(ih, "_IUPMOT_FS_MENUBOX",iupAttribGet(ih, "MENUBOX")); + iupAttribStoreStr(ih, "_IUPMOT_FS_RESIZE", iupAttribGet(ih, "RESIZE")); + iupAttribStoreStr(ih, "_IUPMOT_FS_BORDER", iupAttribGet(ih, "BORDER")); + iupAttribStoreStr(ih, "_IUPMOT_FS_TITLE", IupGetAttribute(ih, "TITLE")); /* must use IupGetAttribute to check from the native implementation */ + + /* remove the decorations attributes */ + iupAttribSetStr(ih, "MAXBOX", "NO"); + iupAttribSetStr(ih, "MINBOX", "NO"); + iupAttribSetStr(ih, "MENUBOX", "NO"); + IupSetAttribute(ih, "TITLE", NULL); iupAttribSetStr(ih, "TITLE", NULL); /* remove from the hash table if we are during IupMap */ + iupAttribSetStr(ih, "RESIZE", "NO"); + iupAttribSetStr(ih, "BORDER", "NO"); + + /* use WM fullscreen support */ + if (!motDialogSetFullScreen(ih, 1)) + { + /* or configure fullscreen manually */ + int decor; + int width, height; + + /* hide before changing decorations */ + if (visible) + { + iupAttribSetStr(ih, "_IUPMOT_SHOW_STATE", NULL); /* To avoid a SHOW_CB notification */ + XtUnmapWidget(ih->handle); + } + + /* save the previous position and size */ + iupAttribStoreStr(ih, "_IUPMOT_FS_X", IupGetAttribute(ih, "X")); /* must use IupGetAttribute to check from the native implementation */ + iupAttribStoreStr(ih, "_IUPMOT_FS_Y", IupGetAttribute(ih, "Y")); + iupAttribStoreStr(ih, "_IUPMOT_FS_SIZE", IupGetAttribute(ih, "RASTERSIZE")); + + /* save the previous decoration */ + XtVaGetValues(ih->handle, XmNmwmDecorations, &decor, NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_DECOR", (char*)decor); + + /* remove the decorations */ + XtVaSetValues(ih->handle, XmNmwmDecorations, (XtArgVal)0, NULL); + motDialogSetWindowManagerStyle(ih); + + /* get full screen size */ + iupdrvGetFullSize(&width, &height); + + /* set position and size */ + XtVaSetValues(ih->handle, XmNwidth, (XtArgVal)width, + XmNheight, (XtArgVal)height, + XmNx, (XtArgVal)0, + XmNy, (XtArgVal)0, + NULL); + + /* layout will be updated in motDialogConfigureNotify */ + if (visible) + XtMapWidget(ih->handle); + } + } + } + else + { + char* fs_style = iupAttribGet(ih, "_IUPMOT_FS_STYLE"); + if (fs_style) + { + /* can only switch back from full screen if window was visible */ + /* when fullscreen was set */ + if (iupStrEqualNoCase(fs_style, "VISIBLE")) + { + iupAttribSetStr(ih, "_IUPMOT_FS_STYLE", NULL); + + /* restore the decorations attributes */ + iupAttribStoreStr(ih, "MAXBOX", iupAttribGet(ih, "_IUPMOT_FS_MAXBOX")); + iupAttribStoreStr(ih, "MINBOX", iupAttribGet(ih, "_IUPMOT_FS_MINBOX")); + iupAttribStoreStr(ih, "MENUBOX",iupAttribGet(ih, "_IUPMOT_FS_MENUBOX")); + IupSetAttribute(ih, "TITLE", iupAttribGet(ih, "_IUPMOT_FS_TITLE")); /* TITLE is not stored in the HashTable */ + iupAttribStoreStr(ih, "RESIZE", iupAttribGet(ih, "_IUPMOT_FS_RESIZE")); + iupAttribStoreStr(ih, "BORDER", iupAttribGet(ih, "_IUPMOT_FS_BORDER")); + + if (!motDialogSetFullScreen(ih, 0)) + { + int border, caption, menu, x, y; + int visible = iupdrvDialogIsVisible(ih); + if (visible) + XtUnmapWidget(ih->handle); + + /* restore the decorations */ + XtVaSetValues(ih->handle, XmNmwmDecorations, (XtArgVal)(int)iupAttribGet(ih, "_IUPMOT_FS_DECOR"), NULL); + motDialogSetWindowManagerStyle(ih); + + /* the dialog decoration will not be considered yet in the next XtVaSetValues */ + /* so compensate the decoration when restoring the position and size */ + iupdrvDialogGetDecoration(ih, &border, &caption, &menu); + x = iupAttribGetInt(ih, "_IUPMOT_FS_X") - (border); + y = iupAttribGetInt(ih, "_IUPMOT_FS_Y") - (border+caption+menu); + + /* restore position and size */ + XtVaSetValues(ih->handle, + XmNx, (XtArgVal)x, + XmNy, (XtArgVal)y, + XmNwidth, (XtArgVal)(IupGetInt(ih, "_IUPMOT_FS_SIZE") - (2*border)), + XmNheight, (XtArgVal)(IupGetInt2(ih, "_IUPMOT_FS_SIZE") - (2*border+caption)), + NULL); + + /* layout will be updated in motDialogConfigureNotify */ + if (visible) + XtMapWidget(ih->handle); + + /* remove auxiliar attributes */ + iupAttribSetStr(ih, "_IUPMOT_FS_X", NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_Y", NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_SIZE", NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_DECOR", NULL); + } + + /* remove auxiliar attributes */ + iupAttribSetStr(ih, "_IUPMOT_FS_MAXBOX", NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_MINBOX", NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_MENUBOX",NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_RESIZE", NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_BORDER", NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_TITLE", NULL); + } + } + } + return 1; +} + +static int motDialogSetIconAttrib(Ihandle* ih, const char *value) +{ + if (!value) + XtVaSetValues(ih->handle, XmNiconPixmap, NULL, NULL); + else + { + Pixmap icon = (Pixmap)iupImageGetIcon(value); + Pixmap icon_mask = (Pixmap)iupImageGetMask(value); + if (icon) + XtVaSetValues(ih->handle, XmNiconPixmap, icon, NULL); + if (icon_mask) + XtVaSetValues(ih->handle, XmNiconMask, icon, NULL); + } + return 1; +} + +/**************************************************************** + Callbacks and Events +****************************************************************/ + + +static void motDialogCBclose(Widget w, XtPointer client_data, XtPointer call_data) +{ + Icallback cb; + Ihandle *ih = (Ihandle*)client_data; + if (!ih) return; + (void)call_data; + (void)w; + + /* even when ACTIVE=NO the dialog gets this event */ + if (!iupdrvIsActive(ih)) + return; + + cb = IupGetCallback(ih, "CLOSE_CB"); + if (cb) + { + int ret = cb(ih); + if (ret == IUP_IGNORE) + return; + if (ret == IUP_CLOSE) + IupExitLoop(); + } + + IupHide(ih); /* default: close the window */ +} + +static void motDialogConfigureNotify(Widget w, XEvent *evt, String* s, Cardinal *card) +{ + IFnii cb; + int border, caption, menu; + XConfigureEvent *cevent = (XConfigureEvent *)evt; + Ihandle* ih; + (void)s; + (void)card; + + XtVaGetValues(w, XmNuserData, &ih, NULL); + if (!ih) return; + + if (ih->data->menu && ih->data->menu->handle) + { + XtVaSetValues(ih->data->menu->handle, + XmNwidth, (XtArgVal)(cevent->width), + NULL); + } + + if (ih->data->ignore_resize) return; + + iupdrvDialogGetDecoration(ih, &border, &caption, &menu); + + /* update dialog size */ + ih->currentwidth = cevent->width + 2*border; + ih->currentheight = cevent->height + 2*border + caption; /* menu is inside the dialog_manager */ + + cb = (IFnii)IupGetCallback(ih, "RESIZE_CB"); + if (!cb || cb(ih, cevent->width, cevent->height - menu)!=IUP_IGNORE) /* width and height here are for the client area */ + { + ih->data->ignore_resize = 1; + IupRefresh(ih); + ih->data->ignore_resize = 0; + } +} + +static void motDialogCBStructureNotifyEvent(Widget w, XtPointer data, XEvent *evt, Boolean *cont) +{ + Ihandle *ih = (Ihandle*)data; + int state = -1; + (void)cont; + (void)w; + + switch(evt->type) + { + case MapNotify: + { + if (ih->data->show_state == IUP_MINIMIZE) /* it is a RESTORE. */ + state = IUP_RESTORE; + break; + } + case UnmapNotify: + { + if (ih->data->show_state != IUP_HIDE) /* it is a MINIMIZE. */ + state = IUP_MINIMIZE; + break; + } + } + + if (state < 0) + return; + + if (ih->data->show_state != state) + { + IFni cb; + ih->data->show_state = state; + + cb = (IFni)IupGetCallback(ih, "SHOW_CB"); + if (cb && cb(ih, state) == IUP_CLOSE) + IupExitLoop(); + } +} + +static void motDialogDestroyCallback(Widget w, Ihandle *ih, XtPointer call_data) +{ + /* If the IUP dialog was not destroyed, destroy it here. */ + if (iupObjectCheck(ih)) + IupDestroy(ih); + + /* this callback is usefull to destroy children dialogs when the parent is destroyed. */ + /* The application is responsable for destroying the children before this happen. */ + (void)w; + (void)call_data; +} + + +/**************************************************************** + Idialog +****************************************************************/ + +/* replace the common dialog SetChildrenPosition method because of + the menu that it is inside the dialog. */ +static void motDialogSetChildrenPositionMethod(Ihandle* ih, int x, int y) +{ + int menu_h = motDialogGetMenuSize(ih); + (void)x; + (void)y; + + /* Child coordinates are relative to client left-top corner. */ + iupBaseSetPosition(ih->firstchild, 0, menu_h); +} + +static void* motDialogGetInnerNativeContainerHandleMethod(Ihandle* ih, Ihandle* child) +{ + (void)child; + return XtNameToWidget(ih->handle, "*dialog_manager"); +} + +static int motDialogMapMethod(Ihandle* ih) +{ + Widget dialog_manager; + InativeHandle* parent; + int mwm_decor = 0; + int num_args = 0; + Arg args[20]; + + if (iupAttribGetBoolean(ih, "DIALOGFRAME")) + { + iupAttribSetStr(ih, "RESIZE", "NO"); + iupAttribSetStr(ih, "MAXBOX", "NO"); + iupAttribSetStr(ih, "MINBOX", "NO"); + } + + /****************************/ + /* Create the dialog shell */ + /****************************/ + + if (iupAttribGet(ih, "TITLE")) + mwm_decor |= MWM_DECOR_TITLE; + if (iupAttribGetBoolean(ih, "MENUBOX")) + mwm_decor |= MWM_DECOR_MENU; + if (iupAttribGetBoolean(ih, "MINBOX")) + mwm_decor |= MWM_DECOR_MINIMIZE; + if (iupAttribGetBoolean(ih, "MAXBOX")) + mwm_decor |= MWM_DECOR_MAXIMIZE; + if (iupAttribGetBoolean(ih, "RESIZE")) + mwm_decor |= MWM_DECOR_RESIZEH; + if (iupAttribGetBoolean(ih, "BORDER")) + mwm_decor |= MWM_DECOR_BORDER; + + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* so XtRealizeWidget will not show the dialog */ + iupmotSetArg(args, num_args, XmNdeleteResponse, XmDO_NOTHING); + iupmotSetArg(args, num_args, XmNallowShellResize, True); /* Used so the BulletinBoard can control the shell size */ + iupmotSetArg(args, num_args, XmNtitle, ""); + iupmotSetArg(args, num_args, XmNvisual, iupmot_visual); + + if (iupmotColorMap()) + iupmotSetArg(args, num_args, XmNcolormap, iupmotColorMap()); + + if (mwm_decor != 0x7E) + iupmotSetArg(args, num_args, XmNmwmDecorations, mwm_decor); + + if (iupAttribGetBoolean(ih, "SAVEUNDER")) + iupmotSetArg(args, num_args, XmNsaveUnder, True); + + parent = iupDialogGetNativeParent(ih); + if (parent) + ih->handle = XtCreatePopupShell(NULL, topLevelShellWidgetClass, (Widget)parent, args, num_args); + else + ih->handle = XtAppCreateShell(NULL, "dialog", topLevelShellWidgetClass, iupmot_display, args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + XmAddWMProtocolCallback(ih->handle, iupmot_wm_deletewindow, motDialogCBclose, (XtPointer)ih); + + XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, StructureNotifyMask, False, (XtEventHandler)motDialogCBStructureNotifyEvent, (XtPointer)ih); + + XtAddCallback(ih->handle, XmNdestroyCallback, (XtCallbackProc)motDialogDestroyCallback, (XtPointer)ih); + + /*****************************/ + /* Create the dialog manager */ + /*****************************/ + + dialog_manager = XtVaCreateManagedWidget( + "dialog_manager", + xmBulletinBoardWidgetClass, + ih->handle, + XmNmarginWidth, 0, + XmNmarginHeight, 0, + XmNwidth, 100, /* set this to avoid size calculation problems */ + XmNheight, 100, + XmNborderWidth, 0, + XmNshadowThickness, 0, + XmNnoResize, iupAttribGetBoolean(ih, "RESIZE")? False: True, + XmNresizePolicy, XmRESIZE_NONE, /* no automatic resize of children */ + XmNuserData, ih, /* used only in motDialogConfigureNotify */ + XmNnavigationType, XmTAB_GROUP, + NULL); + + XtOverrideTranslations(dialog_manager, XtParseTranslationTable("<Configure>: iupDialogConfigure()")); + XtAddCallback(dialog_manager, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + XtAddEventHandler(dialog_manager, KeyPressMask, False,(XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + /* child dialogs must be always on top of the parent */ + if (parent) + XSetTransientForHint(iupmot_display, XtWindow(ih->handle), XtWindow(parent)); + + if (mwm_decor != 0x7E) /* some decoration was changed */ + motDialogSetWindowManagerStyle(ih); + + /* Ignore VISIBLE before mapping */ + iupAttribSetStr(ih, "VISIBLE", NULL); + + if (IupGetGlobal("_IUP_RESET_DLGBGCOLOR")) + { + iupmotSetGlobalColorAttrib(dialog_manager, XmNbackground, "DLGBGCOLOR"); + iupmotSetGlobalColorAttrib(dialog_manager, XmNforeground, "DLGFGCOLOR"); + IupSetGlobal("_IUP_RESET_DLGBGCOLOR", NULL); + } + + return IUP_NOERROR; +} + +static void motDialogUnMapMethod(Ihandle* ih) +{ + Widget dialog_manager; + if (ih->data->menu) + { + ih->data->menu->handle = NULL; /* the dialog will destroy the native menu */ + IupDestroy(ih->data->menu); + } + + dialog_manager = XtNameToWidget(ih->handle, "*dialog_manager"); + XtVaSetValues(dialog_manager, XmNuserData, NULL, NULL); + + XtRemoveEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtRemoveEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + XtRemoveEventHandler(ih->handle, StructureNotifyMask, False, (XtEventHandler)motDialogCBStructureNotifyEvent, (XtPointer)ih); + XtRemoveCallback(ih->handle, XmNdestroyCallback, (XtCallbackProc)motDialogDestroyCallback, (XtPointer)ih); + + XtRemoveEventHandler(dialog_manager, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + XtRemoveCallback(dialog_manager, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + + iupdrvBaseUnMapMethod(ih); +} + +static void motDialogLayoutUpdateMethod(Ihandle *ih) +{ + int border, caption, menu; + + if (ih->data->ignore_resize || + iupAttribGet(ih, "_IUPMOT_FS_STYLE")) + return; + + /* for dialogs the position is not updated here */ + ih->data->ignore_resize = 1; + + iupdrvDialogGetDecoration(ih, &border, &caption, &menu); + + if (!iupAttribGetBoolean(ih, "RESIZE")) + { + int width = ih->currentwidth - 2*border; + int height = ih->currentheight - 2*border - caption; + XtVaSetValues(ih->handle, + XmNwidth, width, + XmNheight, height, + XmNminWidth, width, + XmNminHeight, height, + XmNmaxWidth, width, + XmNmaxHeight, height, + NULL); + } + else + { + XtVaSetValues(ih->handle, + XmNwidth, (XtArgVal)(ih->currentwidth - 2*border), /* excluding the border */ + XmNheight, (XtArgVal)(ih->currentheight - 2*border - caption), + NULL); + } + + ih->data->ignore_resize = 0; +} + +/***************************************************************/ + +void iupdrvDialogInitClass(Iclass* ic) +{ + /* Driver Dependent Class methods */ + ic->Map = motDialogMapMethod; + ic->UnMap = motDialogUnMapMethod; + ic->LayoutUpdate = motDialogLayoutUpdateMethod; + ic->SetChildrenPosition = motDialogSetChildrenPositionMethod; + ic->GetInnerNativeContainerHandle = motDialogGetInnerNativeContainerHandleMethod; + + if (!iupmot_wm_deletewindow) + { + /* Set up a translation table that captures "Resize" events + (also called ConfigureNotify or Configure events). */ + XtActionsRec rec = {"iupDialogConfigure", motDialogConfigureNotify}; + XtAppAddActions(iupmot_appcontext, &rec, 1); + + /* register atom to intercept the close button in the window frame */ + iupmot_wm_deletewindow = XmInternAtom(iupmot_display, "WM_DELETE_WINDOW", False); + } + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motDialogSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "X", motDialogGetXAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "Y", motDialogGetYAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + + /* Base Container */ + iupClassRegisterAttribute(ic, "CLIENTSIZE", motDialogGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + + /* Special */ + iupClassRegisterAttribute(ic, "TITLE", motDialogGetTitleAttrib, motDialogSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupDialog only */ + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motDialogSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "ICON", NULL, motDialogSetIconAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FULLSCREEN", NULL, motDialogSetFullScreenAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MINSIZE", NULL, motDialogSetMinSizeAttrib, IUPAF_SAMEASSYSTEM, "1x1", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MAXSIZE", NULL, motDialogSetMaxSizeAttrib, IUPAF_SAMEASSYSTEM, "65535x65535", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SAVEUNDER", NULL, NULL, "YES", NULL, IUPAF_NO_INHERIT); + + /* IupDialog X Only */ + iupClassRegisterAttribute(ic, "XWINDOW", iupmotGetXWindowAttrib, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING); +} diff --git a/iup/src/mot/iupmot_drv.h b/iup/src/mot/iupmot_drv.h new file mode 100755 index 0000000..8a536ef --- /dev/null +++ b/iup/src/mot/iupmot_drv.h @@ -0,0 +1,75 @@ +/** \file + * \brief Motif Driver + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMOT_DRV_H +#define __IUPMOT_DRV_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* global variables, declared in iupmot_open.c */ +extern Widget iupmot_appshell; +extern Display* iupmot_display; +extern int iupmot_screen; +extern XtAppContext iupmot_appcontext; +extern Visual* iupmot_visual; +extern Atom iupmot_wm_deletewindow; + +/* dialog */ +void iupmotDialogSetVisual(Ihandle* ih, void* visual); +void iupmotDialogResetVisual(Ihandle* ih); + +/* focus */ +void iupmotFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont); + +/* key */ +void iupmotCanvasKeyReleaseEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont); +void iupmotKeyPressEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont); +KeySym iupmotKeyCharToKeySym(char c); +void iupmotButtonKeySetStatus(unsigned int state, unsigned int but, char* status, int doubleclick); +void iupmotKeyEncode(int key, unsigned int *keyval, unsigned int *state); + +/* font */ +char* iupmotGetFontListAttrib(Ihandle *ih); +XmFontList iupmotGetFontList(const char* foundry, const char* value); +char* iupmotFindFontList(XmFontList fontlist); +char* iupmotGetFontStructAttrib(Ihandle *ih); +char* iupmotGetFontIdAttrib(Ihandle *ih); + +/* tips */ +/* called from Enter/Leave events to check if a TIP is present. */ +void iupmotTipEnterNotify(Ihandle* ih); +void iupmotTipLeaveNotify(void); +void iupmotTipsFinish(void); + +/* common */ +void iupmotPointerMotionEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont); +void iupmotButtonPressReleaseEvent(Widget w, Ihandle* ih, XEvent* evt, Boolean* cont); +void iupmotEnterLeaveWindowEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont); +void iupmotHelpCallback(Widget w, Ihandle *ih, XtPointer call_data); +void iupmotSetString(Widget w, const char *resource, const char* value); +char* iupmotConvertString(XmString str); +void iupmotSetMnemonicTitle(Ihandle *ih, const char* value); +void iupmotDisableDragSource(Widget w); +void iupmotSetPixmap(Ihandle* ih, const char* name, const char* prop, int make_inactive); +void iupmotSetGlobalColorAttrib(Widget w, const char* xmname, const char* name); +void iupmotSetBgColor(Widget w, Pixel color); +char* iupmotGetBgColorAttrib(Ihandle* ih); + +void iupmotGetWindowSize(Ihandle *ih, int *width, int *height); + +char* iupmotGetXWindowAttrib(Ihandle *ih); + +#define iupmotSetArg(_a, _i, _n, _d) ((_a)[(_i)].name = (_n), (_a)[(_i)].value = (XtArgVal)(_d), (_i)++) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/mot/iupmot_filedlg.c b/iup/src/mot/iupmot_filedlg.c new file mode 100755 index 0000000..768dd2b --- /dev/null +++ b/iup/src/mot/iupmot_filedlg.c @@ -0,0 +1,578 @@ +/** \file + * \brief Motif IupFileDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <Xm/Xm.h> +#include <Xm/MwmUtil.h> +#include <Xm/FileSB.h> +#include <Xm/Protocols.h> +#include <Xm/SelectioB.h> +#include <Xm/MessageB.h> +#include <Xm/DrawingA.h> +#include <Xm/PushB.h> +#include <Xm/Frame.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drvinfo.h" +#include "iup_dialog.h" +#include "iup_strmessage.h" +#include "iup_drvinfo.h" + +#include "iupmot_drv.h" + + +enum {IUP_DIALOGOPEN, IUP_DIALOGSAVE, IUP_DIALOGDIR}; + +static void motFileDlgAskUserCallback(Widget w, int* ret_code, XmSelectionBoxCallbackStruct* cbs) +{ + if (cbs->reason == XmCR_OK) + *ret_code = 1; + else + *ret_code = -1; + XtDestroyWidget(XtParent(w)); +} + +static int motFileDlgAskUser(Widget parent, const char* message) +{ + Widget questionbox; + Arg args[3]; + int ret_code = 0; + XmString title; + + XtSetArg(args[0], XmNautoUnmanage, False); + XtSetArg(args[1], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); + XtSetArg(args[2], XmNnoResize, True); + questionbox = XmCreateQuestionDialog(parent, "filedlg_question", args, 3); + iupmotSetString(questionbox, XmNmessageString, message); + XtVaGetValues(parent, XmNdialogTitle, &title, NULL); + XtVaSetValues(questionbox, XmNdialogTitle, title, NULL); + + XtAddCallback(questionbox, XmNokCallback, (XtCallbackProc)motFileDlgAskUserCallback, (XtPointer)&ret_code); + XtAddCallback(questionbox, XmNcancelCallback, (XtCallbackProc)motFileDlgAskUserCallback, (XtPointer)&ret_code); + XtUnmanageChild(XmMessageBoxGetChild(questionbox, XmDIALOG_HELP_BUTTON)); + XtManageChild(questionbox); + + while (ret_code == 0) + XtAppProcessEvent(iupmot_appcontext, XtIMAll); + + XtUnmanageChild(questionbox); + + if (ret_code == 1) + return 1; + else + return 0; +} + +static int motFileDlgCheckValue(Ihandle* ih, Widget w) +{ + char* value = iupAttribGet(ih, "VALUE"); + int dialogtype = iupAttribGetInt(ih, "_IUPDLG_DIALOGTYPE"); + + if (dialogtype == IUP_DIALOGDIR) + { + if (!iupdrvIsDirectory(value)) /* if does not exist or not a directory */ + { + iupStrMessageShowError(ih, "IUP_INVALIDDIR"); + return 0; + } + } + else + { + if (iupdrvIsDirectory(value)) /* selected a directory */ + { + iupStrMessageShowError(ih, "IUP_INVALIDDIR"); + return 0; + } + else if (!iupdrvIsFile(value)) /* new file */ + { + value = iupAttribGet(ih, "ALLOWNEW"); + if (!value) + { + if (dialogtype == IUP_DIALOGSAVE) + value = "YES"; + else + value = "NO"; + } + + if (!iupStrBoolean(value)) + { + iupStrMessageShowError(ih, "IUP_FILENOTEXIST"); + return 0; + } + } + else if (dialogtype == IUP_DIALOGSAVE && !iupAttribGetInt(ih, "NOOVERWRITEPROMPT")) + { + if (!motFileDlgAskUser(w, iupStrMessageGet("IUP_FILEOVERWRITE"))) + return 0; + } + } + + return 1; +} + +static void motFileDlgCBclose(Widget w, XtPointer client_data, XtPointer call_data) +{ + Ihandle *ih = (Ihandle*)client_data; + if (!ih) return; + (void)call_data; + (void)w; + iupAttribSetStr(ih, "VALUE", NULL); + iupAttribSetStr(ih, "STATUS", "-1"); + iupAttribSetStr(ih, "_IUP_WM_DELETE", "1"); +} + +static void motFileDlgCallback(Widget w, Ihandle* ih, XmFileSelectionBoxCallbackStruct* call_data) +{ + (void)w; + if (call_data->reason == XmCR_OK) + { + int dialogtype = iupAttribGetInt(ih, "_IUPDLG_DIALOGTYPE"); + char* filename; + XmStringGetLtoR(call_data->value, XmSTRING_DEFAULT_CHARSET, &filename); + iupAttribStoreStr(ih, "VALUE", filename); + XtFree(filename); + + if (!motFileDlgCheckValue(ih, w)) + return; + + if (dialogtype == IUP_DIALOGDIR) + { + iupAttribSetStr(ih, "STATUS", "0"); + iupAttribSetStr(ih, "FILEEXIST", NULL); + } + else + { + IFnss file_cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + if (file_cb && file_cb(ih, iupAttribGet(ih, "VALUE"), "OK") == IUP_IGNORE) + return; + + if (iupdrvIsFile(iupAttribGet(ih, "VALUE"))) /* check if file exists */ + { + iupAttribSetStr(ih, "FILEEXIST", "YES"); + iupAttribSetStr(ih, "STATUS", "0"); + } + else + { + iupAttribSetStr(ih, "FILEEXIST", "NO"); + iupAttribSetStr(ih, "STATUS", "1"); + } + } + + if (!iupAttribGetBoolean(ih, "NOCHANGEDIR")) /* do change the current directory */ + { + /* XmFileSelection does not change the current directory */ + XmString xm_dir; + char* dir; + XtVaGetValues(w, XmNdirectory, &xm_dir, NULL); + XmStringGetLtoR(xm_dir, XmSTRING_DEFAULT_CHARSET, &dir); + iupdrvSetCurrentDirectory(dir); + XtFree(dir); + } + } + else if (call_data->reason == XmCR_CANCEL) + { + iupAttribSetStr(ih, "VALUE", NULL); + iupAttribSetStr(ih, "FILEEXIST", NULL); + iupAttribSetStr(ih, "STATUS", "-1"); + } +} + +static void motFileDlgHelpCallback(Widget w, XtPointer client_data, XtPointer call_data) +{ + Ihandle *ih = (Ihandle*)client_data; + Icallback cb = IupGetCallback(ih, "HELP_CB"); + if (cb && cb(ih) == IUP_CLOSE) + { + iupAttribSetStr(ih, "VALUE", NULL); + iupAttribSetStr(ih, "FILEEXIST", NULL); + iupAttribSetStr(ih, "STATUS", "-1"); + } + + (void)call_data; + (void)w; +} + +typedef struct _ImotPromt +{ + XmString xm_dir; + int ret_code; +} ImotPromt; + +static void motFileDlgPromptCallback(Widget w, ImotPromt* prompt, XmSelectionBoxCallbackStruct* cbs) +{ + if (cbs->reason == XmCR_OK) + prompt->xm_dir = XmStringCopy(cbs->value); + + prompt->ret_code = 1; + XtDestroyWidget(XtParent(w)); +} + +static XmString motFileDlgPrompt(Widget parent, const char* message) +{ + Widget promptbox; + Arg args[2]; + ImotPromt prompt; + XmString title; + + XtSetArg(args[0], XmNautoUnmanage, False); + XtSetArg(args[1], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); + promptbox = XmCreatePromptDialog(parent, "filedlg_prompt", args, 2); + iupmotSetString(promptbox, XmNselectionLabelString, message); + XtVaGetValues(parent, XmNdialogTitle, &title, NULL); + XtVaSetValues(promptbox, XmNdialogTitle, title, NULL); + + prompt.ret_code = 0; + prompt.xm_dir = NULL; + + XtAddCallback(promptbox, XmNokCallback, (XtCallbackProc)motFileDlgPromptCallback, (XtPointer)&prompt); + XtAddCallback(promptbox, XmNcancelCallback, (XtCallbackProc)motFileDlgPromptCallback, (XtPointer)&prompt); + XtUnmanageChild(XmSelectionBoxGetChild(promptbox, XmDIALOG_HELP_BUTTON)); + XtManageChild(promptbox); + + while (prompt.ret_code == 0) + XtAppProcessEvent(iupmot_appcontext, XtIMAll); + + XtUnmanageChild(promptbox); + + return prompt.xm_dir; +} + +static void motFileDlgNewFolderCallback(Widget w, Widget filebox, XtPointer call_data) +{ + XmString xm_new_dir = motFileDlgPrompt(filebox, iupStrMessageGet("IUP_NAMENEWFOLDER")); + if (xm_new_dir) + { + XmString xm_dir; + XtVaGetValues(filebox, XmNdirectory, &xm_dir, NULL); + xm_dir = XmStringConcat(xm_dir, xm_new_dir); + + { + char* dir; + XmStringGetLtoR(xm_dir, XmSTRING_DEFAULT_CHARSET, &dir); + iupdrvMakeDirectory(dir); + XtFree(dir); + } + + XtVaSetValues(filebox, XmNdirectory, xm_dir, NULL); + + XmStringFree(xm_dir); + XmStringFree(xm_new_dir); + } + + (void)call_data; + (void)w; +} + +static void motFileDlgPreviewCanvasResizeCallback(Widget w, Ihandle *ih, XtPointer call_data) +{ + Dimension width, height; + XtVaGetValues(w, XmNwidth, &width, + XmNheight, &height, + NULL); + + iupAttribSetInt(ih, "PREVIEWWIDTH", width); + iupAttribSetInt(ih, "PREVIEWHEIGHT", height); + + (void)call_data; +} + +static void motFileDlgUpdatePreviewGLCanvas(Ihandle* ih) +{ + Ihandle* glcanvas = IupGetAttributeHandle(ih, "PREVIEWGLCANVAS"); + if (glcanvas) + { + iupAttribSetStr(glcanvas, "XWINDOW", iupAttribGet(ih, "XWINDOW")); + glcanvas->iclass->Map(glcanvas); + } +} + +static void motFileDlgPreviewCanvasInit(Ihandle *ih, Widget w) +{ + XSetWindowAttributes attrs; + GC gc = XCreateGC(iupmot_display, XtWindow(w), 0, NULL); + iupAttribSetStr(ih, "PREVIEWDC", (char*)gc); + iupAttribSetStr(ih, "WID", (char*)w); + + iupAttribSetStr(ih, "XWINDOW", (char*)XtWindow(w)); + iupAttribSetStr(ih, "XDISPLAY", (char*)iupmot_display); + motFileDlgUpdatePreviewGLCanvas(ih); + + attrs.bit_gravity = ForgetGravity; /* For the DrawingArea widget gets Expose events when you resize it to be smaller. */ + attrs.background_pixmap = None; + XChangeWindowAttributes(iupmot_display, XtWindow(w), CWBitGravity|CWBackPixmap, &attrs); +} + +static void motFileDlgPreviewCanvasExposeCallback(Widget w, Ihandle *ih, XtPointer call_data) +{ + Widget filebox = (Widget)iupAttribGet(ih, "_IUPDLG_FILEBOX"); + char* filename; + XmString xm_file; + IFnss cb; + + if (!iupAttribGet(ih, "PREVIEWDC")) + motFileDlgPreviewCanvasInit(ih, w); + + XtVaGetValues(filebox, XmNdirSpec, &xm_file, NULL); + XmStringGetLtoR(xm_file, XmSTRING_DEFAULT_CHARSET, &filename); + + cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + if (iupdrvIsFile(filename)) + cb(ih, filename, "PAINT"); + else + cb(ih, NULL, "PAINT"); + + XtFree(filename); + (void)call_data; + (void)w; +} + +static void motFileDlgBrowseSelectionCallback(Widget w, Ihandle* ih, XmListCallbackStruct* list_data) +{ + char* filename; + + XmStringGetLtoR(list_data->item, XmSTRING_DEFAULT_CHARSET, &filename); + + if (iupdrvIsFile(filename)) + { + IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + cb(ih, filename, "SELECT"); + } + + XtFree(filename); + (void)w; +} + +static int motFileDlgPopup(Ihandle* ih, int x, int y) +{ + InativeHandle* parent = iupDialogGetNativeParent(ih); + Widget filebox, dialog; + int dialogtype, style = XmDIALOG_FULL_APPLICATION_MODAL; + IFnss file_cb = NULL; + Widget preview_canvas = NULL; + char* value; + + iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */ + iupAttribSetInt(ih, "_IUPDLG_Y", y); + + value = iupAttribGetStr(ih, "DIALOGTYPE"); + if (iupStrEqualNoCase(value, "SAVE")) + dialogtype = IUP_DIALOGSAVE; + else if (iupStrEqualNoCase(value, "DIR")) + dialogtype = IUP_DIALOGDIR; + else + dialogtype = IUP_DIALOGOPEN; + iupAttribSetInt(ih, "_IUPDLG_DIALOGTYPE", dialogtype); + + if (parent) + { + filebox = XmCreateFileSelectionDialog(parent, "filedialog", NULL, 0); + dialog = XtParent(filebox); + } + else + { + dialog = XtAppCreateShell(NULL, "filedialog", topLevelShellWidgetClass, iupmot_display, NULL, 0); + filebox = XmCreateFileSelectionBox(dialog, "filebox", NULL, 0); + style = XmDIALOG_MODELESS; + XtVaSetValues(dialog, + XmNmwmInputMode, MWM_INPUT_FULL_APPLICATION_MODAL, + XmNmappedWhenManaged, False, + XmNsaveUnder, True, + NULL); + } + if (!filebox) + return IUP_NOERROR; + + if (!iupAttribGetBoolean(ih, "SHOWHIDDEN")) + XtVaSetValues(filebox, XmNfileFilterStyle, XmFILTER_HIDDEN_FILES, NULL); + + value = iupAttribGet(ih, "TITLE"); + if (!value) + { + if (dialogtype == IUP_DIALOGSAVE) + value = "IUP_SAVEAS"; + else if (dialogtype == IUP_DIALOGOPEN) + value = "IUP_OPEN"; + else + value = "IUP_SELECTDIR"; + iupAttribSetStr(ih, "TITLE", iupStrMessageGet(value)); + } + iupmotSetString(filebox, XmNdialogTitle, value); + + XtVaSetValues(filebox, + XmNdialogStyle, style, + XmNautoUnmanage, False, + NULL); + + if (dialogtype == IUP_DIALOGDIR) + XtVaSetValues(filebox, XmNfileTypeMask, XmFILE_DIRECTORY, NULL); + + /* just check for the path inside FILE */ + value = iupAttribGet(ih, "FILE"); + if (value && value[0] == '/') + { + char* dir = iupStrFileGetPath(value); + iupAttribStoreStr(ih, "DIRECTORY", dir); + free(dir); + } + + /* set XmNdirectory before XmNpattern and before XmNdirSpec */ + + value = iupAttribGet(ih, "DIRECTORY"); + if (value) + iupmotSetString(filebox, XmNdirectory, value); + + value = iupAttribGet(ih, "FILTER"); + if (value) + { + char *filter = value; + char *p = strchr(value, ';'); + if (p) + { + int size = p-value; + filter = (char*)malloc(size+1); + memcpy(filter, value, size); + filter[size] = 0; + } + + iupmotSetString(filebox, XmNpattern, filter); + + if (filter != value) + free(filter); + } + + value = iupAttribGet(ih, "FILE"); + if (value) + { + char* file = value; + + if (value[0] != '/') /* if does not contains a full path, then add the directory */ + { + char* cur_dir = NULL; + char* dir = iupAttribGet(ih, "DIRECTORY"); + if (!dir) + { + cur_dir = iupdrvGetCurrentDirectory(); + dir = cur_dir; + } + + file = iupStrFileMakeFileName(dir, value); + + if (cur_dir) + free(cur_dir); + } + + /* clear value before setting. Do not know why we have to do this, + but if not cleared it will fail to set the XmNdirSpec value. */ + iupmotSetString(filebox, XmNdirSpec, ""); + iupmotSetString(filebox, XmNdirSpec, file); + + if (file != value) + free(file); + } + + if (!IupGetCallback(ih, "HELP_CB")) + XtUnmanageChild(XmFileSelectionBoxGetChild(filebox, XmDIALOG_HELP_BUTTON)); + + XtAddCallback(filebox, XmNokCallback, (XtCallbackProc)motFileDlgCallback, (XtPointer)ih); + XtAddCallback(filebox, XmNcancelCallback, (XtCallbackProc)motFileDlgCallback, (XtPointer)ih); + XtAddCallback(filebox, XmNhelpCallback, (XtCallbackProc)motFileDlgHelpCallback, (XtPointer)ih); + + if (dialogtype == IUP_DIALOGDIR) + { + Widget new_folder = XtVaCreateManagedWidget("new_folder", xmPushButtonWidgetClass, filebox, + XmNlabelType, XmSTRING, + NULL); + iupmotSetString(new_folder, XmNlabelString, iupStrMessageGet("IUP_CREATEFOLDER")); + XtAddCallback(new_folder, XmNactivateCallback, (XtCallbackProc)motFileDlgNewFolderCallback, (XtPointer)filebox); + } + else + { + file_cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + if (file_cb) + { + Widget file_list = XmFileSelectionBoxGetChild(filebox, XmDIALOG_LIST); + XtAddCallback(file_list, XmNbrowseSelectionCallback, (XtCallbackProc)motFileDlgBrowseSelectionCallback, (XtPointer)ih); + + if (iupAttribGetBoolean(ih, "SHOWPREVIEW")) + { + Widget frame = XtVaCreateManagedWidget("preview_canvas", xmFrameWidgetClass, filebox, + XmNshadowType, XmSHADOW_ETCHED_IN, + NULL); + + preview_canvas = XtVaCreateManagedWidget("preview_canvas", xmDrawingAreaWidgetClass, frame, + XmNwidth, 180, + XmNheight, 150, + XmNresizePolicy, XmRESIZE_GROW, + NULL); + + XtAddCallback(preview_canvas, XmNexposeCallback, (XtCallbackProc)motFileDlgPreviewCanvasExposeCallback, (XtPointer)ih); + XtAddCallback(preview_canvas, XmNresizeCallback, (XtCallbackProc)motFileDlgPreviewCanvasResizeCallback, (XtPointer)ih); + + iupAttribSetStr(ih, "_IUPDLG_FILEBOX", (char*)filebox); + } + } + } + + XmAddWMProtocolCallback(dialog, iupmot_wm_deletewindow, motFileDlgCBclose, (XtPointer)ih); + XtManageChild(filebox); + + XtRealizeWidget(dialog); + ih->handle = dialog; + iupDialogUpdatePosition(ih); + ih->handle = NULL; /* reset handle */ + + if (file_cb) + { + if (preview_canvas) + motFileDlgPreviewCanvasInit(ih, preview_canvas); + + file_cb(ih, NULL, "INIT"); + } + + if (style == XmDIALOG_MODELESS) + XtPopup(dialog, XtGrabExclusive); + + /* while the user hasn't provided an answer, simulate main loop. + ** The answer changes as soon as the user selects one of the + ** buttons and the callback routine changes its value. */ + iupAttribSetStr(ih, "STATUS", NULL); + while (iupAttribGet(ih, "STATUS") == NULL) + XtAppProcessEvent(iupmot_appcontext, XtIMAll); + + if (file_cb) + { + if (preview_canvas) + XFreeGC(iupmot_display, (GC)iupAttribGet(ih, "PREVIEWDC")); + + file_cb(ih, NULL, "FINISH"); + } + + if (!iupAttribGet(ih, "_IUP_WM_DELETE")) + { + XtUnmanageChild(filebox); + + if (style == XmDIALOG_MODELESS) + { + XtPopdown(dialog); + XtDestroyWidget(dialog); + } + } + + return IUP_NOERROR; +} + +void iupdrvFileDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = motFileDlgPopup; +} diff --git a/iup/src/mot/iupmot_focus.c b/iup/src/mot/iupmot_focus.c new file mode 100755 index 0000000..5b09bd9 --- /dev/null +++ b/iup/src/mot/iupmot_focus.c @@ -0,0 +1,35 @@ +/** \file + * \brief Motif Focus + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> + +#include <stdio.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_focus.h" +#include "iup_attrib.h" +#include "iup_assert.h" +#include "iup_drv.h" + +#include "iupmot_drv.h" + +void iupdrvSetFocus(Ihandle *ih) +{ + XmProcessTraversal(ih->handle, XmTRAVERSE_CURRENT); +} + +void iupmotFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + (void)w; + (void)cont; + + if (evt->type == FocusIn) + iupCallGetFocusCb(ih); + else if (evt->type == FocusOut) + iupCallKillFocusCb(ih); +} diff --git a/iup/src/mot/iupmot_font.c b/iup/src/mot/iupmot_font.c new file mode 100755 index 0000000..8da06dd --- /dev/null +++ b/iup/src/mot/iupmot_font.c @@ -0,0 +1,443 @@ +/** \file + * \brief Motif Font mapping + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> + +#include <Xm/Xm.h> +#include <Xm/XmP.h> + +#include "iup.h" + +#include "iup_str.h" +#include "iup_attrib.h" +#include "iup_array.h" +#include "iup_object.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_assert.h" + +#include "iupmot_drv.h" + + +typedef struct _ImotFont +{ + char standardfont[1024]; + char xlfd[1024]; /* X-Windows Font Description */ + XmFontList fontlist; /* same as XmRenderTable */ + XFontStruct *fontstruct; + int charwidth, charheight; +} ImotFont; + +static Iarray* mot_fonts = NULL; + +static int motGetFontSize(char* font_name) +{ + int i = 0; + while (i < 8) + { + font_name = strchr(font_name, '-')+1; + i++; + } + + *(strchr(font_name, '-')) = 0; + return atoi(font_name); +} + +static XFontStruct* motLoadFont(const char* foundry, const char *typeface, int size, int bold, int italic, char *xlfd) +{ + XFontStruct* fontstruct; + char font_name[1024]; + char **font_names_list; + char *weight, *slant; + int i, num_fonts, font_size, near_size; + + /* no underline or strikeout support */ + + if (iupStrEqualNoCase(typeface, "System")) + typeface = "fixed"; + + if (!foundry) foundry = "*"; + + if (iupStrEqualNoCase(typeface, "fixed")) + foundry = "misc"; + + if (bold) + weight = "bold"; + else + weight = "medium"; + + if (italic) + slant = "i"; + else + slant = "r"; + + sprintf(font_name,"-%s-%s-%s-%s-*-*-*-*-*-*-*-*-*-*", foundry, typeface, weight, slant); + + font_names_list = XListFonts(iupmot_display, font_name, 32767, &num_fonts); + if (!num_fonts) + { + /* try changing 'i' to 'o', for italic */ + if (italic) + { + slant = "o"; + strstr(font_name, "-i-")[1] = 'o'; + font_names_list = XListFonts(iupmot_display, font_name, 32767, &num_fonts); + } + + if (!num_fonts) + return NULL; + } + + if (size < 0) /* if in pixels convert to points */ + { + double res = ((double)DisplayWidth(iupmot_display, iupmot_screen) / (double)DisplayWidthMM(iupmot_display, iupmot_screen)); /* pixels/mm */ + /* 1 point = 1/72 inch 1 inch = 25.4 mm */ + /* pixel = ((point/72)*25.4)*pixel/mm */ + size = (int)((-size/res)*2.83464567 + 0.5); /* from pixels to points */ + } + + size *= 10; /* convert to deci-points */ + + near_size = -1000; + for (i=0; i<num_fonts; i++) + { + font_size = motGetFontSize(font_names_list[i]); + + if (font_size == size) + { + near_size = font_size; + break; + } + + if (abs(font_size-size) < abs(near_size-size)) + near_size = font_size; + } + + XFreeFontNames(font_names_list); + + sprintf(font_name,"-%s-%s-%s-%s-*-*-*-%d-*-*-*-*-*-*", foundry, typeface, weight, slant, near_size); + fontstruct = XLoadQueryFont(iupmot_display, font_name); + + if (fontstruct) + strcpy(xlfd, font_name); + + return fontstruct; +} + +static XmFontList motFontCreateRenderTable(XFontStruct* fontstruct, int is_underline, int is_strikeout) +{ + XmFontList fontlist; + XmRendition rendition; + Arg args[10]; + int num_args = 0; + + iupmotSetArg(args, num_args, XmNfontType, XmFONT_IS_FONT); + iupmotSetArg(args, num_args, XmNfont, (XtPointer)fontstruct); + iupmotSetArg(args, num_args, XmNloadModel, XmLOAD_IMMEDIATE); + + if (is_underline) + iupmotSetArg(args, num_args, XmNunderlineType, XmSINGLE_LINE); + else + iupmotSetArg(args, num_args, XmNunderlineType, XmNO_LINE); + + if (is_strikeout) + iupmotSetArg(args, num_args, XmNstrikethruType, XmSINGLE_LINE); + else + iupmotSetArg(args, num_args, XmNstrikethruType, XmNO_LINE); + + rendition = XmRenditionCreate(NULL, "", args, num_args); + + fontlist = XmRenderTableAddRenditions(NULL, &rendition, 1, XmDUPLICATE); + + XmRenditionFree(rendition); + + return fontlist; +} + +static int motFontCalcCharWidth(XFontStruct *fontstruct) +{ + if (fontstruct->per_char) + { + int i, all=0; + int first = fontstruct->min_char_or_byte2; + int last = fontstruct->max_char_or_byte2; + if (first < 32) first = 32; /* space */ + if (last > 126) last = 126; /* tilde */ + for (i=first; i<=last; i++) + all += fontstruct->per_char[i].width; + return all/(last-first + 1); /* average character width */ + } + else + return fontstruct->max_bounds.width; +} + +static ImotFont* motFindFont(const char* foundry, const char *standardfont) +{ + char xlfd[1024]; + XFontStruct* fontstruct; + int i, count = iupArrayCount(mot_fonts); + int is_underline = 0, is_strikeout = 0; + + ImotFont* fonts = (ImotFont*)iupArrayGetData(mot_fonts); + + /* Check if the standardfont already exists in cache */ + for (i = 0; i < count; i++) + { + if (iupStrEqualNoCase(standardfont, fonts[i].standardfont)) + return &fonts[i]; + } + + /* not found, create a new one */ + if (standardfont[0] == '-') + { + fontstruct = XLoadQueryFont(iupmot_display, standardfont); + if (!fontstruct) return NULL; + strcpy(xlfd, standardfont); + } + else + { + int size = 0, + is_bold = 0, + is_italic = 0; + char typeface[1024]; + const char* mapped_name; + + if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + return NULL; + + mapped_name = iupFontGetXName(typeface); + if (mapped_name) + strcpy(typeface, mapped_name); + + fontstruct = motLoadFont(foundry, typeface, size, is_bold, is_italic, xlfd); + if (!fontstruct) return NULL; + } + + /* create room in the array */ + fonts = (ImotFont*)iupArrayInc(mot_fonts); + + strcpy(fonts[i].standardfont, standardfont); + strcpy(fonts[i].xlfd, xlfd); + fonts[i].fontstruct = fontstruct; + fonts[i].fontlist = motFontCreateRenderTable(fontstruct, is_underline, is_strikeout); + fonts[i].charwidth = motFontCalcCharWidth(fontstruct); + fonts[i].charheight = fontstruct->ascent + fontstruct->descent; + + return &fonts[i]; +} + +char* iupdrvGetSystemFont(void) +{ + static char systemfont[200] = ""; + ImotFont* motfont = NULL; + char* font = XGetDefault(iupmot_display, "Iup", "fontList"); + if (font) + motfont = motFindFont(NULL, font); + + if (!motfont) + { + font = "Fixed, 11"; + motfont = motFindFont("misc", font); + } + + strcpy(systemfont, font); + return systemfont; +} + +char* iupmotFindFontList(XmFontList fontlist) +{ + int i, count = iupArrayCount(mot_fonts); + ImotFont* fonts = (ImotFont*)iupArrayGetData(mot_fonts); + + /* Check if the standardfont already exists in cache */ + for (i = 0; i < count; i++) + { + if (fontlist == fonts[i].fontlist) + return fonts[i].standardfont; + } + + return NULL; +} + +XmFontList iupmotGetFontList(const char* foundry, const char* value) +{ + ImotFont *motfont = motFindFont(foundry, value); + if (!motfont) + { + iupERROR1("Failed to create Font: %s", value); + return NULL; + } + + return motfont->fontlist; +} + +static ImotFont* motFontCreateNativeFont(Ihandle* ih, const char* value) +{ + ImotFont *motfont = motFindFont(iupAttribGet(ih, "FOUNDRY"), value); + if (!motfont) + { + iupERROR1("Failed to create Font: %s", value); + return NULL; + } + + iupAttribSetStr(ih, "_IUPMOT_FONT", (char*)motfont); + iupAttribSetStr(ih, "XLFD", motfont->xlfd); + return motfont; +} + +static ImotFont* motGetFont(Ihandle *ih) +{ + ImotFont* motfont = (ImotFont*)iupAttribGet(ih, "_IUPMOT_FONT"); + if (!motfont) + motfont = motFontCreateNativeFont(ih, iupGetFontAttrib(ih)); + return motfont; +} + +char* iupmotGetFontListAttrib(Ihandle *ih) +{ + ImotFont* motfont = motGetFont(ih); + if (!motfont) + return NULL; + else + return (char*)motfont->fontlist; +} + +char* iupmotGetFontStructAttrib(Ihandle *ih) +{ + ImotFont* motfont = motGetFont(ih); + if (!motfont) + return NULL; + else + return (char*)motfont->fontstruct; +} + +char* iupmotGetFontIdAttrib(Ihandle *ih) +{ + ImotFont* motfont = motGetFont(ih); + if (!motfont) + return NULL; + else + return (char*)motfont->fontstruct->fid; +} + +int iupdrvSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + ImotFont *motfont = motFontCreateNativeFont(ih, value); + if (!motfont) + return 1; + + /* If FONT is changed, must update the SIZE attribute */ + iupBaseUpdateSizeFromFont(ih); + + /* FONT attribute must be able to be set before mapping, + so the font is enable for size calculation. */ + if (ih->handle && (ih->iclass->nativetype != IUP_TYPEVOID)) + XtVaSetValues(ih->handle, XmNrenderTable, motfont->fontlist, NULL); + + return 1; +} + +int iupdrvFontGetStringWidth(Ihandle* ih, const char* str) +{ + XFontStruct* fontstruct; + int len; + char* line_end; + + if (!str || str[0]==0) + return 0; + + fontstruct = (XFontStruct*)iupmotGetFontStructAttrib(ih); + if (!fontstruct) + return 0; + + line_end = strchr(str, '\n'); + if (line_end) + len = line_end-str; + else + len = strlen(str); + + return XTextWidth(fontstruct, str, len); +} + +void iupdrvFontGetMultiLineStringSize(Ihandle* ih, const char* str, int *w, int *h) +{ + int num_lin, max_w; + + ImotFont* motfont = motGetFont(ih); + if (!motfont) + { + if (w) *w = 0; + if (h) *h = 0; + return; + } + + if (!str) + { + if (w) *w = 0; + if (h) *h = motfont->charheight * 1; + return; + } + + max_w = 0; + num_lin = 1; + if (str[0]) + { + int len, lw; + const char *nextstr; + const char *curstr = str; + do + { + nextstr = iupStrNextLine(curstr, &len); + lw = XTextWidth(motfont->fontstruct, curstr, len); + max_w = iupMAX(max_w, lw); + + curstr = nextstr; + if (*nextstr) + num_lin++; + } while(*nextstr); + } + + if (w) *w = max_w; + if (h) *h = motfont->charheight * num_lin; +} + + +void iupdrvFontGetCharSize(Ihandle* ih, int *charwidth, int *charheight) +{ + ImotFont* motfont = motGetFont(ih); + if (!motfont) + { + if (charwidth) *charwidth = 0; + if (charheight) *charheight = 0; + return; + } + + if (charheight) + *charheight = motfont->charheight; + + if (charwidth) + *charwidth = motfont->charwidth; +} + +void iupdrvFontInit(void) +{ + mot_fonts = iupArrayCreate(50, sizeof(ImotFont)); +} + +void iupdrvFontFinish(void) +{ + int i, count = iupArrayCount(mot_fonts); + ImotFont* fonts = (ImotFont*)iupArrayGetData(mot_fonts); + for (i = 0; i < count; i++) + { + XmFontListFree(fonts[i].fontlist); + fonts[i].fontlist = NULL; + XFreeFont(iupmot_display, fonts[i].fontstruct); + fonts[i].fontstruct = NULL; + } + iupArrayDestroy(mot_fonts); +} diff --git a/iup/src/mot/iupmot_fontdlg.c b/iup/src/mot/iupmot_fontdlg.c new file mode 100755 index 0000000..42767b2 --- /dev/null +++ b/iup/src/mot/iupmot_fontdlg.c @@ -0,0 +1,31 @@ +/** \file + * \brief IupFontDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drvinfo.h" +#include "iup_dialog.h" + +#include "iupmot_drv.h" + + +static int motFontDlgPopup(Ihandle* ih, int x, int y) +{ + (void)ih; + (void)x; + (void)y; + return IUP_ERROR; +} + +void iupdrvFontDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = motFontDlgPopup; +} diff --git a/iup/src/mot/iupmot_frame.c b/iup/src/mot/iupmot_frame.c new file mode 100755 index 0000000..39de5d8 --- /dev/null +++ b/iup/src/mot/iupmot_frame.c @@ -0,0 +1,257 @@ +/** \file + * \brief Frame Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/Frame.h> +#include <Xm/Label.h> +#include <Xm/BulletinB.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_dialog.h" +#include "iup_image.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +void iupdrvFrameGetDecorOffset(Ihandle* ih, int *x, int *y) +{ + (void)ih; + *x = 0; + *y = 0; +} + +static int motFrameSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color; + + /* ignore given value, must use only from parent */ + value = iupBaseNativeParentGetBgColor(ih); + + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + Widget title_label, child_manager; + + iupmotSetBgColor(ih->handle, color); + + child_manager = XtNameToWidget(ih->handle, "*child_manager"); + iupmotSetBgColor(child_manager, color); + + title_label = XtNameToWidget(ih->handle, "*title_label"); + if (!title_label) return 1; + iupmotSetBgColor(title_label, color); + + return 1; + } + return 0; +} + +static int motFrameSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + Pixel color; + + /* ignore given value, must use only from parent */ + value = iupAttribGetInheritNativeParent(ih, "BACKGROUND"); + + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + Widget title_label, child_manager; + + iupmotSetBgColor(ih->handle, color); + + child_manager = XtNameToWidget(ih->handle, "*child_manager"); + iupmotSetBgColor(child_manager, color); + + title_label = XtNameToWidget(ih->handle, "*title_label"); + if (!title_label) return 1; + iupmotSetBgColor(title_label, color); + + return 1; + } + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + if (pixmap) + { + Widget child_manager = XtNameToWidget(ih->handle, "*child_manager"); + Widget title_label = XtNameToWidget(ih->handle, "*title_label"); + + XtVaSetValues(child_manager, XmNbackgroundPixmap, pixmap, NULL); + if (title_label) + XtVaSetValues(title_label, XmNbackgroundPixmap, pixmap, NULL); + + return 1; + } + } + return 0; +} + +static int motFrameSetFgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + Widget title_label = XtNameToWidget(ih->handle, "*title_label"); + if (!title_label) return 0; + XtVaSetValues(title_label, XmNforeground, color, NULL); + return 1; + } + return 0; +} + +static int motFrameSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + iupdrvSetStandardFontAttrib(ih, value); + + if (ih->handle) + { + XmFontList fontlist; + Widget title_label = XtNameToWidget(ih->handle, "*title_label"); + if (!title_label) return 1; + + fontlist = (XmFontList)iupmotGetFontListAttrib(ih); + XtVaSetValues(title_label, XmNrenderTable, fontlist, NULL); + } + + return 1; +} + +static int motFrameSetTitleAttrib(Ihandle* ih, const char* value) +{ + Widget title_label = XtNameToWidget(ih->handle, "*title_label"); + if (title_label) + { + if (!value) value = ""; + iupmotSetString(title_label, XmNlabelString, value); + return 1; + } + return 0; +} + +static void* motFrameGetInnerNativeContainerHandleMethod(Ihandle* ih, Ihandle* child) +{ + (void)child; + return XtNameToWidget(ih->handle, "*child_manager"); +} + +static int motFrameMapMethod(Ihandle* ih) +{ + char *title; + int num_args = 0; + Arg args[20]; + Widget child_manager; + + if (!ih->parent) + return IUP_ERROR; + + title = iupAttribGet(ih, "TITLE"); + + if (title) + iupAttribSetStr(ih, "_IUPFRAME_HAS_TITLE", "1"); + else + { + char* value = iupAttribGetStr(ih, "SUNKEN"); + if (iupStrBoolean(value)) + iupmotSetArg(args, num_args, XmNshadowType, XmSHADOW_IN); + else + iupmotSetArg(args, num_args, XmNshadowType, XmSHADOW_ETCHED_IN); + } + + /* Core */ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Manager */ + iupmotSetArg(args, num_args, XmNshadowThickness, 2); + /* Frame */ + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* no shadow margins */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); /* no shadow margins */ + + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + xmFrameWidgetClass, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + if (title) + { + Widget title_label; + num_args = 0; + /* Label */ + iupmotSetArg(args, num_args, XmNlabelType, XmSTRING); + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + /* Frame Constraint */ + iupmotSetArg(args, num_args, XmNchildType, XmFRAME_TITLE_CHILD); + title_label = XtCreateManagedWidget("title_label", xmLabelWidgetClass, ih->handle, args, num_args); + iupmotSetString(title_label, XmNlabelString, title); + } + + child_manager = XtVaCreateManagedWidget( + "child_manager", + xmBulletinBoardWidgetClass, + ih->handle, + /* Core */ + XmNborderWidth, 0, + /* Manager */ + XmNshadowThickness, 0, + XmNnavigationType, XmTAB_GROUP, + /* BulletinBoard */ + XmNmarginWidth, 0, + XmNmarginHeight, 0, + XmNresizePolicy, XmRESIZE_NONE, /* no automatic resize of children */ + /* Frame Constraint */ + XmNchildType, XmFRAME_WORKAREA_CHILD, + NULL); + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + return IUP_NOERROR; +} + +void iupdrvFrameInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motFrameMapMethod; + ic->GetInnerNativeContainerHandle = motFrameGetInnerNativeContainerHandleMethod; + + /* Driver Dependent Attribute functions */ + + /* Overwrite Common */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, motFrameSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motFrameSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motFrameSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, motFrameSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "TITLE", NULL, motFrameSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +} diff --git a/iup/src/mot/iupmot_globalattrib.c b/iup/src/mot/iupmot_globalattrib.c new file mode 100755 index 0000000..9567cf5 --- /dev/null +++ b/iup/src/mot/iupmot_globalattrib.c @@ -0,0 +1,155 @@ +/** \file + * \brief Motif Driver implementation of iupdrvSetGlobal + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> + +#include <stdio.h> + +#include "iup.h" + +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvinfo.h" +#include "iup_strmessage.h" + +#include "iupmot_drv.h" + + +static void motGlobalSendKey(int key, int press) +{ + Window focus; + int revert_to; + XKeyEvent evt; + memset(&evt, 0, sizeof(XKeyEvent)); + evt.display = iupmot_display; + evt.send_event = True; + evt.root = DefaultRootWindow(iupmot_display); + + XGetInputFocus(iupmot_display, &focus, &revert_to); + evt.window = focus; + + iupmotKeyEncode(key, &evt.keycode, &evt.state); + if (!evt.keycode) + return; + + if (press & 0x01) + { + evt.type = KeyPress; + XSendEvent(iupmot_display, (Window)InputFocus, False, KeyPressMask, (XEvent*)&evt); + } + + if (press & 0x02) + { + evt.type = KeyRelease; + XSendEvent(iupmot_display, (Window)InputFocus, False, KeyReleaseMask, (XEvent*)&evt); + } +} + +int iupdrvSetGlobal(const char *name, const char *value) +{ + if (iupStrEqual(name, "LANGUAGE")) + { + iupStrMessageUpdateLanguage(value); + return 1; + } + if (iupStrEqual(name, "AUTOREPEAT")) + { + XKeyboardControl values; + if (iupStrBoolean(value)) + values.auto_repeat_mode = 1; + else + values.auto_repeat_mode = 0; + XChangeKeyboardControl(iupmot_display, KBAutoRepeatMode, &values); + return 0; + } + if (iupStrEqual(name, "CURSORPOS")) + { + int x, y; + if (iupStrToIntInt(value, &x, &y, 'x') == 2) + XWarpPointer(iupmot_display,None,RootWindow(iupmot_display, iupmot_screen),0,0,0,0,x,y); + return 0; + } + if (iupStrEqual(name, "KEYPRESS")) + { + int key; + if (iupStrToInt(value, &key)) + motGlobalSendKey(key, 0x01); + return 0; + } + if (iupStrEqual(name, "KEYRELEASE")) + { + int key; + if (iupStrToInt(value, &key)) + motGlobalSendKey(key, 0x02); + return 0; + } + if (iupStrEqual(name, "KEY")) + { + int key; + if (iupStrToInt(value, &key)) + motGlobalSendKey(key, 0x03); + return 0; + } + return 1; +} + +char* iupdrvGetGlobal(const char *name) +{ + if (iupStrEqual(name, "CURSORPOS")) + { + int x, y; + char* str = iupStrGetMemory(50); + iupdrvGetCursorPos(&x, &y); + sprintf(str, "%dx%d", x, y); + return str; + } + if (iupStrEqual(name, "SHIFTKEY")) + { + char key[5]; + iupdrvGetKeyState(key); + if (key[0] == 'S') + return "ON"; + return "OFF"; + } + if (iupStrEqual(name, "CONTROLKEY")) + { + char key[5]; + iupdrvGetKeyState(key); + if (key[1] == 'C') + return "ON"; + return "OFF"; + } + if (iupStrEqual(name, "MODKEYSTATE")) + { + char *str = iupStrGetMemory(5); + iupdrvGetKeyState(str); + return str; + } + if (iupStrEqual(name, "SCREENSIZE")) + { + char *str = iupStrGetMemory(50); + int w, h; + iupdrvGetScreenSize(&w, &h); + sprintf(str, "%dx%d", w, h); + return str; + } + if (iupStrEqual(name, "FULLSIZE")) + { + char *str = iupStrGetMemory(50); + int w, h; + iupdrvGetFullSize(&w, &h); + sprintf(str, "%dx%d", w, h); + return str; + } + if (iupStrEqual(name, "SCREENDEPTH")) + { + char *str = iupStrGetMemory(50); + int bpp = iupdrvGetScreenDepth(); + sprintf(str, "%d", bpp); + return str; + } + return NULL; +} diff --git a/iup/src/mot/iupmot_image.c b/iup/src/mot/iupmot_image.c new file mode 100755 index 0000000..b0078d5 --- /dev/null +++ b/iup/src/mot/iupmot_image.c @@ -0,0 +1,397 @@ +/** \file + * \brief Image Resource. + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> + +#include <stdio.h> +#include <limits.h> +#include <stdlib.h> +#include <memory.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_image.h" +#include "iup_drvinfo.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +void iupdrvImageGetRawData(void* handle, unsigned char* imgdata) +{ + Pixmap pixmap = (Pixmap)handle; + int w, h, y, x, bpp; + XImage *xi; + + if (!iupdrvImageGetInfo(handle, &w, &h, &bpp)) + return; + + if (bpp==8) + return; + + xi = XGetImage(iupmot_display, pixmap, 0, 0, w, h, ULONG_MAX, ZPixmap); + if (xi) + { + /* planes are separated in imgdata */ + int planesize = w*h; + unsigned char *r = imgdata, + *g = imgdata+planesize, + *b = imgdata+2*planesize; + for (y=0; y<h; y++) + { + int lineoffset = (h-1 - y)*w; /* imgdata is bottom up */ + for (x=0; x<w; x++) + { + iupmotColorGetRGB(XGetPixel(xi, x, y), r + lineoffset+x, g + lineoffset+x, b + lineoffset+x); + } + } + + XDestroyImage(xi); + } +} + +void* iupdrvImageCreateImageRaw(int width, int height, int bpp, iupColor* colors, int colors_count, unsigned char *imgdata) +{ + int y, x; + Pixmap pixmap; + GC gc; + + pixmap = XCreatePixmap(iupmot_display, + RootWindow(iupmot_display,iupmot_screen), + width, height, iupdrvGetScreenDepth()); + if (!pixmap) + return NULL; + + gc = XCreateGC(iupmot_display,pixmap,0,NULL); + + /* Pixmap is top-bottom */ + /* imgdata is bottom up */ + + if (bpp == 8) + { + Pixel color2pixel[256]; + int i; + for (i=0;i<colors_count;i++) + color2pixel[i] = iupmotColorGetPixel(colors[i].r, colors[i].g, colors[i].b); + + for (y=0;y<height;y++) + { + int lineoffset = (height-1 - y)*width; /* imgdata is bottom up */ + for(x=0;x<width;x++) + { + unsigned long p = color2pixel[imgdata[lineoffset+x]]; + XSetForeground(iupmot_display,gc,p); + XDrawPoint(iupmot_display,pixmap,gc,x,y); + } + } + } + else + { + /* planes are separated in imgdata */ + int planesize = width*height; + unsigned char *r = imgdata, + *g = imgdata+planesize, + *b = imgdata+2*planesize; + for (y=0;y<height;y++) + { + int lineoffset = (height-1 - y)*width; /* imgdata is bottom up */ + for(x=0;x<width;x++) + { + unsigned long p = iupmotColorGetPixel(r[lineoffset+x], g[lineoffset+x], b[lineoffset+x]); + XSetForeground(iupmot_display,gc,p); + XDrawPoint(iupmot_display,pixmap,gc,x,y); + } + } + } + + XFreeGC(iupmot_display,gc); + + return (void*)pixmap; +} + +void* iupdrvImageCreateImage(Ihandle *ih, const char* bgcolor, int make_inactive) +{ + int y, x, bpp, bgcolor_depend = 0, + width = ih->currentwidth, + height = ih->currentheight; + unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID"); + Pixmap pixmap; + unsigned char bg_r=0, bg_g=0, bg_b=0; + GC gc; + Pixel color2pixel[256]; + + bpp = iupAttribGetInt(ih, "BPP"); + + iupStrToRGB(bgcolor, &bg_r, &bg_g, &bg_b); + + if (bpp == 8) + { + int i, colors_count = 0; + iupColor colors[256]; + + iupImageInitColorTable(ih, colors, &colors_count); + + for (i=0;i<colors_count;i++) + { + if (colors[i].a == 0) + { + colors[i].r = bg_r; + colors[i].g = bg_g; + colors[i].b = bg_b; + colors[i].a = 255; + bgcolor_depend = 1; + } + + if (make_inactive) + iupImageColorMakeInactive(&(colors[i].r), &(colors[i].g), &(colors[i].b), + bg_r, bg_g, bg_b); + + color2pixel[i] = iupmotColorGetPixel(colors[i].r, colors[i].g, colors[i].b); + } + } + + pixmap = XCreatePixmap(iupmot_display, + RootWindow(iupmot_display,iupmot_screen), + width, height, iupdrvGetScreenDepth()); + if (!pixmap) + return NULL; + + gc = XCreateGC(iupmot_display,pixmap,0,NULL); + for (y=0;y<height;y++) + { + for(x=0;x<width;x++) + { + unsigned long p; + if (bpp == 8) + p = color2pixel[imgdata[y*width+x]]; + else + { + int channels = (bpp==24)? 3: 4; + unsigned char *pixel_data = imgdata + y*width*channels + x*channels; + unsigned char r = *(pixel_data), + g = *(pixel_data+1), + b = *(pixel_data+2); + + if (bpp == 32) + { + unsigned char a = *(pixel_data+3); + if (a != 255) + { + r = iupALPHABLEND(r, bg_r, a); + g = iupALPHABLEND(g, bg_g, a); + b = iupALPHABLEND(b, bg_b, a); + bgcolor_depend = 1; + } + } + + if (make_inactive) + iupImageColorMakeInactive(&r, &g, &b, bg_r, bg_g, bg_b); + + p = iupmotColorGetPixel(r, g, b); + } + + XSetForeground(iupmot_display,gc,p); + XDrawPoint(iupmot_display,pixmap,gc,x,y); + } + } + XFreeGC(iupmot_display,gc); + + if (bgcolor_depend || make_inactive) + iupAttribSetStr(ih, "_IUP_BGCOLOR_DEPEND", "1"); + + return (void*)pixmap; +} + +void* iupdrvImageCreateIcon(Ihandle *ih) +{ + return iupdrvImageCreateImage(ih, NULL, 0); +} + +void* iupdrvImageCreateCursor(Ihandle *ih) +{ + int bpp,y,x,hx,hy, + width = ih->currentwidth, + height = ih->currentheight, + line_size = (width+7)/8, + size_bytes = line_size*height; + unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID"); + char *sbits, *mbits, *sb, *mb; + Pixmap source, mask; + XColor fg, bg; + unsigned char r, g, b; + Cursor cursor; + + bpp = iupAttribGetInt(ih, "BPP"); + if (bpp > 8) + return NULL; + + sbits = (char*)malloc(2*size_bytes); + if (!sbits) return NULL; + memset(sbits, 0, 2*size_bytes); + mbits = sbits + size_bytes; + + sb = sbits; + mb = mbits; + for (y=0; y<height; y++) + { + for (x=0; x<width; x++) + { + int byte = x/8; + int bit = x%8; + int index = (int)imgdata[y*width+x]; + /* index==0 is transparent */ + if (index == 1) + sb[byte] = (char)(sb[byte] | (1<<bit)); + if (index != 0) + mb[byte] = (char)(mb[byte] | (1<<bit)); + } + + sb += line_size; + mb += line_size; + } + + r = 255; g = 255; b = 255; + iupStrToRGB(iupAttribGet(ih, "1"), &r, &g, &b ); + fg.red = iupCOLOR8TO16(r); + fg.green = iupCOLOR8TO16(g); + fg.blue = iupCOLOR8TO16(b); + fg.flags = DoRed | DoGreen | DoBlue; + + r = 0; g = 0; b = 0; + iupStrToRGB(iupAttribGet(ih, "2"), &r, &g, &b ); + bg.red = iupCOLOR8TO16(r); + bg.green = iupCOLOR8TO16(g); + bg.blue = iupCOLOR8TO16(b); + bg.flags = DoRed | DoGreen | DoBlue; + + hx=0; hy=0; + iupStrToIntInt(iupAttribGet(ih, "HOTSPOT"), &hx, &hy, ':'); + + source = XCreateBitmapFromData(iupmot_display, + RootWindow(iupmot_display,iupmot_screen), + sbits, width, height); + mask = XCreateBitmapFromData(iupmot_display, + RootWindow(iupmot_display,iupmot_screen), + mbits, width, height); + + cursor = XCreatePixmapCursor(iupmot_display, source, mask, &fg, &bg, hx, hy); + + free(sbits); + return (void*)cursor; +} + +void* iupdrvImageCreateMask(Ihandle *ih) +{ + int bpp,y,x, + width = ih->currentwidth, + height = ih->currentheight, + line_size = (width+7)/8, + size_bytes = line_size*height; + unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID"); + char *bits, *sb; + Pixmap mask; + unsigned char colors[256]; + + bpp = iupAttribGetInt(ih, "BPP"); + if (bpp > 8) + return NULL; + + bits = (char*)malloc(size_bytes); + if (!bits) return NULL; + memset(bits, 0, size_bytes); + + iupImageInitNonBgColors(ih, colors); + + sb = bits; + for (y=0; y<height; y++) + { + for (x=0; x<width; x++) + { + int byte = x/8; + int bit = x%8; + int index = (int)imgdata[y*width+x]; + if (colors[index]) + sb[byte] = (char)(sb[byte] | (1<<bit)); + } + + sb += line_size; + } + + mask = XCreateBitmapFromData(iupmot_display, + RootWindow(iupmot_display,iupmot_screen), + bits, width, height); + + free(bits); + return (void*)mask; +} + +void* iupdrvImageLoad(const char* name, int type) +{ + if (type == IUPIMAGE_CURSOR) + { + Cursor cursor = 0; + int id; + if (iupStrToInt(name, &id)) + cursor = XCreateFontCursor(iupmot_display, id); + return (void*)cursor; + } + else /* IUPIMAGE_IMAGE or IUPIMAGE_ICON */ + { + Screen* screen = ScreenOfDisplay(iupmot_display, iupmot_screen); + Pixmap pixmap = XmGetPixmap(screen, (char*)name, BlackPixelOfScreen(screen), WhitePixelOfScreen(screen)); + if (pixmap == XmUNSPECIFIED_PIXMAP) + { + unsigned int width, height; + int hotx, hoty; + pixmap = 0; + XReadBitmapFile(iupmot_display, RootWindow(iupmot_display,iupmot_screen), name, &width, &height, &pixmap, &hotx, &hoty); + } + return (void*)pixmap; + } +} + +int iupdrvImageGetInfo(void* handle, int *w, int *h, int *bpp) +{ + Pixmap pixmap = (Pixmap)handle; + Window root; + int x, y; + unsigned int width, height, b, depth; + if (!XGetGeometry(iupmot_display, pixmap, &root, &x, &y, &width, &height, &b, &depth)) + { + if (w) *w = 0; + if (h) *h = 0; + if (bpp) *bpp = 0; + return 0; + } + if (w) *w = width; + if (h) *h = height; + if (bpp) *bpp = iupImageNormBpp(depth); + return 1; +} + +int iupdrvImageGetRawInfo(void* handle, int *w, int *h, int *bpp, iupColor* colors, int *colors_count) +{ + /* How to get the pallete? */ + (void)colors; + (void)colors_count; + return iupdrvImageGetInfo(handle, w, h, bpp); +} + +void iupdrvImageDestroy(void* handle, int type) +{ + if (type == IUPIMAGE_CURSOR) + XFreeCursor(iupmot_display, (Cursor)handle); + else + { + Screen* screen = ScreenOfDisplay(iupmot_display, iupmot_screen); + if (!XmDestroyPixmap(screen, (Pixmap)handle)) + XFreePixmap(iupmot_display, (Pixmap)handle); + } +} + diff --git a/iup/src/mot/iupmot_key.c b/iup/src/mot/iupmot_key.c new file mode 100755 index 0000000..835b5d7 --- /dev/null +++ b/iup/src/mot/iupmot_key.c @@ -0,0 +1,425 @@ +/** \file + * \brief Motif Driver keyboard mapping + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <X11/keysym.h> + +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> + +#include "iup.h" +#include "iupcbs.h" +#include "iupkey.h" + +#include "iup_object.h" +#include "iup_key.h" +#include "iup_str.h" + +#include "iupmot_drv.h" + +typedef struct Imot2iupkey +{ + KeySym motcode; + int iupcode; + int s_iupcode; + int c_iupcode; + int m_iupcode; + int y_iupcode; +} Imot2iupkey; + +static Imot2iupkey motkey_map[] = { + +{ XK_Escape, K_ESC, K_sESC, K_cESC, K_mESC ,K_yESC }, +{ XK_Pause, K_PAUSE, K_sPAUSE, K_cPAUSE, K_mPAUSE ,K_yPAUSE }, +{ XK_Print, K_Print, K_sPrint, K_cPrint, K_mPrint ,K_yPrint }, +{ XK_Menu, K_Menu, K_sMenu, K_cMenu, K_mMenu ,K_yMenu }, + +{ XK_Home, K_HOME, K_sHOME, K_cHOME, K_mHOME ,K_yHOME }, +{ XK_Up, K_UP, K_sUP, K_cUP, K_mUP ,K_yUP }, +{ XK_Prior, K_PGUP, K_sPGUP, K_cPGUP, K_mPGUP ,K_yPGUP }, +{ XK_Left, K_LEFT, K_sLEFT, K_cLEFT, K_mLEFT ,K_yLEFT }, +{ XK_Begin, K_MIDDLE,K_sMIDDLE, K_cMIDDLE,K_mMIDDLE,K_yMIDDLE}, +{ XK_Right, K_RIGHT, K_sRIGHT, K_cRIGHT, K_mRIGHT ,K_yRIGHT }, +{ XK_End, K_END, K_sEND, K_cEND, K_mEND ,K_yEND }, +{ XK_Down, K_DOWN, K_sDOWN, K_cDOWN, K_mDOWN ,K_yDOWN }, +{ XK_Next, K_PGDN, K_sPGDN, K_cPGDN, K_mPGDN ,K_yPGDN }, +{ XK_Insert, K_INS, K_sINS, K_cINS, K_mINS ,K_yINS }, +{ XK_Delete, K_DEL, K_sDEL, K_cDEL, K_mDEL ,K_yDEL }, +{ XK_space, K_SP, K_sSP, K_cSP, K_mSP ,K_ySP }, +{ XK_Tab, K_TAB, K_sTAB, K_cTAB, K_mTAB ,K_yTAB }, +{ XK_Return, K_CR, K_sCR, K_cCR, K_mCR ,K_yCR }, +{ XK_BackSpace, K_BS, K_sBS, K_cBS, K_mBS ,K_yBS }, + +{ XK_1, K_1, K_exclam, K_c1, K_m1, K_y1 }, +{ XK_2, K_2, K_at, K_c2, K_m2, K_y2 }, +{ XK_3, K_3, K_numbersign, K_c3, K_m3, K_y3 }, +{ XK_4, K_4, K_dollar, K_c4, K_m4, K_y4 }, +{ XK_5, K_5, K_percent, K_c5, K_m5, K_y5 }, +{ XK_6, K_6, K_circum, K_c6, K_m6, K_y6 }, +{ XK_7, K_7, K_ampersand, K_c7, K_m7, K_y7 }, +{ XK_8, K_8, K_asterisk, K_c8, K_m8, K_y8 }, +{ XK_9, K_9, K_parentleft, K_c9, K_m9, K_y9 }, +{ XK_0, K_0, K_parentright, K_c0, K_m0, K_y0 }, + +{ XK_a, K_a, K_A, K_cA, K_mA, K_yA }, +{ XK_b, K_b, K_B, K_cB, K_mB, K_yB }, +{ XK_c, K_c, K_C, K_cC, K_mC, K_yC }, +{ XK_d, K_d, K_D, K_cD, K_mD, K_yD }, +{ XK_e, K_e, K_E, K_cE, K_mE, K_yE }, +{ XK_f, K_f, K_F, K_cF, K_mF, K_yF }, +{ XK_g, K_g, K_G, K_cG, K_mG, K_yG }, +{ XK_h, K_h, K_H, K_cH, K_mH, K_yH }, +{ XK_i, K_i, K_I, K_cI, K_mI, K_yI }, +{ XK_j, K_j, K_J, K_cJ, K_mJ, K_yJ }, +{ XK_k, K_k, K_K, K_cK, K_mK, K_yK }, +{ XK_l, K_l, K_L, K_cL, K_mL, K_yL }, +{ XK_m, K_m, K_M, K_cM, K_mM, K_yM }, +{ XK_n, K_n, K_N, K_cN, K_mN, K_yN }, +{ XK_o, K_o, K_O, K_cO, K_mO, K_yO }, +{ XK_p, K_p, K_P, K_cP, K_mP, K_yP }, +{ XK_q, K_q, K_Q, K_cQ, K_mQ, K_yQ }, +{ XK_r, K_r, K_R, K_cR, K_mR, K_yR }, +{ XK_s, K_s, K_S, K_cS, K_mS, K_yS }, +{ XK_t, K_t, K_T, K_cT, K_mT, K_yT }, +{ XK_u, K_u, K_U, K_cU, K_mU, K_yU }, +{ XK_v, K_v, K_V, K_cV, K_mV, K_yV }, +{ XK_w, K_w, K_W, K_cW, K_mW, K_yW }, +{ XK_x, K_x, K_X, K_cX, K_mX, K_yX }, +{ XK_y, K_y, K_Y, K_cY, K_mY, K_yY }, +{ XK_z, K_z, K_Z, K_cZ, K_mZ, K_yZ }, + +{ XK_F1, K_F1, K_sF1, K_cF1, K_mF1, K_yF1 }, +{ XK_F2, K_F2, K_sF2, K_cF2, K_mF2, K_yF2 }, +{ XK_F3, K_F3, K_sF3, K_cF3, K_mF3, K_yF3 }, +{ XK_F4, K_F4, K_sF4, K_cF4, K_mF4, K_yF4 }, +{ XK_F5, K_F5, K_sF5, K_cF5, K_mF5, K_yF5 }, +{ XK_F6, K_F6, K_sF6, K_cF6, K_mF6, K_yF6 }, +{ XK_F7, K_F7, K_sF7, K_cF7, K_mF7, K_yF7 }, +{ XK_F8, K_F8, K_sF8, K_cF8, K_mF8, K_yF8 }, +{ XK_F9, K_F9, K_sF9, K_cF9, K_mF9, K_yF9 }, +{ XK_F10, K_F10, K_sF10, K_cF10, K_mF10, K_yF10 }, +{ XK_F11, K_F11, K_sF11, K_cF11, K_mF11, K_yF11 }, +{ XK_F12, K_F12, K_sF12, K_cF12, K_mF12, K_yF12 }, + +{ XK_semicolon, K_semicolon, K_colon, K_cSemicolon, K_mSemicolon, K_ySemicolon }, +{ XK_equal, K_equal, K_plus, K_cEqual, K_mEqual, K_yEqual }, +{ XK_comma, K_comma, K_less, K_cComma, K_mComma, K_yComma }, +{ XK_minus, K_minus, K_underscore, K_cMinus, K_mMinus, K_yMinus }, +{ XK_period, K_period, K_greater, K_cPeriod, K_mPeriod, K_yPeriod }, +{ XK_slash, K_slash, K_question, K_cSlash, K_mSlash, K_ySlash }, +{ XK_grave, K_grave, K_tilde, 0, 0, 0 }, +{ XK_bracketleft, K_bracketleft, K_braceleft, K_cBracketleft, K_mBracketleft, K_yBracketleft }, +{ XK_backslash, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash }, +{ XK_bracketright,K_bracketright, K_braceright, K_cBracketright,K_mBracketright,K_yBracketright }, +{ XK_apostrophe, K_apostrophe, K_quotedbl, 0, 0, 0 }, + +{ XK_KP_0, K_0, K_0, K_c0, K_m0, K_y0 }, +{ XK_KP_1, K_1, K_1, K_c1, K_m1, K_y1 }, +{ XK_KP_2, K_2, K_2, K_c2, K_m2, K_y2 }, +{ XK_KP_3, K_3, K_3, K_c3, K_m3, K_y3 }, +{ XK_KP_4, K_4, K_4, K_c4, K_m4, K_y4 }, +{ XK_KP_5, K_5, K_5, K_c5, K_m5, K_y5 }, +{ XK_KP_6, K_6, K_6, K_c6, K_m6, K_y6 }, +{ XK_KP_7, K_7, K_7, K_c7, K_m7, K_y7 }, +{ XK_KP_8, K_8, K_8, K_c8, K_m8, K_y8 }, +{ XK_KP_9, K_9, K_9, K_c9, K_m9, K_y9 }, +{ XK_KP_Multiply, K_asterisk, K_sAsterisk, K_cAsterisk, K_mAsterisk, K_yAsterisk }, +{ XK_KP_Add, K_plus, K_sPlus, K_cPlus, K_mPlus, K_yPlus }, +{ XK_KP_Subtract, K_minus, K_sMinus, K_cMinus, K_mMinus, K_yMinus }, +{ XK_KP_Decimal, K_period, K_sPeriod, K_cPeriod, K_mPeriod, K_yPeriod }, +{ XK_KP_Divide, K_slash, K_sSlash, K_cSlash, K_mSlash, K_ySlash }, +{ XK_KP_Separator, K_comma, K_sComma, K_cComma, K_mComma, K_yComma }, + +{ XK_ccedilla, K_ccedilla, K_Ccedilla, K_cCcedilla, K_mCcedilla, K_yCcedilla }, + +{ XK_dead_tilde, K_tilde, K_circum, 0, 0, 0 }, +{ XK_dead_acute, K_acute, K_grave, 0, 0, 0 }, +{ XK_dead_grave, K_grave, K_tilde, 0, 0, 0 }, + +{ XK_KP_F1, K_F1, K_sF1, K_cF1, K_mF1, K_yF1 }, +{ XK_KP_F2, K_F2, K_sF2, K_cF2, K_mF2, K_yF2 }, +{ XK_KP_F3, K_F3, K_sF3, K_cF3, K_mF3, K_yF3 }, +{ XK_KP_F4, K_F4, K_sF4, K_cF4, K_mF4, K_yF4 }, +{ XK_KP_Space, K_SP, K_sSP, K_cSP, K_mSP ,K_ySP }, +{ XK_KP_Tab, K_TAB, K_sTAB, K_cTAB, K_mTAB ,K_yTAB }, +{ XK_KP_Equal, K_equal, 0, K_cEqual, K_mEqual, K_yEqual }, + +{ XK_KP_Enter, K_CR, K_sCR, K_cCR, K_mCR, K_yCR }, +{ XK_KP_Home, K_HOME, K_sHOME, K_cHOME, K_mHOME, K_yHOME }, +{ XK_KP_Up, K_UP, K_sUP, K_cUP, K_mUP, K_yUP }, +{ XK_KP_Page_Up, K_PGUP, K_sPGUP, K_cPGUP, K_mPGUP, K_yPGUP }, +{ XK_KP_Left, K_LEFT, K_sLEFT, K_cLEFT, K_mLEFT, K_yLEFT }, +{ XK_KP_Begin, K_MIDDLE,K_sMIDDLE, K_cMIDDLE,K_mMIDDLE,K_yMIDDLE}, +{ XK_KP_Right, K_RIGHT, K_sRIGHT, K_cRIGHT, K_mRIGHT, K_yRIGHT }, +{ XK_KP_End, K_END, K_sEND, K_cEND, K_mEND, K_yEND }, +{ XK_KP_Down, K_DOWN, K_sDOWN, K_cDOWN, K_mDOWN, K_yDOWN }, +{ XK_KP_Page_Down, K_PGDN, K_sPGDN, K_cPGDN, K_mPGDN, K_yPGDN }, +{ XK_KP_Insert, K_INS, K_sINS, K_cINS, K_mINS, K_yINS }, +{ XK_KP_Delete, K_DEL, K_sDEL, K_cDEL, K_mDEL, K_yDEL } + +}; + +void iupmotKeyEncode(int key, unsigned int *keyval, unsigned int *state) +{ + int i, iupcode = key & 0xFF; /* 0-255 interval */ + int count = sizeof(motkey_map)/sizeof(motkey_map[0]); + for (i = 0; i < count; i++) + { + Imot2iupkey* key_map = &(motkey_map[i]); + if (key_map->iupcode == iupcode) + { + *keyval = XKeysymToKeycode(iupmot_display, key_map->motcode); + *state = 0; + + if (iupcode != key) + { + if (key_map->c_iupcode == key) + *state = ControlMask; + else if (key_map->m_iupcode == key) + *state = Mod1Mask; + else if (key_map->y_iupcode == key) + *state = Mod4Mask; + else if (key_map->s_iupcode == key) + *state = ShiftMask; + } + return; + } + else if (key_map->s_iupcode == key) /* There are Shift keys bellow 256 */ + { + *keyval = XKeysymToKeycode(iupmot_display, key_map->motcode); + *state = ShiftMask; + return; + } + } +} + +static int motKeyMap2Iup(unsigned int state, int i) +{ + int code = 0; + if (state & ControlMask) /* Ctrl */ + code = motkey_map[i].c_iupcode; + else if (state & Mod1Mask || + state & Mod5Mask) /* Alt */ + code = motkey_map[i].m_iupcode; + else if (state & Mod4Mask) /* Apple/Win */ + code = motkey_map[i].y_iupcode; + else if (state & LockMask) /* CapsLock */ + { + if ((state & ShiftMask) || !iupKeyCanCaps(motkey_map[i].iupcode)) + return motkey_map[i].iupcode; + else + code = motkey_map[i].s_iupcode; + } + else if (state & ShiftMask) /* Shift */ + code = motkey_map[i].s_iupcode; + else + return motkey_map[i].iupcode; + + if (!code) + code = motkey_map[i].iupcode; + + return code; +} + +static int motKeyDecode(XKeyEvent *evt) +{ + int i; + KeySym motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + int count = sizeof(motkey_map)/sizeof(motkey_map[0]); + + if ((evt->state & Mod2Mask) && /* NumLock */ + (motcode >= XK_KP_Home) && + (motcode <= XK_KP_Delete)) + { + /* remap to numeric keys */ + KeySym remap_numkey[] = {XK_KP_7, XK_KP_4, XK_KP_8, XK_KP_6, XK_KP_2, XK_KP_9, XK_KP_3, XK_KP_1, XK_KP_5, XK_KP_0, XK_KP_Decimal}; + motcode = remap_numkey[motcode-XK_KP_Home]; + } + + for (i = 0; i < count; i++) + { + if (motkey_map[i].motcode == motcode) + return motKeyMap2Iup(evt->state, i); + } + + return 0; +} + +KeySym iupmotKeyCharToKeySym(char c) +{ + int i; + int count = sizeof(motkey_map)/sizeof(motkey_map[0]); + + for (i = 0; i < count; i++) + { + if (motkey_map[i].iupcode == c) + return motkey_map[i].motcode; + if (motkey_map[i].s_iupcode == c) + { + if (motkey_map[i].motcode >= XK_a && + motkey_map[i].motcode <= XK_z) + return motkey_map[i].motcode - (XK_a-XK_A); + } + } + + return 0; +} + +/* Discards keyrepeat by removing the keypress event from the queue. + * The pair keyrelease/keypress is always put together in the queue, + * by removing the keypress, we only worry about keyrelease. In case + * of a keyrelease, we ignore it if the next event is a keypress (which + * means repetition. Otherwise it is a real keyrelease. + * + * Returns 1 if the keypress is found in the queue and 0 otherwise. + */ +static int motKeyDiscardKeypressRepeat(XEvent *evt) +{ + XEvent ahead; + if (XEventsQueued(iupmot_display, QueuedAfterReading)) + { + XPeekEvent(iupmot_display, &ahead); + if (ahead.type == KeyPress && ahead.xkey.window == evt->xkey.window + && ahead.xkey.keycode == evt->xkey.keycode && ahead.xkey.time == evt->xkey.time) + { + /* Pop off the repeated KeyPress and ignore */ + XNextEvent(iupmot_display, evt); + /* Ignore the auto repeated KeyRelease/KeyPress pair */ + return 1; + } + } + /* No KeyPress found */ + return 0; +} + +/* this is called only for canvas */ +void iupmotCanvasKeyReleaseEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + if (motKeyDiscardKeypressRepeat(evt)) + { + /* call key_press because it was removed from the queue */ + iupmotKeyPressEvent(w, ih, evt, cont); + } + else + { + int result; + int code = motKeyDecode((XKeyEvent*)evt); + if (code == 0) + return; + result = iupKeyCallKeyPressCb(ih, code, 0); + if (result == IUP_CLOSE) + { + IupExitLoop(); + return; + } + if (result == IUP_IGNORE) + { + *cont = False; + return; + } + } +} + +void iupmotKeyPressEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + int result; + int code = motKeyDecode((XKeyEvent*)evt); + if (code == 0) + return; + + if ((((XKeyEvent*)evt)->state & Mod1Mask || ((XKeyEvent*)evt)->state & Mod5Mask)) /* Alt */ + { + KeySym motcode = XKeycodeToKeysym(iupmot_display, ((XKeyEvent*)evt)->keycode, 0); + if (motcode < 128) + { + IFni cb; + Ihandle* dialog = IupGetDialog(ih); + char attrib[22] = "_IUPMOT_MNEMONIC_ _CB"; + attrib[17] = (char)toupper(motcode); + cb = (IFni)IupGetCallback(dialog, attrib); + if (cb) + { + cb(dialog, attrib[17]); + return; + } + } + } + + result = iupKeyCallKeyCb(ih, code); + if (result == IUP_CLOSE) + { + IupExitLoop(); + return; + } + if (result == IUP_IGNORE) + { + *cont = False; + return; + } + + /* in the previous callback the dialog could be destroyed */ + if (iupObjectCheck(ih)) + { + /* this is called only for canvas */ + if (ih->iclass->nativetype==IUP_TYPECANVAS) + { + result = iupKeyCallKeyPressCb(ih, code, 1); + if (result == IUP_CLOSE) + { + IupExitLoop(); + return; + } + if (result == IUP_IGNORE) + { + *cont = False; + return; + } + } + + if (!iupKeyProcessNavigation(ih, code, ((XKeyEvent*)evt)->state & ShiftMask)) + { + *cont = False; + return; + } + } + + (void)w; +} + +void iupmotButtonKeySetStatus(unsigned int state, unsigned int but, char* status, int doubleclick) +{ + if (state & ShiftMask) + iupKEYSETSHIFT(status); + + if (state & ControlMask) + iupKEYSETCONTROL(status); + + if ((state & Button1Mask) || but==Button1) + iupKEYSETBUTTON1(status); + + if ((state & Button2Mask) || but==Button2) + iupKEYSETBUTTON2(status); + + if ((state & Button3Mask) || but==Button3) + iupKEYSETBUTTON3(status); + + if ((state & Button4Mask) || but==Button4) + iupKEYSETBUTTON4(status); + + if ((state & Button5Mask) || but==Button5) + iupKEYSETBUTTON5(status); + + if (state & Mod1Mask || state & Mod5Mask) /* Alt */ + iupKEYSETALT(status); + + if (state & Mod4Mask) /* Apple/Win */ + iupKEYSETSYS(status); + + if (doubleclick) + iupKEYSETDOUBLE(status); +} + diff --git a/iup/src/mot/iupmot_label.c b/iup/src/mot/iupmot_label.c new file mode 100755 index 0000000..52dfc9a --- /dev/null +++ b/iup/src/mot/iupmot_label.c @@ -0,0 +1,256 @@ +/** \file + * \brief Label Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/Label.h> +#include <Xm/Separator.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_label.h" +#include "iup_drv.h" +#include "iup_image.h" + +#include "iupmot_drv.h" + + +static int motLabelSetTitleAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_LABEL_TEXT) + { + iupmotSetMnemonicTitle(ih, value); + return 1; + } + + return 0; +} + +static int motLabelSetBgColorAttrib(Ihandle* ih, const char* value) +{ + /* ignore given value, must use only from parent */ + value = iupBaseNativeParentGetBgColor(ih); + + if (iupdrvBaseSetBgColorAttrib(ih, value)) + return 1; + return 0; +} + +static int motLabelSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + /* ignore given value, must use only from parent */ + value = iupAttribGetInheritNativeParent(ih, "BACKGROUND"); + + if (iupdrvBaseSetBgColorAttrib(ih, value)) + return 1; + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + if (pixmap) + { + XtVaSetValues(ih->handle, XmNbackgroundPixmap, pixmap, NULL); + return 1; + } + } + return 0; +} + +static int motLabelSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT) + { + unsigned char align; + char value1[30]="", value2[30]=""; + + iupStrToStrStr(value, value1, value2, ':'); /* value2 is ignored, NOT supported in Motif */ + + if (iupStrEqualNoCase(value1, "ARIGHT")) + align = XmALIGNMENT_END; + else if (iupStrEqualNoCase(value1, "ACENTER")) + align = XmALIGNMENT_CENTER; + else /* "ALEFT" */ + align = XmALIGNMENT_BEGINNING; + + XtVaSetValues(ih->handle, XmNalignment, align, NULL); + return 1; + } + else + return 0; +} + +static int motLabelSetImageAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_LABEL_IMAGE) + { + iupmotSetPixmap(ih, value, XmNlabelPixmap, 0); + + if (!iupdrvIsActive(ih)) + { + if (!iupAttribGet(ih, "IMINACTIVE")) + { + /* if not active and IMINACTIVE is not defined + then automaticaly create one based on IMAGE */ + iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 1); /* make_inactive */ + } + } + return 1; + } + else + return 0; +} + +static int motLabelSetImInactiveAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_LABEL_IMAGE) + { + iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 0); + return 1; + } + else + return 0; +} + +static int motLabelSetActiveAttrib(Ihandle* ih, const char* value) +{ + /* update the inactive image if necessary */ + if (ih->data->type == IUP_LABEL_IMAGE && !iupStrBoolean(value)) + { + if (!iupAttribGet(ih, "IMINACTIVE")) + { + /* if not defined then automaticaly create one based on IMAGE */ + char* name = iupAttribGet(ih, "IMAGE"); + iupmotSetPixmap(ih, name, XmNlabelInsensitivePixmap, 1); /* make_inactive */ + } + } + + return iupBaseSetActiveAttrib(ih, value); +} + +static int motLabelSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle && ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT) + { + XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); + } + return 0; +} + +static int motLabelMapMethod(Ihandle* ih) +{ + char* value; + int num_args = 0; + Arg args[20]; + WidgetClass widget_class; + + value = iupAttribGet(ih, "SEPARATOR"); + if (value) + { + widget_class = xmSeparatorWidgetClass; + if (iupStrEqualNoCase(value, "HORIZONTAL")) + { + ih->data->type = IUP_LABEL_SEP_HORIZ; + iupmotSetArg(args, num_args, XmNorientation, XmHORIZONTAL); + } + else /* "VERTICAL" */ + { + ih->data->type = IUP_LABEL_SEP_VERT; + iupmotSetArg(args, num_args, XmNorientation, XmVERTICAL); + } + } + else + { + value = iupAttribGet(ih, "IMAGE"); + widget_class = xmLabelWidgetClass; + if (value) + { + ih->data->type = IUP_LABEL_IMAGE; + iupmotSetArg(args, num_args, XmNlabelType, XmPIXMAP); + } + else + { + ih->data->type = IUP_LABEL_TEXT; + iupmotSetArg(args, num_args, XmNlabelType, XmSTRING); + } + } + + /* Core */ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Primitive */ + iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupmotSetArg(args, num_args, XmNhighlightThickness, 0); + /* Label */ + iupmotSetArg(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNmarginTop, 0); /* no extra margins */ + iupmotSetArg(args, num_args, XmNmarginLeft, 0); + iupmotSetArg(args, num_args, XmNmarginBottom, 0); + iupmotSetArg(args, num_args, XmNmarginRight, 0); + + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + widget_class, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + /* Drag Source is enabled by default in label */ + iupmotDisableDragSource(ih->handle); + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + if (ih->data->type == IUP_LABEL_TEXT) + iupmotSetString(ih->handle, XmNlabelString, ""); + + return IUP_NOERROR; +} + +void iupdrvLabelInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motLabelMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, motLabelSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", iupmotGetBgColorAttrib, motLabelSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motLabelSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "TITLE", NULL, motLabelSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupLabel only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, motLabelSetAlignmentAttrib, "ALEFT:ACENTER", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "IMAGE", NULL, motLabelSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PADDING", iupLabelGetPaddingAttrib, motLabelSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + + /* IupLabel GTK and Motif only */ + iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, motLabelSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +} diff --git a/iup/src/mot/iupmot_list.c b/iup/src/mot/iupmot_list.c new file mode 100755 index 0000000..f8e73ed --- /dev/null +++ b/iup/src/mot/iupmot_list.c @@ -0,0 +1,1404 @@ +/** \file + * \brief List Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/List.h> +#include <Xm/ComboBox.h> +#include <Xm/ScrolledW.h> +#include <Xm/TextF.h> +#include <X11/keysym.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <time.h> +#include <limits.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_mask.h" +#include "iup_key.h" +#include "iup_list.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +static void motListComboBoxSelectionCallback(Widget w, Ihandle* ih, XmComboBoxCallbackStruct* call_data); + + +void iupdrvListAddItemSpace(Ihandle* ih, int *h) +{ + if (ih->data->has_editbox) + *h += 1; + else + *h += 3; +} + +void iupdrvListAddBorders(Ihandle* ih, int *x, int *y) +{ + int border_size = 2*4; + (*x) += border_size; + (*y) += border_size; + + if (ih->data->is_dropdown) + { + if (ih->data->has_editbox) + { + /* extra border for the editbox */ + int internal_border_size = 2*2; + (*x) += internal_border_size; + (*y) += internal_border_size; + } + } + else + { + if (ih->data->has_editbox) + (*y) += 2*2; /* internal border between editbox and list */ + else + (*x) += 2; /* extra border for the simple list */ + } +} + +static int motListConvertXYToPos(Ihandle* ih, int x, int y) +{ + (void)x; + if (ih->data->has_editbox) + { + Widget cblist; + XtVaGetValues(ih->handle, XmNlist, &cblist, NULL); + return XmListYToPos(cblist, (Position)y); /* XmListYToPos returns start at 1 */ + } + else + return XmListYToPos(ih->handle, (Position)y); +} + +int iupdrvListGetCount(Ihandle* ih) +{ + int count; + XtVaGetValues(ih->handle, XmNitemCount, &count, NULL); + return count; +} + +static void motListAddItem(Ihandle* ih, int pos, const char* value) +{ + XmString str = XmStringCreateLocalized((String)value); + /* The utility functions use 0=last 1=first */ + if (ih->data->is_dropdown || ih->data->has_editbox) + XmComboBoxAddItem(ih->handle, str, pos+1, False); + else + XmListAddItem(ih->handle, str, pos+1); + XmStringFree(str); +} + +static void motListAddSortedItem(Ihandle* ih, const char *value) +{ + char *text; + XmString *strlist; + int u_bound, l_bound = 0; + + XtVaGetValues(ih->handle, XmNitemCount, &u_bound, XmNitems, &strlist, NULL); + + u_bound--; + /* perform binary search */ + while (u_bound >= l_bound) + { + int i = l_bound + (u_bound - l_bound)/2; + text = (char*)XmStringUnparse(strlist[i], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); + if (!text) + break; + if (strcmp (text, value) > 0) + u_bound = i-1; /* newtext comes before item */ + else + l_bound = i+1; /* newtext comes after item */ + XtFree(text); + } + + motListAddItem(ih, l_bound, value); +} + +void iupdrvListAppendItem(Ihandle* ih, const char* value) +{ + if (iupAttribGetBoolean(ih, "SORT")) + motListAddSortedItem(ih, value); + else + motListAddItem(ih, -1, value); +} + +void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value) +{ + if (iupAttribGetBoolean(ih, "SORT")) + motListAddSortedItem(ih, value); + else + motListAddItem(ih, pos, value); +} + +void iupdrvListRemoveItem(Ihandle* ih, int pos) +{ + /* The utility functions use 0=last 1=first */ + if (ih->data->is_dropdown || ih->data->has_editbox) + XmComboBoxDeletePos(ih->handle, pos+1); + else + XmListDeletePos(ih->handle, pos+1); +} + +void iupdrvListRemoveAllItems(Ihandle* ih) +{ + if (ih->data->is_dropdown || ih->data->has_editbox) + { + Widget cblist; + XtVaGetValues(ih->handle, XmNlist, &cblist, NULL); + XmListDeleteAllItems(cblist); + XmComboBoxUpdate(ih->handle); + } + else + XmListDeleteAllItems(ih->handle); +} + + +/*********************************************************************************/ + + +static char* motListGetIdValueAttrib(Ihandle* ih, const char* name_id) +{ + int pos = iupListGetPos(ih, name_id); + if (pos != -1) + { + XmString* items; + XtVaGetValues(ih->handle, XmNitems, &items, NULL); + return iupmotConvertString(items[pos]); + } + return NULL; +} + +static int motListSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (sb_win) + { + Pixel color; + + /* ignore given value for the scrollbars, must use only from parent */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + color = iupmotColorGetPixelStr(parent_value); + if (color != (Pixel)-1) + { + Widget sb = NULL; + + iupmotSetBgColor(sb_win, color); + + XtVaGetValues(sb_win, XmNverticalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + + XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + } + + return iupdrvBaseSetBgColorAttrib(ih, value); /* use given value for contents */ + } + else + { + char* parent_value; + + /* use given value for Edit and List also */ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + Widget cbedit, cblist, sb; + + iupmotSetBgColor(ih->handle, color); + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + if (cbedit) iupmotSetBgColor(cbedit, color); + + XtVaGetValues(ih->handle, XmNlist, &cblist, NULL); + if (cblist) iupmotSetBgColor(cblist, color); + + XtVaGetValues(cblist, XmNverticalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + + XtVaGetValues(cblist, XmNhorizontalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + } + + /* but reset just the background, so the combobox will look like a button */ + parent_value = iupBaseNativeParentGetBgColor(ih); + + color = iupmotColorGetPixelStr(parent_value); + if (color != (Pixel)-1) + XtVaSetValues(ih->handle, XmNbackground, color, NULL); + + return 1; + } +} + +static int motListSetFgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + XtVaSetValues(ih->handle, XmNforeground, color, NULL); + + if (ih->data->is_dropdown || ih->data->has_editbox) + { + Widget w; + XtVaGetValues(ih->handle, XmNtextField, &w, NULL); + XtVaSetValues(w, XmNforeground, color, NULL); + + XtVaGetValues(ih->handle, XmNlist, &w, NULL); + XtVaSetValues(w, XmNforeground, color, NULL); + } + } + + return 1; +} + +static char* motListGetValueAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + char *str, *xstr; + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + xstr = XmTextFieldGetString(cbedit); + str = iupStrGetMemoryCopy(xstr); + XtFree(xstr); + return str; + } + else + { + if (ih->data->is_dropdown) + { + char* str; + int pos; + XtVaGetValues(ih->handle, XmNselectedPosition, &pos, NULL); + str = iupStrGetMemory(50); + sprintf(str, "%d", pos+1); /* IUP starts at 1 */ + return str; + } + else + { + int *pos, sel_count; + if (XmListGetSelectedPos(ih->handle, &pos, &sel_count)) /* XmListGetSelectedPos starts at 1 */ + { + if (!ih->data->is_multiple) + { + char* str = iupStrGetMemory(50); + sprintf(str, "%d", pos[0]); + XtFree((char*)pos); + return str; + } + else + { + int i, count; + char* str; + XtVaGetValues(ih->handle, XmNitemCount, &count, NULL); + str = iupStrGetMemory(count+1); + memset(str, '-', count); + str[count]=0; + for (i=0; i<sel_count; i++) + str[pos[i]-1] = '+'; + XtFree((char*)pos); + return str; + } + } + } + } + + return NULL; +} + +static int motListSetValueAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->has_editbox) + { + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + if (!value) value = ""; + + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); /* disable callbacks */ + + XmTextFieldSetString(cbedit, (char*)value); + + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + else + { + if (ih->data->is_dropdown) + { + int pos; + if (iupStrToInt(value, &pos)==1) + { + XtRemoveCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motListComboBoxSelectionCallback, (XtPointer)ih); + + XtVaSetValues(ih->handle, XmNselectedPosition, pos-1, NULL); /* IUP starts at 1 */ + iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos); + + XtAddCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motListComboBoxSelectionCallback, (XtPointer)ih); + } + } + else + { + if (!ih->data->is_multiple) + { + int pos; + if (iupStrToInt(value, &pos)==1) + { + XmListSelectPos(ih->handle, pos, FALSE); /* XmListSelectPos starts at 1 */ + iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos); + } + else + { + XmListDeselectAllItems(ih->handle); + iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); + } + } + else + { + /* User has changed a multiple selection on a simple list. */ + int i, count, len; + + /* Clear all selections */ + XmListDeselectAllItems(ih->handle); + + if (!value) + { + iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); + return 0; + } + + XtVaGetValues(ih->handle, XmNitemCount, &count, NULL); + len = strlen(value); + if (len < count) + count = len; + + XtVaSetValues(ih->handle, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL); + + /* update selection list */ + for (i = 0; i<count; i++) + { + if (value[i]=='+') + XmListSelectPos(ih->handle, i+1, False); /* XmListSelectPos starts at 1 */ + } + + XtVaSetValues(ih->handle, XmNselectionPolicy, XmEXTENDED_SELECT, + XmNselectionMode, XmNORMAL_MODE, NULL); /* must also restore this */ + iupAttribStoreStr(ih, "_IUPLIST_OLDVALUE", value); + } + } + } + + return 0; +} + +static int motListSetVisibleItemsAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->is_dropdown) + { + int count; + if (iupStrToInt(value, &count)==1) + XtVaSetValues(ih->handle, XmNvisibleItemCount, count, NULL); + } + return 1; +} + +static int motListSetShowDropdownAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->is_dropdown) + { + if (iupStrBoolean(value)) + { + XButtonEvent ev; + memset(&ev, 0, sizeof(XButtonEvent)); + ev.type = ButtonPress; + ev.display = XtDisplay(ih->handle); + ev.send_event = True; + ev.root = RootWindow(iupmot_display, iupmot_screen); + ev.time = clock()*CLOCKS_PER_SEC; + ev.window = XtWindow(ih->handle); + ev.state = Button1Mask; + ev.button = Button1; + ev.same_screen = True; + XtCallActionProc(ih->handle, "CBDropDownList", (XEvent*)&ev, 0, 0 ); + } + else + XtCallActionProc(ih->handle, "CBDisarm", 0, 0, 0 ); + } + return 0; +} + +static int motListSetTopItemAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->is_dropdown) + { + int pos = 1; + if (iupStrToInt(value, &pos)) + { + if (ih->data->has_editbox) + { + Widget cblist; + XtVaGetValues(ih->handle, XmNlist, &cblist, NULL); + XtVaSetValues(cblist, XmNtopItemPosition, pos, NULL); + } + else + XtVaSetValues(ih->handle, XmNtopItemPosition, pos, NULL); + } + } + return 0; +} + +static int motListSetSpacingAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->is_dropdown) + return 0; + + if (!iupStrToInt(value, &ih->data->spacing)) + ih->data->spacing = 0; + + if (ih->handle) + { + if (ih->data->has_editbox) + { + Widget cblist; + XtVaGetValues(ih->handle, XmNlist, &cblist, NULL); + XtVaSetValues(cblist, XmNlistSpacing, ih->data->spacing*2, + XmNlistMarginWidth, ih->data->spacing, + XmNlistMarginHeight, ih->data->spacing, + NULL); + } + else + XtVaSetValues(ih->handle, XmNlistSpacing, ih->data->spacing*2, + XmNlistMarginWidth, ih->data->spacing, + XmNlistMarginHeight, ih->data->spacing, + NULL); + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ +} + +static int motListSetPaddingAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->has_editbox) + return 0; + + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle) + { + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XtVaSetValues(cbedit, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ +} + +static int motListSetReadOnlyAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->has_editbox) + { + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XtVaSetValues(cbedit, XmNeditable, iupStrBoolean(value)? False: True, NULL); + } + return 0; +} + +static char* motListGetReadOnlyAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + Boolean editable; + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XtVaGetValues(cbedit, XmNeditable, &editable, NULL); + if (editable) + return "YES"; + else + return "NO"; + } + else + return NULL; +} + +static int motListSetInsertAttrib(Ihandle* ih, const char* value) +{ + if (!value) + return 0; + + if (ih->data->has_editbox) + { + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); /* disable callbacks */ + XmTextFieldRemove(cbedit); + XmTextFieldInsert(cbedit, XmTextFieldGetInsertionPosition(cbedit), (char*)value); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + + return 0; +} + +static int motListSetSelectedTextAttrib(Ihandle* ih, const char* value) +{ + XmTextPosition start, end; + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value) + return 0; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + if (XmTextFieldGetSelectionPosition(cbedit, &start, &end) && start!=end) + { + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); /* disable callbacks */ + XmTextFieldReplace(cbedit, start, end, (char*)value); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + + return 0; +} + +static char* motListGetSelectedTextAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + char* selectedtext, *str; + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + selectedtext = XmTextFieldGetSelection(cbedit); + str = iupStrGetMemoryCopy(selectedtext); + XtFree(selectedtext); + return str; + } + else + return NULL; +} + +static int motListSetAppendAttrib(Ihandle* ih, const char* value) +{ + if (value && ih->data->has_editbox) + { + XmTextPosition pos; + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + pos = XmTextFieldGetLastPosition(cbedit); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); /* disable callbacks */ + XmTextFieldInsert(cbedit, pos+1, (char*)value); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + return 0; +} + +static int motListSetSelectionAttrib(Ihandle* ih, const char* value) +{ + int start=1, end=1; + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldClearSelection(cbedit, CurrentTime); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldSetSelection(cbedit, (XmTextPosition)0, (XmTextPosition)XmTextFieldGetLastPosition(cbedit), CurrentTime); + return 0; + } + + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<1 || end<1) + return 0; + + start--; /* IUP starts at 1 */ + end--; + + /* end is inside the selection, in IUP is outside */ + end--; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldSetSelection(cbedit, (XmTextPosition)start, (XmTextPosition)end, CurrentTime); + + return 0; +} + +static char* motListGetSelectionAttrib(Ihandle* ih) +{ + XmTextPosition start = 0, end = 0; + char* str; + Widget cbedit; + if (!ih->data->has_editbox) + return NULL; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + if (!XmTextFieldGetSelectionPosition(cbedit, &start, &end) || start==end) + return NULL; + + str = iupStrGetMemory(100); + + /* end is inside the selection, in IUP is outside */ + end++; + + start++; /* IUP starts at 1 */ + end++; + sprintf(str, "%d:%d", (int)start, (int)end); + + return str; +} + +static int motListSetSelectionPosAttrib(Ihandle* ih, const char* value) +{ + int start=0, end=0; + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldClearSelection(cbedit, CurrentTime); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldSetSelection(cbedit, (XmTextPosition)0, (XmTextPosition)XmTextFieldGetLastPosition(cbedit), CurrentTime); + return 0; + } + + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<0 || end<0) + return 0; + + /* end is inside the selection, in IUP is outside */ + end--; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldSetSelection(cbedit, (XmTextPosition)start, (XmTextPosition)end, CurrentTime); + + return 0; +} + +static char* motListGetSelectionPosAttrib(Ihandle* ih) +{ + XmTextPosition start = 0, end = 0; + char* str; + Widget cbedit; + if (!ih->data->has_editbox) + return NULL; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + if (!XmTextFieldGetSelectionPosition(cbedit, &start, &end) || start==end) + return NULL; + + str = iupStrGetMemory(100); + + /* end is inside the selection, in IUP is outside */ + end++; + + sprintf(str, "%d:%d", (int)start, (int)end); + + return str; +} + +static int motListSetCaretAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + pos--; /* IUP starts at 1 */ + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldSetInsertionPosition(cbedit, (XmTextPosition)pos); + XmTextFieldShowPosition(cbedit, (XmTextPosition)pos); + + return 0; +} + +static char* motListGetCaretAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + XmTextPosition pos; + Widget cbedit; + char* str = iupStrGetMemory(50); + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + pos = XmTextFieldGetInsertionPosition(cbedit); + pos++; /* IUP starts at 1 */ + sprintf(str, "%d", (int)pos); + return str; + } + else + return NULL; +} + +static int motListSetCaretPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldSetInsertionPosition(cbedit, (XmTextPosition)pos); + XmTextFieldShowPosition(cbedit, (XmTextPosition)pos); + + return 0; +} + +static char* motListGetCaretPosAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + XmTextPosition pos; + Widget cbedit; + char* str = iupStrGetMemory(50); + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + pos = XmTextFieldGetInsertionPosition(cbedit); + sprintf(str, "%d", (int)pos); + return str; + } + else + return NULL; +} + +static int motListSetScrollToAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 1) pos = 1; + pos--; /* return to Motif referece */ + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldShowPosition(cbedit, (XmTextPosition)pos); + + return 0; +} + +static int motListSetScrollToPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldShowPosition(cbedit, (XmTextPosition)pos); + + return 0; +} + +static int motListSetNCAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->has_editbox) + return 0; + + if (!iupStrToInt(value, &ih->data->nc)) + ih->data->nc = INT_MAX; + + if (ih->handle) + { + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XtVaSetValues(cbedit, XmNmaxLength, ih->data->nc, NULL); + } + return 0; +} + +static int motListSetClipboardAttrib(Ihandle *ih, const char *value) +{ + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + + if (iupStrEqualNoCase(value, "COPY")) + { + char *str = XmTextFieldGetSelection(cbedit); + + XmTextFieldCopy(cbedit, CurrentTime); + + /* do it also for the X clipboard */ + XStoreBytes(iupmot_display, str, strlen(str)+1); + XtFree(str); + } + else if (iupStrEqualNoCase(value, "CUT")) + { + char *str = XmTextFieldGetSelection(cbedit); + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + + XmTextFieldCut(cbedit, CurrentTime); + + /* do it also for the X clipboard */ + XStoreBytes(iupmot_display, str, strlen(str)+1); + XtFree(str); + XmTextFieldRemove(cbedit); + + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + else if (iupStrEqualNoCase(value, "PASTE")) + { + int size; + char* str = XFetchBytes(iupmot_display, &size); + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + + XmTextFieldPaste(cbedit); /* TODO: this could force 2 pastes, check in CDE */ + + /* do it also for the X clipboard */ + XmTextFieldRemove(cbedit); + XmTextFieldInsert(cbedit, XmTextFieldGetInsertionPosition(cbedit), str); + XFree(str); + + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + else if (iupStrEqualNoCase(value, "CLEAR")) + { + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XmTextFieldRemove(cbedit); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + return 0; +} + + +/*********************************************************************************/ + + +static void motListEditModifyVerifyCallback(Widget cbedit, Ihandle *ih, XmTextVerifyPtr text) +{ + int start, end, key = 0; + char *value, *new_value, *insert_value; + KeySym motcode = 0; + IFnis cb; + + if (iupAttribGet(ih, "_IUPMOT_DISABLE_TEXT_CB")) + return; + + cb = (IFnis)IupGetCallback(ih, "EDIT_CB"); + if (!cb && !ih->data->mask) + return; + + if (text->event && text->event->type == KeyPress) + { + unsigned int state = ((XKeyEvent*)text->event)->state; + if (state & ControlMask || /* Ctrl */ + state & Mod1Mask || + state & Mod5Mask || /* Alt */ + state & Mod4Mask) /* Apple/Win */ + return; + + motcode = XKeycodeToKeysym(iupmot_display, ((XKeyEvent*)text->event)->keycode, 0); + } + + value = XmTextFieldGetString(cbedit); + start = text->startPos; + end = text->endPos; + insert_value = text->text->ptr; + + if (motcode == XK_Delete) + { + new_value = value; + iupStrRemove(value, start, end, 1); + } + else if (motcode == XK_BackSpace) + { + new_value = value; + iupStrRemove(value, start, end, -1); + } + else + { + if (!value) + new_value = iupStrDup(insert_value); + else if (insert_value) + new_value = iupStrInsert(value, insert_value, start, end); + else + new_value = value; + } + + if (insert_value && insert_value[0]!=0 && insert_value[1]==0) + key = insert_value[0]; + + if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0) + { + if (new_value != value) free(new_value); + XtFree(value); + text->doit = False; /* abort processing */ + return; + } + + if (cb) + { + int cb_ret = cb(ih, key, (char*)new_value); + if (cb_ret==IUP_IGNORE) + text->doit = False; /* abort processing */ + else if (cb_ret==IUP_CLOSE) + { + IupExitLoop(); + text->doit = False; /* abort processing */ + } + else if (cb_ret!=0 && key!=0 && + cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE) + { + insert_value[0] = (char)cb_ret; /* replace key */ + } + } + + if (new_value != value) free(new_value); + XtFree(value); +} + +static void motListEditMotionVerifyCallback(Widget w, Ihandle* ih, XmTextVerifyCallbackStruct* textverify) +{ + int pos; + + IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB"); + if (!cb) return; + + pos = textverify->newInsert; + + if (pos != ih->data->last_caret_pos) + { + ih->data->last_caret_pos = pos; + cb(ih, 1, pos+1, pos); + } + + (void)w; +} + +static void motListEditKeyPressEvent(Widget cbedit, Ihandle *ih, XKeyEvent *evt, Boolean *cont) +{ + *cont = True; + iupmotKeyPressEvent(cbedit, ih, (XEvent*)evt, cont); + if (*cont == False) + return; + + if (evt->state & ControlMask) /* Ctrl */ + { + KeySym motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + if (motcode == XK_c) + { + motListSetClipboardAttrib(ih, "COPY"); + *cont = False; + return; + } + else if (motcode == XK_x) + { + motListSetClipboardAttrib(ih, "CUT"); + *cont = False; + return; + } + else if (motcode == XK_v) + { + motListSetClipboardAttrib(ih, "PASTE"); + *cont = False; + return; + } + else if (motcode == XK_a) + { + XmTextFieldSetSelection(cbedit, 0, XmTextFieldGetLastPosition(cbedit), CurrentTime); + *cont = False; + return; + } + } +} + +static void motListEditValueChangedCallback(Widget w, Ihandle* ih, XmAnyCallbackStruct* valuechanged) +{ + if (iupAttribGet(ih, "_IUPMOT_DISABLE_TEXT_CB")) + return; + + iupBaseCallValueChangedCb(ih); + + (void)valuechanged; + (void)w; +} + +static void motListDropDownPopupCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + IFni cb = (IFni)IupGetCallback(ih, "DROPDOWN_CB"); + if (cb) + cb(ih, 1); + (void)w; + (void)call_data; +} + +static void motListDropDownPopdownCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + IFni cb = (IFni)IupGetCallback(ih, "DROPDOWN_CB"); + if (cb) + cb(ih, 0); + (void)w; + (void)call_data; +} + +static void motListDefaultActionCallback(Widget w, Ihandle* ih, XmListCallbackStruct* call_data) +{ + if (call_data->event->type == ButtonPress || call_data->event->type == ButtonRelease) + { + IFnis cb = (IFnis) IupGetCallback(ih, "DBLCLICK_CB"); + if (cb) + { + int pos = call_data->item_position; /* Here Motif already starts at 1 */ + iupListSingleCallDblClickCallback(ih, cb, pos); + } + } + + (void)w; +} + +static void motListComboBoxSelectionCallback(Widget w, Ihandle* ih, XmComboBoxCallbackStruct* call_data) +{ + IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION"); + if (cb) + { + int pos = call_data->item_position; + if (pos==0) + { + /* must check if it is really checked or it is for the edit box */ + XmString* items; + XtVaGetValues(ih->handle, XmNitems, &items, NULL); + if (!XmStringCompare(call_data->item_or_text, items[0])) + return; + } + pos++; /* IUP starts at 1 */ + iupListSingleCallActionCallback(ih, cb, pos); + } + + if (!ih->data->has_editbox) + iupBaseCallValueChangedCb(ih); + + (void)w; +} + +static void motListBrowseSelectionCallback(Widget w, Ihandle* ih, XmListCallbackStruct* call_data) +{ + IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION"); + if (cb) + { + int pos = call_data->item_position; /* Here Motif already starts at 1 */ + iupListSingleCallActionCallback(ih, cb, pos); + } + + if (!ih->data->has_editbox) + iupBaseCallValueChangedCb(ih); + + (void)w; +} + +static void motListExtendedSelectionCallback(Widget w, Ihandle* ih, XmListCallbackStruct* call_data) +{ + IFns multi_cb = (IFns)IupGetCallback(ih, "MULTISELECT_CB"); + IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION"); + if (multi_cb || cb) + { + int* pos = call_data->selected_item_positions; + int sel_count = call_data->selected_item_count; + int i; + + /* In Motif, the position of item is "plus one". + "iupListMultipleCallActionCallback" works with the list of selected items from the zero position. + So, "minus one" here. */ + for (i = 0; i < sel_count; i++) + pos[i] -= 1; + + iupListMultipleCallActionCallback(ih, cb, multi_cb, pos, sel_count); + } + + if (!ih->data->has_editbox) + iupBaseCallValueChangedCb(ih); + + (void)w; +} + + +/*********************************************************************************/ + + +static int motListMapMethod(Ihandle* ih) +{ + int num_args = 0; + Arg args[30]; + Widget parent = iupChildTreeGetNativeParentHandle(ih); + char* child_id = iupDialogGetChildIdStr(ih); + + if (ih->data->is_dropdown || ih->data->has_editbox) + { + /* could not set XmNmappedWhenManaged to False because the list and the edit box where not displayed */ + /* iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + iupmotSetArg(args, num_args, XmNmarginHeight, 0); + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupmotSetArg(args, num_args, XmNhighlightThickness, 2); + iupmotSetArg(args, num_args, XmNshadowThickness, 2); + + if (ih->data->has_editbox) + { + if (ih->data->is_dropdown) + iupmotSetArg(args, num_args, XmNcomboBoxType, XmDROP_DOWN_COMBO_BOX); /* hidden-list+edit */ + else + iupmotSetArg(args, num_args, XmNcomboBoxType, XmCOMBO_BOX); /* visible-list+edit */ + } + else + iupmotSetArg(args, num_args, XmNcomboBoxType, XmDROP_DOWN_LIST); /* hidden-list */ + + ih->handle = XtCreateManagedWidget( + child_id, /* child identifier */ + xmComboBoxWidgetClass, /* widget class */ + parent, /* widget parent */ + args, num_args); + } + else + { + Widget sb_win; + + /* Create the scrolled window */ + + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); + iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE); + iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); /* can NOT be XmAS_NEEDED because XmAPPLICATION_DEFINED */ + iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ + iupmotSetArg(args, num_args, XmNborderWidth, 0); + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + + sb_win = XtCreateManagedWidget( + child_id, /* child identifier */ + xmScrolledWindowWidgetClass, /* widget class */ + parent, /* widget parent */ + args, num_args); + + if (!sb_win) + return IUP_ERROR; + + parent = sb_win; + child_id = "list"; + + /* Create the list */ + + num_args = 0; + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupmotSetArg(args, num_args, XmNhighlightThickness, 2); + iupmotSetArg(args, num_args, XmNshadowThickness, 2); + + iupmotSetArg(args, num_args, XmNlistMarginHeight, 0); /* default padding */ + iupmotSetArg(args, num_args, XmNlistMarginWidth, 0); + iupmotSetArg(args, num_args, XmNlistSpacing, 0); + iupmotSetArg(args, num_args, XmNlistSizePolicy, XmCONSTANT); /* don't grow to fit, add scrollbar */ + + if (ih->data->is_multiple) + iupmotSetArg(args, num_args, XmNselectionPolicy, XmEXTENDED_SELECT); + else + iupmotSetArg(args, num_args, XmNselectionPolicy, XmBROWSE_SELECT); + + if (iupAttribGetBoolean(ih, "AUTOHIDE")) + iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmAS_NEEDED); + else + iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); + + ih->handle = XtCreateManagedWidget( + child_id, /* child identifier */ + xmListWidgetClass, /* widget class */ + parent, /* widget parent */ + args, num_args); + } + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + if (ih->data->is_dropdown || ih->data->has_editbox) + { + Widget cbedit, cblist; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XtVaGetValues(ih->handle, XmNlist, &cblist, NULL); + + XtAddEventHandler(cbedit, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(cbedit, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(cbedit, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddCallback(cbedit, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + + XtAddCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motListComboBoxSelectionCallback, (XtPointer)ih); + + if (ih->data->has_editbox) + { + XtAddEventHandler(cbedit, KeyPressMask, False, (XtEventHandler)motListEditKeyPressEvent, (XtPointer)ih); + XtAddCallback(cbedit, XmNmodifyVerifyCallback, (XtCallbackProc)motListEditModifyVerifyCallback, (XtPointer)ih); + XtAddCallback(cbedit, XmNmotionVerifyCallback, (XtCallbackProc)motListEditMotionVerifyCallback, (XtPointer)ih); + XtAddCallback(cbedit, XmNvalueChangedCallback, (XtCallbackProc)motListEditValueChangedCallback, (XtPointer)ih); + + /* Disable Drag Source */ + iupmotDisableDragSource(cbedit); + } + else + XtAddEventHandler(cbedit, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + + if (ih->data->is_dropdown) + { + XtVaSetValues(ih->handle, XmNvisibleItemCount, 5, NULL); + XtAddCallback(XtParent(XtParent(cblist)), XmNpopupCallback, (XtCallbackProc)motListDropDownPopupCallback, (XtPointer)ih); + XtAddCallback(XtParent(XtParent(cblist)), XmNpopdownCallback, (XtCallbackProc)motListDropDownPopdownCallback, (XtPointer)ih); + } + else + { + XtAddCallback(cblist, XmNdefaultActionCallback, (XtCallbackProc)motListDefaultActionCallback, (XtPointer)ih); + XtAddEventHandler(cblist, PointerMotionMask, False, (XtEventHandler)iupmotPointerMotionEvent, (XtPointer)ih); + XtAddEventHandler(cblist, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)iupmotButtonPressReleaseEvent, (XtPointer)ih); + + /* Disable Drag Source */ + iupmotDisableDragSource(cblist); + } + } + else + { + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)parent); + XtVaSetValues(parent, XmNworkWindow, ih->handle, NULL); + + XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, PointerMotionMask, False, (XtEventHandler)iupmotPointerMotionEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)iupmotButtonPressReleaseEvent, (XtPointer)ih); + + XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + XtAddCallback (ih->handle, XmNbrowseSelectionCallback, (XtCallbackProc)motListBrowseSelectionCallback, (XtPointer)ih); + XtAddCallback (ih->handle, XmNextendedSelectionCallback, (XtCallbackProc)motListExtendedSelectionCallback, (XtPointer)ih); + XtAddCallback (ih->handle, XmNdefaultActionCallback, (XtCallbackProc)motListDefaultActionCallback, (XtPointer)ih); + } + + /* Disable Drag Source */ + iupmotDisableDragSource(ih->handle); + + /* initialize the widget */ + if (ih->data->is_dropdown || ih->data->has_editbox) + XtRealizeWidget(ih->handle); + else + XtRealizeWidget(parent); + + if (IupGetGlobal("_IUP_RESET_TXTCOLORS")) + { + iupmotSetGlobalColorAttrib(ih->handle, XmNbackground, "TXTBGCOLOR"); + iupmotSetGlobalColorAttrib(ih->handle, XmNforeground, "TXTFGCOLOR"); + IupSetGlobal("_IUP_RESET_TXTCOLORS", NULL); + } + + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)motListConvertXYToPos); + + iupListSetInitialItems(ih); + + return IUP_NOERROR; +} + +void iupdrvListInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motListMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motListSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, motListSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT); + + /* IupList only */ + iupClassRegisterAttributeId(ic, "IDVALUE", motListGetIdValueAttrib, iupListSetIdValueAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE", motListGetValueAttrib, motListSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VISIBLE_ITEMS", NULL, motListSetVisibleItemsAttrib, IUPAF_SAMEASSYSTEM, "5", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "TOPITEM", NULL, motListSetTopItemAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWDROPDOWN", NULL, motListSetShowDropdownAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPACING", iupListGetSpacingAttrib, motListSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + + iupClassRegisterAttribute(ic, "PADDING", iupListGetPaddingAttrib, motListSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "SELECTEDTEXT", motListGetSelectedTextAttrib, motListSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTION", motListGetSelectionAttrib, motListSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTIONPOS", motListGetSelectionPosAttrib, motListSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARET", motListGetCaretAttrib, motListSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARETPOS", motListGetCaretPosAttrib, motListSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INSERT", NULL, motListSetInsertAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "APPEND", NULL, motListSetAppendAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "READONLY", motListGetReadOnlyAttrib, motListSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "NC", iupListGetNCAttrib, motListSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, motListSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTO", NULL, motListSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, motListSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); +} diff --git a/iup/src/mot/iupmot_loop.c b/iup/src/mot/iupmot_loop.c new file mode 100755 index 0000000..828ddcd --- /dev/null +++ b/iup/src/mot/iupmot_loop.c @@ -0,0 +1,108 @@ +/** \file + * \brief Motif Message Loop + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> + +#include <Xm/Xm.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iupmot_drv.h" + + +/* local variables */ +static int mot_mainloop = 0; +static int mot_exitmainloop = 0; +static IFidle mot_idle_cb = NULL; +static XtWorkProcId mot_idle_id; + + +static Boolean motIdlecbWorkProc(XtPointer client_data) +{ + (void)client_data; + if (mot_idle_cb) + { + int ret = mot_idle_cb(); + if (ret == IUP_CLOSE) + { + mot_idle_cb = NULL; + IupExitLoop(); + return True; /* removes the working procedure */ + } + if (ret == IUP_IGNORE) + { + mot_idle_cb = NULL; + return True; /* removes the working procedure */ + } + + return False; /* keeps the working procedure */ + } + + return True; /* removes the working procedure */ +} + +void iupdrvSetIdleFunction(Icallback f) +{ + if (mot_idle_cb) + XtRemoveWorkProc(mot_idle_id); + + mot_idle_cb = (IFidle)f; + + if (mot_idle_cb) + mot_idle_id = XtAppAddWorkProc(iupmot_appcontext, motIdlecbWorkProc, NULL); +} + +static int motLoopStep(void) +{ + XtAppProcessEvent(iupmot_appcontext, XtIMAll); + return (mot_exitmainloop)? IUP_CLOSE : IUP_DEFAULT; +} + +void IupExitLoop(void) +{ + mot_exitmainloop = 1; +} + +int IupMainLoopLevel(void) +{ + return mot_mainloop; +} + +int IupMainLoop(void) +{ + mot_mainloop++; + mot_exitmainloop = 0; + + while (!mot_exitmainloop) + { + if (motLoopStep() == IUP_CLOSE) + break; + } + + mot_exitmainloop = 0; + mot_mainloop--; + return IUP_NOERROR; +} + +int IupLoopStep(void) +{ + if (!XtAppPending(iupmot_appcontext)) + return IUP_DEFAULT; + + return motLoopStep(); +} + +void IupFlush(void) +{ + while (XPending(iupmot_display) != 0) + { + if (motLoopStep() == IUP_CLOSE) + break; + } + + XFlush(iupmot_display); +} diff --git a/iup/src/mot/iupmot_menu.c b/iup/src/mot/iupmot_menu.c new file mode 100755 index 0000000..be9b953 --- /dev/null +++ b/iup/src/mot/iupmot_menu.c @@ -0,0 +1,457 @@ +/** \file + * \brief Menu Resources + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/RowColumn.h> +#include <Xm/Separator.h> +#include <Xm/CascadeB.h> +#include <Xm/ToggleB.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_label.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_image.h" +#include "iup_menu.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +static int mot_menu_exitloop = 0; + +int iupdrvMenuPopup(Ihandle* ih, int x, int y) +{ + XButtonEvent ev; + ev.x_root = x; + ev.y_root = y; + XmMenuPosition(ih->handle, &ev); + + XtManageChild(ih->handle); + + mot_menu_exitloop = 0; + while (!mot_menu_exitloop) + XtAppProcessEvent(iupmot_appcontext, XtIMAll); + mot_menu_exitloop = 0; + + return IUP_NOERROR; +} + +int iupdrvMenuGetMenuBarSize(Ihandle* ih) +{ + int ch; + iupdrvFontGetCharSize(ih, NULL, &ch); + return 5 + ch + 5; +} + + +/*******************************************************************************************/ + + +static void motItemActivateCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + Icallback cb; + + if (XmIsToggleButton(ih->handle) && !iupAttribGetBoolean(ih, "AUTOTOGGLE") && !iupAttribGetBoolean(ih->parent, "RADIO")) + { + /* Motif by default will do autotoggle */ + XmToggleButtonSetState(ih->handle, !XmToggleButtonGetState(ih->handle),0); + } + + cb = IupGetCallback(ih, "ACTION"); + if (cb && cb(ih)==IUP_CLOSE) + IupExitLoop(); + + (void)w; + (void)call_data; +} + +static void motItemArmCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + Icallback cb = IupGetCallback(ih, "HIGHLIGHT_CB"); + if (cb) + cb(ih); + + (void)w; + (void)call_data; +} + +static void motMenuMapCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + Icallback cb = IupGetCallback(ih, "OPEN_CB"); + if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "OPEN_CB"); /* check also in the Submenu */ + if (cb) cb(ih); + + (void)w; + (void)call_data; +} + +static void motMenuUnmapCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + Icallback cb = IupGetCallback(ih, "MENUCLOSE_CB"); + if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "MENUCLOSE_CB"); /* check also in the Submenu */ + if (cb) cb(ih); + + (void)w; + (void)call_data; +} + +static void motPopupMenuUnmapCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + motMenuUnmapCallback(w, ih, call_data); + mot_menu_exitloop = 1; +} + + +/*******************************************************************************************/ + + +static void motMenuUnMapMethod(Ihandle* ih) +{ + if (iupMenuIsMenuBar(ih)) + XtDestroyWidget(ih->handle); + else + XtDestroyWidget(XtParent(ih->handle)); /* in this case the RowColumn widget is a child of a MenuShell. */ +} + +static int motMenuMapMethod(Ihandle* ih) +{ + int num_args = 0; + Arg args[30]; + + if (iupMenuIsMenuBar(ih)) + { + /* top level menu used for MENU attribute in IupDialog (a menu bar) */ + + ih->handle = XtVaCreateManagedWidget( + iupMenuGetChildIdStr(ih), + xmRowColumnWidgetClass, + iupChildTreeGetNativeParentHandle(ih), + XmNrowColumnType, XmMENU_BAR, + XmNmarginHeight, 0, + XmNmarginWidth, 0, + XmNresizeWidth, False, + NULL); + if (!ih->handle) + return IUP_ERROR; + } + else + { + /* all XmCreate* functions here, also create RowColumn Widgets. */ + + if (ih->parent) + { + /* parent is a submenu */ + + if (iupAttribGetBoolean(ih, "RADIO")) + { + iupmotSetArg(args, num_args, XmNpacking, XmPACK_COLUMN); + iupmotSetArg(args, num_args, XmNradioBehavior, TRUE); + } + + ih->handle = XmCreatePulldownMenu( + ih->parent->handle, + iupMenuGetChildIdStr(ih), + args, + num_args); + if (!ih->handle) + return IUP_ERROR; + + /* update the CascadeButton */ + XtVaSetValues(ih->parent->handle, XmNsubMenuId, ih->handle, NULL); + + XtAddCallback(ih->handle, XmNmapCallback, (XtCallbackProc)motMenuMapCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNunmapCallback, (XtCallbackProc)motMenuUnmapCallback, (XtPointer)ih); + } + else + { + /* top level menu used for IupPopup */ + + iupmotSetArg(args, num_args, XmNpopupEnabled, XmPOPUP_AUTOMATIC); + + ih->handle = XmCreatePopupMenu( + iupmot_appshell, + iupMenuGetChildIdStr(ih), + args, + num_args); + if (!ih->handle) + return IUP_ERROR; + + XtAddCallback(ih->handle, XmNmapCallback, (XtCallbackProc)motMenuMapCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNunmapCallback, (XtCallbackProc)motPopupMenuUnmapCallback, (XtPointer)ih); + } + } + + ih->serial = iupMenuGetChildId(ih); /* must be after using the string */ + + return IUP_NOERROR; +} + +void iupdrvMenuInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motMenuMapMethod; + ic->UnMap = motMenuUnMapMethod; + + /* Used by iupdrvMenuGetMenuBarSize */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, NULL, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_DEFAULT); /* use inheritance to retrieve standard fonts */ + + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); +} + + +/*******************************************************************************************/ + + +static int motItemSetTitleImageAttrib(Ihandle* ih, const char* value) +{ + iupmotSetPixmap(ih, value, XmNlabelPixmap, 0); + return 1; +} + +static int motItemSetTitleAttrib(Ihandle* ih, const char* value) +{ + char *str; + + if (!value) + { + str = " "; + value = str; + } + else + str = iupMenuProcessTitle(ih, value); + + if (XmIsToggleButton(ih->handle)) + { + char *p = strchr(str, '\t'); + if (p) + { + int offset = (p-str); + char* new_value = iupStrDup(str); + char* acc_value = new_value + offset + 1; + new_value[offset] = 0; + iupmotSetMnemonicTitle(ih, new_value); + iupmotSetString(ih->handle, XmNacceleratorText, acc_value); + free(new_value); + + if (str != value) free(str); + return 1; + } + } + + iupmotSetMnemonicTitle(ih, str); + + if (str != value) free(str); + return 1; +} + +static int motItemSetValueAttrib(Ihandle* ih, const char* value) +{ + if (XmIsToggleButton(ih->handle)) + { + if (iupAttribGetBoolean(ih->parent, "RADIO")) + value = "ON"; + + XmToggleButtonSetState(ih->handle, iupStrBoolean(value),0); + } + return 0; +} + +static char* motItemGetValueAttrib(Ihandle* ih) +{ + if (XmIsToggleButton(ih->handle) && XmToggleButtonGetState(ih->handle)) + return "ON"; + else + return "OFF"; +} + +static int motItemMapMethod(Ihandle* ih) +{ + int pos; + + if (!ih->parent) + return IUP_ERROR; + + /* Menu bar can contain only CascadeButtons */ + if (iupMenuIsMenuBar(ih->parent)) + { + ih->handle = XtVaCreateManagedWidget( + iupMenuGetChildIdStr(ih), + xmCascadeButtonWidgetClass, + ih->parent->handle, + NULL); + + XtAddCallback(ih->handle, XmNactivateCallback, (XtCallbackProc)motItemActivateCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNcascadingCallback, (XtCallbackProc)motItemArmCallback, (XtPointer)ih); + } + else + { + int num_args = 0; + Arg args[10]; + + if (iupAttribGetBoolean(ih->parent, "RADIO")) + { + iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); + iupmotSetArg(args, num_args, XmNindicatorType, XmONE_OF_MANY_ROUND); + iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK_BOX); + iupmotSetArg(args, num_args, XmNindicatorSize, 13); + iupmotSetArg(args, num_args, XmNselectColor, iupmotColorGetPixel(0, 0, 0)); + } + else + { + if (iupAttribGetBoolean(ih, "HIDEMARK")) + iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_NONE); + else + iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK); + iupmotSetArg(args, num_args, XmNlabelType, iupAttribGet(ih, "TITLEIMAGE")? XmPIXMAP: XmSTRING); + } + + ih->handle = XtCreateManagedWidget( + iupMenuGetChildIdStr(ih), + xmToggleButtonWidgetClass, + ih->parent->handle, + args, + num_args); + + XtAddCallback(ih->handle, XmNvalueChangedCallback, (XtCallbackProc)motItemActivateCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNarmCallback, (XtCallbackProc)motItemArmCallback, (XtPointer)ih); + } + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupMenuGetChildId(ih); /* must be after using the string */ + + XtAddCallback (ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + + pos = IupGetChildPos(ih->parent, ih); + XtVaSetValues(ih->handle, XmNpositionIndex, pos, NULL); /* RowColumn Constraint */ + + iupUpdateStandardFontAttrib(ih); + + return IUP_NOERROR; +} + +void iupdrvItemInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motItemMapMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Common */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, iupdrvSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* use inheritance to retrieve standard fonts */ + + /* Visual */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* IupItem only */ + iupClassRegisterAttribute(ic, "VALUE", motItemGetValueAttrib, motItemSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TITLE", NULL, motItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TITLEIMAGE", NULL, motItemSetTitleImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupItem Gtk and Motif only */ + iupClassRegisterAttribute(ic, "HIDEMARK", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED); +} + + +/*******************************************************************************************/ + + +static int motSubmenuMapMethod(Ihandle* ih) +{ + int pos; + + if (!ih->parent) + return IUP_ERROR; + + ih->handle = XtVaCreateManagedWidget( + iupMenuGetChildIdStr(ih), + xmCascadeButtonWidgetClass, + ih->parent->handle, + NULL); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupMenuGetChildId(ih); /* must be after using the string */ + + pos = IupGetChildPos(ih->parent, ih); + XtVaSetValues(ih->handle, XmNpositionIndex, pos, NULL); /* RowColumn Constraint */ + + XtAddCallback(ih->handle, XmNcascadingCallback, (XtCallbackProc)motItemArmCallback, (XtPointer)ih); + + iupUpdateStandardFontAttrib(ih); + + return IUP_NOERROR; +} + +void iupdrvSubmenuInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motSubmenuMapMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Common */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, iupdrvSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* use inheritance to retrieve standard fonts */ + + /* Visual */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* IupSubmenu only */ + iupClassRegisterAttribute(ic, "TITLE", NULL, motItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +} + + +/*******************************************************************************************/ + + +static int motSeparatorMapMethod(Ihandle* ih) +{ + int pos; + + if (!ih->parent) + return IUP_ERROR; + + ih->handle = XtVaCreateManagedWidget( + iupMenuGetChildIdStr(ih), + xmSeparatorWidgetClass, + ih->parent->handle, + NULL); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupMenuGetChildId(ih); /* must be after using the string */ + + pos = IupGetChildPos(ih->parent, ih); + XtVaSetValues(ih->handle, XmNpositionIndex, pos, NULL); /* RowColumn Constraint */ + + return IUP_NOERROR; +} + +void iupdrvSeparatorInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motSeparatorMapMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); +} diff --git a/iup/src/mot/iupmot_messagedlg.c b/iup/src/mot/iupmot_messagedlg.c new file mode 100755 index 0000000..6660503 --- /dev/null +++ b/iup/src/mot/iupmot_messagedlg.c @@ -0,0 +1,191 @@ +/** \file + * \brief Motif IupMessageDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <Xm/Xm.h> +#include <Xm/MwmUtil.h> +#include <Xm/MessageB.h> +#include <Xm/Protocols.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drvinfo.h" +#include "iup_dialog.h" +#include "iup_strmessage.h" + +#include "iupmot_drv.h" + + +static void motMessageDlgDeleteWindowCallback(Widget w, XtPointer client_data, XtPointer call_data) +{ + Ihandle *ih = (Ihandle*)client_data; + if (!ih) return; + (void)call_data; + (void)w; + if (iupStrEqualNoCase(iupAttribGetStr(ih, "BUTTONS"), "OK")) + iupAttribSetStr(ih, "BUTTONRESPONSE", "1"); + else + iupAttribSetStr(ih, "BUTTONRESPONSE", "2"); + iupAttribSetStr(ih, "_IUP_WM_DELETE", "1"); +} + +static void motMessageDlgCallback(Widget w, Ihandle* ih, XmAnyCallbackStruct* call_data) +{ + (void)w; + if (call_data->reason == XmCR_OK) + iupAttribSetStr(ih, "BUTTONRESPONSE", "1"); + else if (call_data->reason == XmCR_CANCEL) + iupAttribSetStr(ih, "BUTTONRESPONSE", "2"); +} + +static void motMessageDlgHelpCallback(Widget w, XtPointer client_data, XtPointer call_data) +{ + Ihandle *ih = (Ihandle*)client_data; + Icallback cb = (Icallback)IupGetCallback(ih, "HELP_CB"); + if (cb && cb(ih) == IUP_CLOSE) + { + if (iupStrEqualNoCase(iupAttribGetStr(ih, "BUTTONS"), "OK")) + iupAttribSetStr(ih, "BUTTONRESPONSE", "1"); + else + iupAttribSetStr(ih, "BUTTONRESPONSE", "2"); + } + + (void)call_data; + (void)w; +} + +static int motMessageDlgPopup(Ihandle* ih, int x, int y) +{ + InativeHandle* parent = iupDialogGetNativeParent(ih); + Widget msgbox, dialog; + int style = XmDIALOG_FULL_APPLICATION_MODAL; + int type = XmDIALOG_MESSAGE; + int num_but = 2; + char *value; + + iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */ + iupAttribSetInt(ih, "_IUPDLG_Y", y); + + if (parent) + { + msgbox = XmCreateMessageDialog(parent, "messagedialog", NULL, 0); + dialog = XtParent(msgbox); + } + else + { + dialog = XtAppCreateShell(NULL, "messagedialog", topLevelShellWidgetClass, iupmot_display, NULL, 0); + msgbox = XmCreateMessageBox(dialog, "messagebox", NULL, 0); + style = XmDIALOG_MODELESS; + XtVaSetValues(dialog, + XmNmwmInputMode, MWM_INPUT_FULL_APPLICATION_MODAL, + XmNmappedWhenManaged, False, + XmNsaveUnder, True, + NULL); + } + if (!msgbox) + return IUP_NOERROR; + + value = iupAttribGetStr(ih, "DIALOGTYPE"); + if (iupStrEqualNoCase(value, "ERROR")) + type = XmDIALOG_ERROR; + else if (iupStrEqualNoCase(value, "WARNING")) + type = XmDIALOG_WARNING; + else if (iupStrEqualNoCase(value, "INFORMATION")) + type = XmDIALOG_INFORMATION; + else if (iupStrEqualNoCase(value, "QUESTION")) + type = XmDIALOG_QUESTION; + + + value = iupAttribGet(ih, "TITLE"); + if (value) + iupmotSetString(msgbox, XmNdialogTitle, value); + else + { + if (parent) + { + XmString title; + XtVaGetValues(parent, XmNdialogTitle, &title, NULL); + XtVaSetValues(msgbox, XmNdialogTitle, title, NULL); + } + } + + value = iupAttribGet(ih, "VALUE"); + if (value) + iupmotSetString(msgbox, XmNmessageString, value); + + XtVaSetValues(msgbox, + XmNdialogType, type, + XmNdialogStyle, style, + XmNautoUnmanage, False, + XmNnoResize, True, + NULL); + + value = iupAttribGetStr(ih, "BUTTONS"); + if (iupStrEqualNoCase(value, "OK")) + { + XtUnmanageChild(XmMessageBoxGetChild(msgbox, XmDIALOG_CANCEL_BUTTON)); + num_but = 1; + } + else if (iupStrEqualNoCase(value, "YESNO")) + { + iupmotSetString(msgbox, XmNokLabelString, iupStrMessageGet("IUP_YES")); + iupmotSetString(msgbox, XmNcancelLabelString, iupStrMessageGet("IUP_NO")); + } + + if (!IupGetCallback(ih, "HELP_CB")) + XtUnmanageChild(XmMessageBoxGetChild(msgbox, XmDIALOG_HELP_BUTTON)); + + if (num_but == 2 && iupAttribGetInt(ih, "BUTTONDEFAULT") == 2) + XtVaSetValues(msgbox, XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON, NULL); + else + XtVaSetValues(msgbox, XmNdefaultButtonType, XmDIALOG_OK_BUTTON, NULL); + + XtAddCallback(msgbox, XmNokCallback, (XtCallbackProc)motMessageDlgCallback, (XtPointer)ih); + XtAddCallback(msgbox, XmNcancelCallback, (XtCallbackProc)motMessageDlgCallback, (XtPointer)ih); + XtAddCallback(msgbox, XmNhelpCallback, (XtCallbackProc)motMessageDlgHelpCallback, (XtPointer)ih); + + XmAddWMProtocolCallback(dialog, iupmot_wm_deletewindow, motMessageDlgDeleteWindowCallback, (XtPointer)ih); + XtManageChild(msgbox); + + XtRealizeWidget(dialog); + ih->handle = dialog; + iupDialogUpdatePosition(ih); + ih->handle = NULL; /* reset handle */ + + if (style == XmDIALOG_MODELESS) + XtPopup(dialog, XtGrabExclusive); + + /* while the user hasn't provided an answer, simulate main loop. + ** The answer changes as soon as the user selects one of the + ** buttons and the callback routine changes its value. */ + iupAttribSetStr(ih, "BUTTONRESPONSE", NULL); + while (iupAttribGet(ih, "BUTTONRESPONSE") == NULL) + XtAppProcessEvent(iupmot_appcontext, XtIMAll); + + if (!iupAttribGet(ih, "_IUP_WM_DELETE")) + { + XtUnmanageChild(msgbox); + + if (style == XmDIALOG_MODELESS) + { + XtPopdown(dialog); + XtDestroyWidget(dialog); + } + } + + return IUP_NOERROR; +} + +void iupdrvMessageDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = motMessageDlgPopup; +} diff --git a/iup/src/mot/iupmot_open.c b/iup/src/mot/iupmot_open.c new file mode 100755 index 0000000..a59dbff --- /dev/null +++ b/iup/src/mot/iupmot_open.c @@ -0,0 +1,141 @@ +/** \file + * \brief Motif Open/Close + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <locale.h> +#include <string.h> + +#include <Xm/Xm.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_globalattrib.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +/* global variables */ +Widget iupmot_appshell = 0; +Display* iupmot_display = 0; +int iupmot_screen = 0; +Visual* iupmot_visual = 0; +XtAppContext iupmot_appcontext = 0; + +void* iupdrvGetDisplay(void) +{ + return iupmot_display; +} + +void iupmotSetGlobalColorAttrib(Widget w, const char* xmname, const char* name) +{ + unsigned char r, g, b; + Pixel color; + + XtVaGetValues(w, xmname, &color, NULL); + iupmotColorGetRGB(color, &r, &g, &b); + + iupGlobalSetDefaultColorAttrib(name, r, g, b); +} + +int iupdrvOpen(int *argc, char ***argv) +{ + IupSetGlobal("DRIVER", "Motif"); + + /* XtSetLanguageProc(NULL, NULL, NULL); + Removed to avoid invalid locale in modern Linux that set LANG=en_US.UTF-8 */ + + /* We do NOT use XtVaOpenApplication because it crashes when using internal dummy argc and argv. + iupmot_appshell = XtVaOpenApplication(&iupmot_appcontext, "Iup", NULL, 0, argc, *argv, NULL, + sessionShellWidgetClass, NULL); */ + + XtToolkitInitialize(); + + iupmot_appcontext = XtCreateApplicationContext(); + + iupmot_display = XtOpenDisplay(iupmot_appcontext, NULL, NULL, "Iup", NULL, 0, argc, *argv); + if (!iupmot_display) + { + fprintf (stderr, "IUP error: cannot open display.\n"); + return IUP_ERROR; + } + + iupmot_appshell = XtAppCreateShell(NULL, "Iup", sessionShellWidgetClass, iupmot_display, NULL, 0); + if (!iupmot_appshell) + { + fprintf(stderr, "IUP error: cannot create shell.\n"); + return IUP_ERROR; + } + IupSetGlobal("APPSHELL", (char*)iupmot_appshell); + + IupStoreGlobal("SYSTEMLANGUAGE", setlocale(LC_ALL, NULL)); + + iupmot_screen = XDefaultScreen(iupmot_display); + + IupSetGlobal("XDISPLAY", (char*)iupmot_display); + IupSetGlobal("XSCREEN", (char*)iupmot_screen); + + /* screen depth can be 8bpp, but canvas can be 24bpp */ + { + XVisualInfo vinfo; + if (XMatchVisualInfo(iupmot_display, iupmot_screen, 24, TrueColor, &vinfo) || + XMatchVisualInfo(iupmot_display, iupmot_screen, 16, TrueColor, &vinfo)) + { + iupmot_visual = vinfo.visual; + IupSetGlobal("TRUECOLORCANVAS", "YES"); + } + else + { + iupmot_visual = DefaultVisual(iupmot_display, iupmot_screen); + IupSetGlobal("TRUECOLORCANVAS", "NO"); + } + } + + /* driver system version */ + { + int major = xmUseVersion/1000; + int minor = xmUseVersion - major * 1000; + IupSetfAttribute(NULL, "MOTIFVERSION", "%d.%d", major, minor); + IupSetfAttribute(NULL, "MOTIFNUMBER", "%d", (XmVERSION * 1000 + XmREVISION * 100 + XmUPDATE_LEVEL)); + + IupSetGlobal("XSERVERVENDOR", ServerVendor(iupmot_display)); + IupSetfAttribute(NULL, "XVENDORRELEASE", "%d", VendorRelease(iupmot_display)); + } + + iupmotColorInit(); + + /* dialog background color */ + { + iupmotSetGlobalColorAttrib(iupmot_appshell, XmNbackground, "DLGBGCOLOR"); + iupGlobalSetDefaultColorAttrib("DLGFGCOLOR", 0, 0, 0); + IupSetGlobal("_IUP_RESET_DLGBGCOLOR", "YES"); /* will update the DLGFGCOLOR when the first dialog is mapped */ + + iupGlobalSetDefaultColorAttrib("TXTBGCOLOR", 255, 255, 255); + iupGlobalSetDefaultColorAttrib("TXTFGCOLOR", 0, 0, 0); + IupSetGlobal("_IUP_RESET_TXTCOLORS", "YES"); /* will update the TXTCOLORS when the first text or list is mapped */ + } + + if (getenv("IUP_DEBUG")) + XSynchronize(iupmot_display, 1); + + return IUP_NOERROR; +} + +void iupdrvClose(void) +{ + iupmotColorFinish(); + iupmotTipsFinish(); + + if (iupmot_appshell) + XtDestroyWidget(iupmot_appshell); + + if (iupmot_appcontext) + XtDestroyApplicationContext(iupmot_appcontext); +} diff --git a/iup/src/mot/iupmot_progressbar.c b/iup/src/mot/iupmot_progressbar.c new file mode 100755 index 0000000..7266d38 --- /dev/null +++ b/iup/src/mot/iupmot_progressbar.c @@ -0,0 +1,165 @@ +/** \file +* \brief Progress bar Control +* +* See Copyright Notice in "iup.h" +*/ + +#include <Xm/Xm.h> +#include <Xm/Scale.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_progressbar.h" +#include "iup_drv.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +static int motProgressBarSetValueAttrib(Ihandle* ih, const char* value) +{ + if (!value) + ih->data->value = 0; + else + ih->data->value = atof(value); + iProgressBarCropValue(ih); + + XtVaSetValues(ih->handle, XmNvalue, (int)(SHRT_MAX * (ih->data->value - ih->data->vmin) / (ih->data->vmax - ih->data->vmin)), NULL); + + return 0; +} + +static int motProgressBarSetBgColorAttrib(Ihandle* ih, const char* value) +{ + if (!iupAttribGetStr(ih, "FGCOLOR")) + { + Pixel color; + unsigned char r, g, b; + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + r = (r*8)/10; + g = (g*8)/10; + b = (b*8)/10; + + color = iupmotColorGetPixel(r, g, b); + if (color != (Pixel)-1) + { + Widget w = XtNameToWidget(ih->handle, "*Scrollbar"); + XtVaSetValues(w, XmNtroughColor, color, NULL); + } + } + + return iupdrvBaseSetBgColorAttrib(ih, value); +} + + +static int motProgressBarSetFgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + Widget w = XtNameToWidget(ih->handle, "*Scrollbar"); + XtVaSetValues(w, XmNtroughColor, color, NULL); + } + + return 1; +} + +static void motProgressBarLayoutUpdateMethod(Ihandle *ih) +{ + unsigned char orientation; + XtVaGetValues(ih->handle, XmNorientation, &orientation, NULL); + + if (orientation == XmVERTICAL) + XtVaSetValues(ih->handle, XmNscaleWidth, ih->currentwidth, NULL); + else + XtVaSetValues(ih->handle, XmNscaleHeight, ih->currentheight, NULL); + + iupdrvBaseLayoutUpdateMethod(ih); +} + +static int motProgressBarMapMethod(Ihandle* ih) +{ + int num_args = 0; + Arg args[30]; + + /* Core */ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Primitive */ + iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupmotSetArg(args, num_args, XmNhighlightThickness, 0); + /* Scale */ + iupmotSetArg(args, num_args, XmNminimum, 0); + iupmotSetArg(args, num_args, XmNmaximum, SHRT_MAX); + iupmotSetArg(args, num_args, XmNslidingMode, XmTHERMOMETER); /* thermometer effect */ + iupmotSetArg(args, num_args, XmNsliderMark, XmNONE); + iupmotSetArg(args, num_args, XmNeditable, False); + iupmotSetArg(args, num_args, XmNshowValue, XmNONE); + + if (iupStrEqualNoCase(iupAttribGetStr(ih, "ORIENTATION"), "VERTICAL")) + { + iupmotSetArg(args, num_args, XmNorientation, XmVERTICAL); + + if (ih->currentheight < ih->currentwidth) + { + int tmp = ih->currentheight; + ih->currentheight = ih->currentwidth; + ih->currentwidth = tmp; + } + } + else + iupmotSetArg(args, num_args, XmNorientation, XmHORIZONTAL); + + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + xmScaleWidgetClass, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + return IUP_NOERROR; +} + +void iupdrvProgressBarInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motProgressBarMapMethod; + ic->LayoutUpdate = motProgressBarLayoutUpdateMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motProgressBarSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, motProgressBarSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + + /* IupProgressBar only */ + iupClassRegisterAttribute(ic, "VALUE", iProgressBarGetValueAttrib, motProgressBarSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ORIENTATION", NULL, NULL, "HORIZONTAL", NULL, IUPAF_NO_INHERIT); +} diff --git a/iup/src/mot/iupmot_tabs.c b/iup/src/mot/iupmot_tabs.c new file mode 100755 index 0000000..7c8a6b5 --- /dev/null +++ b/iup/src/mot/iupmot_tabs.c @@ -0,0 +1,593 @@ +/** \file +* \brief Tabs Control +* +* See Copyright Notice in "iup.h" +*/ + +#include <Xm/Xm.h> +#include <Xm/Notebook.h> +#include <Xm/BulletinB.h> +#include <Xm/PushB.h> +#include <Xm/Label.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_dialog.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_tabs.h" +#include "iup_image.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +int iupdrvTabsExtraDecor(Ihandle* ih) +{ + (void)ih; + return 1; +} + +int iupdrvTabsGetLineCountAttrib(Ihandle* ih) +{ + (void)ih; + return 1; +} + +void iupdrvTabsSetCurrentTab(Ihandle* ih, int pos) +{ + Ihandle* child = IupGetChild(ih, pos); + Ihandle* prev_child = IupGetChild(ih, iupdrvTabsGetCurrentTab(ih)); + IupSetAttribute(child, "VISIBLE", "YES"); + IupSetAttribute(prev_child, "VISIBLE", "NO"); + + XtVaSetValues(ih->handle, XmNcurrentPageNumber, pos, NULL); +} + +int iupdrvTabsGetCurrentTab(Ihandle* ih) +{ + int pos; + XtVaGetValues(ih->handle, XmNcurrentPageNumber, &pos, NULL); + return pos; +} + +static void motTabsUpdatePageNumber(Ihandle* ih) +{ + int pos, old_pos; + Ihandle* child; + for (pos = 0, child = ih->firstchild; child; child = child->brother, pos++) + { + Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER"); + if (child_manager) + { + old_pos = iupAttribGetInt(child, "_IUPMOT_TABNUMBER"); /* did not work when using XtVaGetValues(child_manager, XmNpageNumber) */ + if (pos != old_pos) + { + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + XtVaSetValues(child_manager, XmNpageNumber, pos, NULL); + XtVaSetValues(tab_button, XmNpageNumber, pos, NULL); + iupAttribSetInt(child, "_IUPMOT_TABNUMBER", pos); + } + } + } +} + +static void motTabsUpdatePageBgPixmap(Ihandle* ih, Pixmap pixmap) +{ + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + { + Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER"); + if (child_manager) + XtVaSetValues(child_manager, XmNbackgroundPixmap, pixmap, NULL); + } +} + +static void motTabsUpdatePageBgColor(Ihandle* ih, Pixel color) +{ + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + { + Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER"); + if (child_manager) + iupmotSetBgColor(child_manager, color); + } +} + +static void motTabsUpdateButtonsFgColor(Ihandle* ih, Pixel color) +{ + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + { + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + if (tab_button) + XtVaSetValues(tab_button, XmNforeground, color, NULL); + } +} + +static void motTabsUpdateButtonsBgColor(Ihandle* ih, Pixel color) +{ + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + { + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + if (tab_button) + iupmotSetBgColor(tab_button, color); + } +} + +static void motTabsUpdateButtonsPadding(Ihandle* ih) +{ + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + { + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + if (tab_button) + XtVaSetValues(tab_button, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); + } +} + +static void motTabsUpdatePageFont(Ihandle* ih) +{ + Ihandle* child; + XmFontList fontlist = (XmFontList)iupmotGetFontListAttrib(ih); + + for (child = ih->firstchild; child; child = child->brother) + { + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + if (tab_button) + XtVaSetValues(tab_button, XmNrenderTable, fontlist, NULL); + } +} + +/* ------------------------------------------------------------------------- */ +/* motTabs - Sets and Gets accessors */ +/* ------------------------------------------------------------------------- */ + +static int motTabsSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + + if (ih->handle) + motTabsUpdateButtonsPadding(ih); + return 0; +} + +static void motTabsUpdateTabType(Ihandle* ih) +{ + if (ih->data->type == ITABS_LEFT) + XtVaSetValues(ih->handle, XmNbackPagePlacement, XmBOTTOM_LEFT, + XmNorientation, XmHORIZONTAL, + NULL); + else if(ih->data->type == ITABS_RIGHT) + XtVaSetValues(ih->handle, XmNbackPagePlacement, XmBOTTOM_RIGHT, + XmNorientation, XmHORIZONTAL, + NULL); + else if(ih->data->type == ITABS_BOTTOM) + XtVaSetValues(ih->handle, XmNbackPagePlacement, XmBOTTOM_RIGHT, + XmNorientation, XmVERTICAL, + NULL); + else /* "TOP" */ + XtVaSetValues(ih->handle, XmNbackPagePlacement, XmTOP_RIGHT, + XmNorientation, XmVERTICAL, + NULL); +} + +static int motTabsSetTabTypeAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "LEFT")) + ih->data->type = ITABS_LEFT; + else if(iupStrEqualNoCase(value, "RIGHT")) + ih->data->type = ITABS_RIGHT; + else if(iupStrEqualNoCase(value, "BOTTOM")) + ih->data->type = ITABS_BOTTOM; + else /* "TOP" */ + ih->data->type = ITABS_TOP; + + if (ih->handle) + motTabsUpdateTabType(ih); + + return 0; +} + +static int motTabsSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color; + + /* given value is used only for child, to the Tabs must use only from parent */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + color = iupmotColorGetPixelStr(parent_value); + if (color != (Pixel)-1) + { + iupmotSetBgColor(ih->handle, color); + motTabsUpdatePageBgColor(ih, color); + } + + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + motTabsUpdateButtonsBgColor(ih, color); + + return 1; +} + +static int motTabsSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + /* given value is used only for child, to the Tabs must use only from parent */ + char* parent_value = iupAttribGetInheritNativeParent(ih, "BACKGROUND"); + + Pixel color = iupmotColorGetPixelStr(parent_value); + if (color != (Pixel)-1) + { + iupmotSetBgColor(ih->handle, color); + motTabsUpdatePageBgColor(ih, color); + } + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(parent_value, ih, 0); + if (pixmap) + { + XtVaSetValues(ih->handle, XmNbackgroundPixmap, pixmap, NULL); + motTabsUpdatePageBgPixmap(ih, pixmap); + } + } + + (void)value; + return 1; +} + +static int motTabsSetFgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + XtVaSetValues(ih->handle, XmNforeground, color, NULL); + motTabsUpdateButtonsFgColor(ih, color); + return 1; + } + return 0; +} + +static int motTabsSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + iupdrvSetStandardFontAttrib(ih, value); + if (ih->handle) + motTabsUpdatePageFont(ih); + return 1; +} + +static int motTabsSetTabTitleAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int pos; + if (value && iupStrToInt(name_id, &pos)==1) + { + Ihandle* child = IupGetChild(ih, pos); + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + if (tab_button) + iupmotSetString(tab_button, XmNlabelString, value); + } + return 1; +} + +static int motTabsSetTabImageAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int pos; + if (value && iupStrToInt(name_id, &pos)==1) + { + Ihandle* child = IupGetChild(ih, pos); + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + if (tab_button) + { + Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + if (pixmap) + XtVaSetValues(tab_button, XmNlabelPixmap, pixmap, NULL); + } + } + return 1; +} + + +/* ------------------------------------------------------------------------- */ +/* motTabs - Callback */ +/* ------------------------------------------------------------------------- */ + +void motTabsPageChangedCallback(Widget w, Ihandle* ih, XmNotebookCallbackStruct *nptr) +{ + if (nptr->reason == XmCR_MAJOR_TAB) + { + IFnnn cb; + Ihandle* child = IupGetChild(ih, nptr->page_number); + Ihandle* prev_child = IupGetChild(ih, nptr->prev_page_number); + IupSetAttribute(child, "VISIBLE", "YES"); + IupSetAttribute(prev_child, "VISIBLE", "NO"); + + cb = (IFnnn)IupGetCallback(ih, "TABCHANGE_CB"); + if (cb) + cb(ih, child, prev_child); + } + (void)w; +} + +static void motTabsConfigureNotify(Widget w, XEvent *evt, String* s, Cardinal *card) +{ + /* Motif does not process the changed of position and/or size of children outside the parent's client area. + Since Notebook pages are not resized until they are moved into the visible area, + we must update the children position and size when a tab page is resize. + Since tab pages are not hidden, they are moved outside the visible area, + a resize occours every time a tab is activated. + */ + Ihandle *child; + (void)s; + (void)card; + (void)evt; + + XtVaGetValues(w, XmNuserData, &child, NULL); + if (!child) return; + + iupLayoutUpdate(child); +} + +/* ------------------------------------------------------------------------- */ +/* motTabs - Methods and Init Class */ +/* ------------------------------------------------------------------------- */ + +static void motTabsChildAddedMethod(Ihandle* ih, Ihandle* child) +{ + if (IupGetName(child) == NULL) + iupAttribSetHandleName(child); + + if (ih->handle) + { + Widget child_manager; + Widget tab_button; + int num_args = 0, pos; + Arg args[30]; + char *tabtitle, *tabimage, *background; + Pixel color; + + /* open space for new tab number */ + motTabsUpdatePageNumber(ih); + + pos = IupGetChildPos(ih, child); + + /* Create pages */ + child_manager = XtVaCreateManagedWidget( + "child_manager", + xmBulletinBoardWidgetClass, + ih->handle, + /* Core */ + XmNborderWidth, 0, + /* Manager */ + XmNshadowThickness, 0, + XmNnavigationType, XmTAB_GROUP, + XmNuserData, child, /* used only in motTabsConfigureNotify */ + /* BulletinBoard */ + XmNmarginWidth, 0, + XmNmarginHeight, 0, + XmNresizePolicy, XmRESIZE_NONE, /* no automatic resize of children */ + /* Notebook Constraint */ + XmNnotebookChildType, XmPAGE, + XmNpageNumber, pos, + XmNresizable, True, + NULL); + + XtOverrideTranslations(child_manager, XtParseTranslationTable("<Configure>: iupTabsConfigure()")); + + tabtitle = iupAttribGet(child, "TABTITLE"); + if (!tabtitle) tabtitle = iupTabsAttribGetStrId(ih, "TABTITLE", pos); + tabimage = iupAttribGet(child, "TABIMAGE"); + if (!tabimage) tabimage = iupTabsAttribGetStrId(ih, "TABIMAGE", pos); + if (!tabtitle && !tabimage) + tabtitle = " "; + + /* Create tabs */ + /* Label */ + iupmotSetArg(args, num_args, XmNlabelType, tabtitle? XmSTRING: XmPIXMAP); + iupmotSetArg(args, num_args, XmNmarginHeight, 0); + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + /* Notebook Constraint */ + iupmotSetArg(args, num_args, XmNnotebookChildType, XmMAJOR_TAB); + iupmotSetArg(args, num_args, XmNpageNumber, pos); + tab_button = XtCreateManagedWidget("tab_button", xmPushButtonWidgetClass, ih->handle, args, num_args); + + /* Disable Drag Source */ + iupmotDisableDragSource(tab_button); + + XtAddEventHandler(tab_button, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(tab_button, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(tab_button, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(tab_button, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + + if (tabtitle) + iupmotSetString(tab_button, XmNlabelString, tabtitle); + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(tabimage, ih, 0); + if (pixmap) + XtVaSetValues(tab_button, XmNlabelPixmap, pixmap, NULL); + } + + background = iupBaseNativeParentGetBgColorAttrib(ih); + color = iupmotColorGetPixelStr(background); + if (color != -1) + iupmotSetBgColor(child_manager, color); + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(background, ih, 0); + if (pixmap) + { + XtVaSetValues(child_manager, XmNbackgroundPixmap, pixmap, NULL); + } + } + + background = iupAttribGetStr(ih, "BGCOLOR"); + color = iupmotColorGetPixelStr(background); + if (color != -1) + iupmotSetBgColor(tab_button, color); + + color = iupmotColorGetPixelStr(IupGetAttribute(ih, "FGCOLOR")); + XtVaSetValues(tab_button, XmNforeground, color, NULL); + + XtRealizeWidget(child_manager); + XtRealizeWidget(tab_button); + + iupAttribSetStr(child, "_IUPTAB_CONTAINER", (char*)child_manager); + iupAttribSetStr(child, "_IUPMOT_TABBUTTON", (char*)tab_button); + iupAttribSetInt(child, "_IUPMOT_TABNUMBER", pos); + + if (pos == iupdrvTabsGetCurrentTab(ih)) + IupSetAttribute(child, "VISIBLE", "YES"); + else + IupSetAttribute(child, "VISIBLE", "NO"); + } +} + +static void motTabsChildRemovedMethod(Ihandle* ih, Ihandle* child) +{ + if (ih->handle) + { + Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER"); + if (child_manager) + { + int cur_pos, pos; + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + + cur_pos = iupdrvTabsGetCurrentTab(ih); + pos = iupAttribGetInt(child, "_IUPMOT_TABNUMBER"); /* did not work when using XtVaGetValues(child_manager, XmNpageNumber) */ + if (cur_pos == pos) + { + if (cur_pos == 0) + cur_pos = 1; + else + cur_pos--; + + iupdrvTabsSetCurrentTab(ih, cur_pos); + } + + XtDestroyWidget(tab_button); + XtDestroyWidget(child_manager); + + /* compact the tab number usage */ + motTabsUpdatePageNumber(ih); + + iupAttribSetStr(child, "_IUPTAB_CONTAINER", NULL); + iupAttribSetStr(child, "_IUPMOT_TABBUTTON", NULL); + iupAttribSetStr(child, "_IUPMOT_TABNUMBER", NULL); + } + } +} + +static int motTabsMapMethod(Ihandle* ih) +{ + int num_args = 0; + Arg args[30]; + + if (!ih->parent) + return IUP_ERROR; + + /* Core */ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Manager */ + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupmotSetArg(args, num_args, XmNhighlightThickness, 0); + /* Notebook */ + iupmotSetArg(args, num_args, XmNbindingType, XmNONE); + iupmotSetArg(args, num_args, XmNbindingWidth, 0); + iupmotSetArg(args, num_args, XmNfirstPageNumber, 0); /* IupTabs index always starts with zero */ + iupmotSetArg(args, num_args, XmNbackPageSize, 0); + iupmotSetArg(args, num_args, XmNbackPageNumber, 1); + iupmotSetArg(args, num_args, XmNframeShadowThickness, 2); + + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + xmNotebookWidgetClass, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + /* Disable page scroller */ + { + Widget scroller; + scroller = XtNameToWidget(ih->handle, "*PageScroller"); + XtUnmanageChild(scroller); + } + + /* Callbacks */ + XtAddCallback(ih->handle, XmNpageChangedCallback, (XtCallbackProc)motTabsPageChangedCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + + /* update Tab position */ + motTabsUpdateTabType(ih); + + /* current value is now given by the native system */ + iupAttribSetStr(ih, "_IUPTABS_VALUE_HANDLE", NULL); + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + /* Create pages and tabs */ + if (ih->firstchild) + { + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + motTabsChildAddedMethod(ih, child); + } + + return IUP_NOERROR; +} + +void iupdrvTabsInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motTabsMapMethod; + ic->ChildAdded = motTabsChildAddedMethod; + ic->ChildRemoved = motTabsChildRemovedMethod; + + { + /* Set up a translation table that captures "Resize" events + (also called ConfigureNotify or Configure events). */ + XtActionsRec rec = {"iupTabsConfigure", motTabsConfigureNotify}; + XtAppAddActions(iupmot_appcontext, &rec, 1); + } + + /* Driver Dependent Attribute functions */ + + /* Common */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, motTabsSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motTabsSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, motTabsSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motTabsSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* IupTabs only */ + iupClassRegisterAttribute(ic, "TABTYPE", iupTabsGetTabTypeAttrib, motTabsSetTabTypeAttrib, IUPAF_SAMEASSYSTEM, "TOP", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TABORIENTATION", iupTabsGetTabOrientationAttrib, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); /* can not be set, always HORIZONTAL in Motif */ + iupClassRegisterAttributeId(ic, "TABTITLE", NULL, motTabsSetTabTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TABIMAGE", NULL, motTabsSetTabImageAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, motTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); +} diff --git a/iup/src/mot/iupmot_text.c b/iup/src/mot/iupmot_text.c new file mode 100755 index 0000000..4a8f936 --- /dev/null +++ b/iup/src/mot/iupmot_text.c @@ -0,0 +1,1165 @@ +/** \file + * \brief Text Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/TextF.h> +#include <Xm/Text.h> +#include <Xm/ScrolledW.h> +#include <Xm/SpinB.h> +#include <X11/keysym.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_mask.h" +#include "iup_drv.h" +#include "iup_array.h" +#include "iup_text.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +#ifndef XmIsSpinBox +#define XmIsSpinBox(w) XtIsSubclass(w, xmSpinBoxWidgetClass) +#endif + +#ifndef XmNwrap +#define XmNwrap "Nwrap" +#endif + +void iupdrvTextAddFormatTag(Ihandle* ih, Ihandle* formattag) +{ + (void)ih; + (void)formattag; +} + +void iupdrvTextAddSpin(int *w, int h) +{ + *w += h/2; +} + +void iupdrvTextAddBorders(int *w, int *h) +{ + int border_size = 2*5; + (*w) += border_size; + (*h) += border_size; +} + +static void motTextGetLinColFromPosition(const char *str, int pos, int *lin, int *col ) +{ + int i; + + *lin = 0; + *col = 0; + + for (i=0; i<pos; i++) + { + if (*str == '\n') + { + (*lin)++; + *col = 0; + } + else + (*col)++; + + str++; + } + + (*lin)++; /* IUP starts at 1 */ + (*col)++; +} + +static int motTextSetLinColToPosition(const char *str, int lin, int col) +{ + int pos=0, cur_lin=0, cur_col=0; + + lin--; /* IUP starts at 1 */ + col--; + + while (*str) + { + if (lin<=cur_lin && col<=cur_col) + break; + + if (*str == '\n') + { + cur_lin++; + cur_col = 0; + } + else + cur_col++; + + str++; + pos++; + } + + return pos; +} + +void iupdrvTextConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos) +{ + char* str = XmTextGetString(ih->handle); + *pos = motTextSetLinColToPosition(str, lin, col); + XtFree(str); +} + +void iupdrvTextConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col) +{ + char *str = XmTextGetString(ih->handle); + motTextGetLinColFromPosition(str, pos, lin, col); + XtFree(str); +} + +static int motTextConvertXYToPos(Ihandle* ih, int x, int y) +{ + return XmTextXYToPos(ih->handle, x, y); +} + + +/*******************************************************************************************/ + + +static int motTextSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle) + { + XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); + } + return 0; +} + +static int motTextSetReadOnlyAttrib(Ihandle* ih, const char* value) +{ + XtVaSetValues(ih->handle, XmNeditable, iupStrBoolean(value)? False: True, NULL); + return 0; +} + +static char* motTextGetReadOnlyAttrib(Ihandle* ih) +{ + Boolean editable; + XtVaGetValues(ih->handle, XmNeditable, &editable, NULL); + if (editable) + return "YES"; + else + return "NO"; +} + +static int motTextSetInsertAttrib(Ihandle* ih, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + if (!value) + return 0; + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XmTextRemove(ih->handle); + XmTextInsert(ih->handle, XmTextGetInsertionPosition(ih->handle), (char*)value); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + + return 0; +} + +static int motTextSetSelectedTextAttrib(Ihandle* ih, const char* value) +{ + XmTextPosition start, end; + + if (!value) + return 0; + + if (XmTextGetSelectionPosition(ih->handle, &start, &end) && start!=end) + { + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XmTextReplace(ih->handle, start, end, (char*)value); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + + return 0; +} + +static char* motTextGetSelectedTextAttrib(Ihandle* ih) +{ + char* selectedtext = XmTextGetSelection(ih->handle); + char* str = iupStrGetMemoryCopy(selectedtext); + XtFree(selectedtext); + return str; +} + +static int motTextSetAppendAttrib(Ihandle* ih, const char* value) +{ + XmTextPosition pos; + if (!ih->handle) /* do not store the action before map */ + return 0; + pos = XmTextGetLastPosition(ih->handle); + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + if (ih->data->is_multiline && ih->data->append_newline) + XmTextInsert(ih->handle, pos, "\n"); + if (value) + XmTextInsert(ih->handle, pos+1, (char*)value); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + return 0; +} + +static int motTextSetSelectionAttrib(Ihandle* ih, const char* value) +{ + int start=1, end=1; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + XmTextClearSelection(ih->handle, CurrentTime); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + XmTextSetSelection(ih->handle, (XmTextPosition)0, (XmTextPosition)XmTextGetLastPosition(ih->handle), CurrentTime); + return 0; + } + + if (ih->data->is_multiline) + { + int lin_start=1, col_start=1, lin_end=1, col_end=1; + char *str; + + if (sscanf(value, "%d,%d:%d,%d", &lin_start, &col_start, &lin_end, &col_end)!=4) return 0; + if (lin_start<1 || col_start<1 || lin_end<1 || col_end<1) return 0; + + str = XmTextGetString(ih->handle); + start = motTextSetLinColToPosition(str, lin_start, col_start); + end = motTextSetLinColToPosition(str, lin_end, col_end); + XtFree(str); + } + else + { + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<1 || end<1) + return 0; + + start--; /* IUP starts at 1 */ + end--; + } + + /* end is inside the selection, in IUP is outside */ + end--; + + XmTextSetSelection(ih->handle, (XmTextPosition)start, (XmTextPosition)end, CurrentTime); + + return 0; +} + +static char* motTextGetSelectionAttrib(Ihandle* ih) +{ + XmTextPosition start = 0, end = 0; + char* str; + + if (!XmTextGetSelectionPosition(ih->handle, &start, &end) || start==end) + return NULL; + + str = iupStrGetMemory(100); + + /* end is inside the selection, in IUP is outside */ + end++; + + if (ih->data->is_multiline) + { + int start_col, start_lin, end_col, end_lin; + + char *value = XmTextGetString(ih->handle); + motTextGetLinColFromPosition(value, start, &start_lin, &start_col); + motTextGetLinColFromPosition(value, end, &end_lin, &end_col); + XtFree(value); + + sprintf(str,"%d,%d:%d,%d", start_lin, start_col, end_lin, end_col); + } + else + { + start++; /* IUP starts at 1 */ + end++; + sprintf(str, "%d:%d", (int)start, (int)end); + } + + return str; +} + +static int motTextSetSelectionPosAttrib(Ihandle* ih, const char* value) +{ + int start=0, end=0; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + XmTextClearSelection(ih->handle, CurrentTime); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + XmTextSetSelection(ih->handle, (XmTextPosition)0, (XmTextPosition)XmTextGetLastPosition(ih->handle), CurrentTime); + return 0; + } + + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<0 || end<0) + return 0; + + /* end is inside the selection, in IUP is outside */ + end--; + + XmTextSetSelection(ih->handle, (XmTextPosition)start, (XmTextPosition)end, CurrentTime); + + return 0; +} + +static char* motTextGetSelectionPosAttrib(Ihandle* ih) +{ + XmTextPosition start = 0, end = 0; + char* str; + + if (!XmTextGetSelectionPosition(ih->handle, &start, &end) || start==end) + return NULL; + + str = iupStrGetMemory(100); + + /* end is inside the selection, in IUP is outside */ + end++; + + sprintf(str, "%d:%d", (int)start, (int)end); + + return str; +} + +static int motTextSetCaretAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + + if (!value) + return 0; + + if (ih->data->is_multiline) + { + int lin = 1, col = 1; + char *str; + + iupStrToIntInt(value, &lin, &col, ','); + + str = XmTextGetString(ih->handle); + pos = motTextSetLinColToPosition(str, lin, col); + XtFree(str); + } + else + { + sscanf(value,"%i",&pos); + pos--; /* IUP starts at 1 */ + } + + XmTextSetInsertionPosition(ih->handle, (XmTextPosition)pos); + XmTextShowPosition(ih->handle, (XmTextPosition)pos); + + return 0; +} + +static char* motTextGetCaretAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(50); + + XmTextPosition pos = XmTextGetInsertionPosition(ih->handle); + + if (ih->data->is_multiline) + { + int col, lin; + + char *value = XmTextGetString(ih->handle); + motTextGetLinColFromPosition(value, pos, &lin, &col); + XtFree(value); + + sprintf(str, "%d,%d", lin, col); + } + else + { + pos++; /* IUP starts at 1 */ + sprintf(str, "%d", (int)pos); + } + + return str; +} + +static int motTextSetCaretPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + XmTextSetInsertionPosition(ih->handle, (XmTextPosition)pos); + XmTextShowPosition(ih->handle, (XmTextPosition)pos); + + return 0; +} + +static char* motTextGetCaretPosAttrib(Ihandle* ih) +{ + XmTextPosition pos = XmTextGetInsertionPosition(ih->handle); + char* str = iupStrGetMemory(50); + sprintf(str, "%d", (int)pos); + return str; +} + +static int motTextSetScrollToAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + + if (!value) + return 0; + + if (ih->data->is_multiline) + { + int lin = 1, col = 1, pos; + char* str; + + iupStrToIntInt(value, &lin, &col, ','); + if (lin < 1) lin = 1; + if (col < 1) col = 1; + + str = XmTextGetString(ih->handle); + pos = motTextSetLinColToPosition(str, lin, col); + XtFree(str); + } + else + { + sscanf(value,"%i",&pos); + if (pos < 1) pos = 1; + pos--; /* return to Motif referece */ + } + + XmTextShowPosition(ih->handle, (XmTextPosition)pos); + + return 0; +} + +static int motTextSetScrollToPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + XmTextShowPosition(ih->handle, (XmTextPosition)pos); + + return 0; +} + +static int motTextSetNCAttrib(Ihandle* ih, const char* value) +{ + if (!iupStrToInt(value, &ih->data->nc)) + ih->data->nc = INT_MAX; + if (ih->handle) + XtVaSetValues(ih->handle, XmNmaxLength, ih->data->nc, NULL); + return 0; +} + +static int motTextSetClipboardAttrib(Ihandle *ih, const char *value) +{ + if (iupStrEqualNoCase(value, "COPY")) + { + char *str = XmTextGetSelection(ih->handle); + if (!str) return 0; + + XmTextCopy(ih->handle, CurrentTime); + + /* do it also for the X clipboard */ + XStoreBytes(iupmot_display, str, strlen(str)+1); + XtFree(str); + } + else if (iupStrEqualNoCase(value, "CUT")) + { + char *str = XmTextGetSelection(ih->handle); + if (!str) return 0; + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + + XmTextCut(ih->handle, CurrentTime); + + /* do it also for the X clipboard */ + XStoreBytes(iupmot_display, str, strlen(str)+1); + XtFree(str); + XmTextRemove(ih->handle); + + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + else if (iupStrEqualNoCase(value, "PASTE")) + { + int size; + char* str = XFetchBytes(iupmot_display, &size); + if (!str) return 0; + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + + XmTextPaste(ih->handle); /* TODO: this could force 2 pastes, check in CDE */ + + /* do it also for the X clipboard */ + XmTextRemove(ih->handle); + XmTextInsert(ih->handle, XmTextGetInsertionPosition(ih->handle), str); + XFree(str); + + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + else if (iupStrEqualNoCase(value, "CLEAR")) + { + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XmTextRemove(ih->handle); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + return 0; +} + +static int motTextSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (sb_win) + { + Pixel color; + + /* ignore given value for the scrollbars, must use only from parent */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + color = iupmotColorGetPixelStr(parent_value); + if (color != (Pixel)-1) + { + Widget sb = NULL; + + iupmotSetBgColor(sb_win, color); + + XtVaGetValues(sb_win, XmNverticalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + + XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + } + } + + return iupdrvBaseSetBgColorAttrib(ih, value); /* use given value for contents */ +} + +static int motTextSetSpinMinAttrib(Ihandle* ih, const char* value) +{ + Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox)) + { + int min; + if (iupStrToInt(value, &min)) + { + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XtVaSetValues(ih->handle, XmNminimumValue, min, NULL); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + } + return 1; +} + +static int motTextSetSpinMaxAttrib(Ihandle* ih, const char* value) +{ + Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox)) + { + int max; + if (iupStrToInt(value, &max)) + { + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XtVaSetValues(ih->handle, XmNmaximumValue, max, NULL); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + } + return 1; +} + +static int motTextSetSpinIncAttrib(Ihandle* ih, const char* value) +{ + Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox)) + { + int inc; + if (iupStrToInt(value, &inc)) + { + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XtVaSetValues(ih->handle, XmNincrementValue, inc, NULL); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + } + return 1; +} + +static int motTextSetSpinValueAttrib(Ihandle* ih, const char* value) +{ + Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox)) + { + int pos; + if (iupStrToInt(value, &pos)) + { + char* value = NULL; + int min, max; + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XtVaGetValues(ih->handle, XmNminimumValue, &min, + XmNmaximumValue, &max, NULL); + if (pos < min) pos = min; + if (pos > max) pos = max; + if (iupAttribGet(ih, "_IUPMOT_SPIN_NOAUTO")) + value = XmTextGetString(ih->handle); + + XtVaSetValues(ih->handle, XmNposition, pos, NULL); + + if (value) + { + XmTextSetString(ih->handle, (char*)value); + XtFree(value); + } + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + return 1; + } + } + return 0; +} + +static char* motTextGetSpinValueAttrib(Ihandle* ih) +{ + Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox)) + { + int pos; + char *str = iupStrGetMemory(50); + XtVaGetValues(ih->handle, XmNposition, &pos, NULL); + sprintf(str, "%d", pos); + return str; + } + return NULL; +} + +static int motTextSetValueAttrib(Ihandle* ih, const char* value) +{ + if (!value) value = ""; + motTextSetSpinValueAttrib(ih, value); + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XmTextSetString(ih->handle, (char*)value); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + return 0; +} + +static char* motTextGetValueAttrib(Ihandle* ih) +{ + char* value = XmTextGetString(ih->handle); + char* str = iupStrGetMemoryCopy(value); + XtFree(value); + return str; +} + + +/******************************************************************************/ + + +static void motTextSpinModifyVerifyCallback(Widget w, Ihandle* ih, XmSpinBoxCallbackStruct *cbs) +{ + IFni cb = (IFni) IupGetCallback(ih, "SPIN_CB"); + if (cb) + { + int ret = cb(ih, cbs->position); + if (ret == IUP_IGNORE) + { + cbs->doit = 1; + return; + } + } + (void)w; + + iupAttribSetStr(ih, "_IUPMOT_SPIN_DISABLE_TEXT_CB", "1"); +} + +static void motTextModifyVerifyCallback(Widget w, Ihandle *ih, XmTextVerifyPtr text) +{ + int start, end, key = 0; + char *value, *new_value, *insert_value; + KeySym motcode = 0; + IFnis cb; + + if (iupAttribGet(ih, "_IUPMOT_DISABLE_TEXT_CB")) + return; + + if (iupAttribGet(ih, "_IUPMOT_SPIN_DISABLE_TEXT_CB")) + { + if (iupAttribGet(ih, "_IUPMOT_SPIN_NOAUTO")) + text->doit = False; + + iupAttribSetStr(ih, "_IUPMOT_SPIN_DISABLE_TEXT_CB", NULL); + return; + } + + cb = (IFnis)IupGetCallback(ih, "ACTION"); + if (!cb && !ih->data->mask) + return; + + if (text->event && text->event->type == KeyPress) + { + unsigned int state = ((XKeyEvent*)text->event)->state; + if (state & ControlMask || /* Ctrl */ + state & Mod1Mask || + state & Mod5Mask || /* Alt */ + state & Mod4Mask) /* Apple/Win */ + return; + + motcode = XKeycodeToKeysym(iupmot_display, ((XKeyEvent*)text->event)->keycode, 0); + } + + value = XmTextGetString(ih->handle); + start = text->startPos; + end = text->endPos; + insert_value = text->text->ptr; + + if (motcode == XK_Delete) + { + new_value = value; + iupStrRemove(value, start, end, 1); + } + else if (motcode == XK_BackSpace) + { + new_value = value; + iupStrRemove(value, start, end, -1); + } + else + { + if (!value) + new_value = iupStrDup(insert_value); + else if (insert_value) + new_value = iupStrInsert(value, insert_value, start, end); + else + new_value = value; + } + + if (insert_value && insert_value[0]!=0 && insert_value[1]==0) + key = insert_value[0]; + + if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0) + { + if (new_value != value) free(new_value); + XtFree(value); + text->doit = False; /* abort processing */ + return; + } + + if (cb) + { + int cb_ret = cb(ih, key, (char*)new_value); + if (cb_ret==IUP_IGNORE) + text->doit = False; /* abort processing */ + else if (cb_ret==IUP_CLOSE) + { + IupExitLoop(); + text->doit = False; /* abort processing */ + } + else if (cb_ret!=0 && key!=0 && + cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE) + { + insert_value[0] = (char)cb_ret; /* replace key */ + } + } + + if (text->doit) + { + /* Spin is not automatically updated when you directly edit the text */ + Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox) && !iupAttribGet(ih, "_IUPMOT_SPIN_NOAUTO")) + { + int pos; + if (iupStrToInt(new_value, &pos)) + { + XmTextPosition caret_pos = text->currInsert; + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XtVaSetValues(ih->handle, XmNposition, pos, NULL); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + /* do not handle all situations, but handle the basic ones */ + if (text->startPos == text->endPos) /* insert */ + caret_pos++; + else if (text->startPos < text->endPos && text->startPos < text->currInsert) /* backspace */ + caret_pos--; + XmTextSetInsertionPosition(ih->handle, caret_pos); + text->doit = False; + } + } + } + + if (new_value != value) free(new_value); + XtFree(value); + (void)w; +} + +static void motTextMotionVerifyCallback(Widget w, Ihandle* ih, XmTextVerifyCallbackStruct* textverify) +{ + int col, lin, pos; + + IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB"); + if (!cb) return; + + pos = textverify->newInsert; + + if (ih->data->is_multiline) + { + char *value = XmTextGetString(ih->handle); + motTextGetLinColFromPosition(value, pos, &lin, &col); + XtFree(value); + } + else + { + col = pos; + col++; /* IUP starts at 1 */ + lin = 1; + } + + if (pos != ih->data->last_caret_pos) + { + ih->data->last_caret_pos = pos; + cb(ih, lin, col, pos); + } + + (void)w; +} + +static void motTextValueChangedCallback(Widget w, Ihandle* ih, XmAnyCallbackStruct* valuechanged) +{ + if (iupAttribGet(ih, "_IUPMOT_DISABLE_TEXT_CB")) + return; + + iupBaseCallValueChangedCb(ih); + + (void)valuechanged; + (void)w; +} + +static void motTextKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean *cont) +{ + Widget spinbox; + + *cont = True; + iupmotKeyPressEvent(w, ih, (XEvent*)evt, cont); + if (*cont == False) + return; + + if (evt->state & ControlMask) /* Ctrl */ + { + KeySym motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + if (motcode == XK_c) + motTextSetClipboardAttrib(ih, "COPY"); + else if (motcode == XK_x) + motTextSetClipboardAttrib(ih, "CUT"); + else if (motcode == XK_v) + motTextSetClipboardAttrib(ih, "PASTE"); + else if (motcode == XK_a) + XmTextSetSelection(ih->handle, 0, XmTextGetLastPosition(ih->handle), CurrentTime); + } + + spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox)) + { + KeySym motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + if (motcode == XK_Left || motcode == XK_Right) + { + /* avoid spin increment using Left/Right arrows, + but must manually handle the new cursor position */ + XmTextPosition caret_pos = XmTextGetInsertionPosition(ih->handle); + XmTextSetInsertionPosition(ih->handle, (motcode == XK_Left)? caret_pos-1: caret_pos+1); + *cont = False; + } + } +} + + +/******************************************************************************/ + + +static void motTextLayoutUpdateMethod(Ihandle* ih) +{ + Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox)) + { + XtVaSetValues(ih->handle, + XmNwidth, (XtArgVal)ih->currentwidth-ih->currentheight/2, + XmNheight, (XtArgVal)ih->currentheight, + NULL); + + XtVaSetValues(spinbox, + XmNx, (XtArgVal)ih->x, + XmNy, (XtArgVal)ih->y, + XmNwidth, (XtArgVal)ih->currentwidth, + XmNheight, (XtArgVal)ih->currentheight, + XmNarrowSize, ih->currentheight/2, + NULL); + } + else + iupdrvBaseLayoutUpdateMethod(ih); +} + +static int motTextMapMethod(Ihandle* ih) +{ + int num_args = 0; + Arg args[30]; + Widget parent = iupChildTreeGetNativeParentHandle(ih); + char* child_id = iupDialogGetChildIdStr(ih); + int spin = 0; + WidgetClass widget_class = xmTextWidgetClass; + + if (ih->data->is_multiline) + { + Widget sb_win; + int wordwrap = 0; + + if (iupAttribGetBoolean(ih, "WORDWRAP")) + { + wordwrap = 1; + ih->data->sb &= ~IUP_SB_HORIZ; /* must remove the horizontal scroolbar */ + } + + /******************************/ + /* Create the scrolled window */ + /******************************/ + + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); + iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE); + iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); /* can NOT be XmAS_NEEDED because XmAPPLICATION_DEFINED */ + iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ + iupmotSetArg(args, num_args, XmNborderWidth, 0); + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + + sb_win = XtCreateManagedWidget( + child_id, /* child identifier */ + xmScrolledWindowWidgetClass, /* widget class */ + parent, /* widget parent */ + args, num_args); + + if (!sb_win) + return IUP_ERROR; + + parent = sb_win; + child_id = "text"; + + num_args = 0; + iupmotSetArg(args, num_args, XmNeditMode, XmMULTI_LINE_EDIT); + if (wordwrap) + iupmotSetArg(args, num_args, XmNwordWrap, True); + } + else + { + widget_class = xmTextFieldWidgetClass; + + if (iupAttribGetBoolean(ih, "SPIN")) + { + Widget spinbox; + + num_args = 0; + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between spin and text */ + iupmotSetArg(args, num_args, XmNborderWidth, 0); + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupmotSetArg(args, num_args, XmNmarginHeight, 0); + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNarrowSize, 8); + + if (iupStrEqualNoCase(iupAttribGetStr(ih, "SPINALIGN"), "LEFT")) + iupmotSetArg(args, num_args, XmNarrowLayout, XmARROWS_BEGINNING); + else + iupmotSetArg(args, num_args, XmNarrowLayout, XmARROWS_END); + + spinbox = XtCreateManagedWidget( + child_id, /* child identifier */ + xmSpinBoxWidgetClass, /* widget class */ + parent, /* widget parent */ + args, num_args); + + if (!spinbox) + return IUP_ERROR; + + XtAddCallback(spinbox, XmNmodifyVerifyCallback, (XtCallbackProc)motTextSpinModifyVerifyCallback, (XtPointer)ih); + + parent = spinbox; + child_id = "text"; + spin = 1; + + if (!iupAttribGetBoolean(ih, "SPINAUTO")) + iupAttribSetStr(ih, "_IUPMOT_SPIN_NOAUTO", "1"); + } + + num_args = 0; + iupmotSetArg(args, num_args, XmNeditMode, XmSINGLE_LINE_EDIT); + + if (spin) + { + /* Spin Constraints */ + iupmotSetArg(args, num_args, XmNspinBoxChildType, XmNUMERIC); + iupmotSetArg(args, num_args, XmNminimumValue, 0); + iupmotSetArg(args, num_args, XmNmaximumValue, 100); + iupmotSetArg(args, num_args, XmNposition, 0); + + if (iupAttribGetBoolean(ih, "SPINWRAP")) + iupmotSetArg(args, num_args, XmNwrap, TRUE); + else + iupmotSetArg(args, num_args, XmNwrap, FALSE); + } + else + { + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + } + } + + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupmotSetArg(args, num_args, XmNhighlightThickness, 2); + iupmotSetArg(args, num_args, XmNverifyBell, False); + iupmotSetArg(args, num_args, XmNspacing, 0); + + if (iupAttribGetBoolean(ih, "BORDER")) + iupmotSetArg(args, num_args, XmNshadowThickness, 2); + else + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + + if (ih->data->is_multiline) + { + if (ih->data->sb & IUP_SB_HORIZ) + iupmotSetArg(args, num_args, XmNscrollHorizontal, True); + else + iupmotSetArg(args, num_args, XmNscrollHorizontal, False); + + if (ih->data->sb & IUP_SB_VERT) + iupmotSetArg(args, num_args, XmNscrollVertical, True); + else + iupmotSetArg(args, num_args, XmNscrollVertical, False); + } + + ih->handle = XtCreateManagedWidget( + child_id, /* child identifier */ + widget_class, /* widget class */ + parent, /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + if (ih->data->is_multiline) + { + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)parent); + XtVaSetValues(parent, XmNworkWindow, ih->handle, NULL); + } + else if (spin) + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)parent); + + XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)motTextKeyPressEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, PointerMotionMask, False, (XtEventHandler)iupmotPointerMotionEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)iupmotButtonPressReleaseEvent, (XtPointer)ih); + + XtAddCallback(ih->handle, XmNmodifyVerifyCallback, (XtCallbackProc)motTextModifyVerifyCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNmotionVerifyCallback, (XtCallbackProc)motTextMotionVerifyCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNvalueChangedCallback, (XtCallbackProc)motTextValueChangedCallback, (XtPointer)ih); + + /* Disable Drag Source */ + iupmotDisableDragSource(ih->handle); + + /* initialize the widget */ + if (ih->data->is_multiline || spin) + XtRealizeWidget(parent); + else + XtRealizeWidget(ih->handle); + + if (IupGetGlobal("_IUP_RESET_TXTCOLORS")) + { + iupmotSetGlobalColorAttrib(ih->handle, XmNbackground, "TXTBGCOLOR"); + iupmotSetGlobalColorAttrib(ih->handle, XmNforeground, "TXTFGCOLOR"); + IupSetGlobal("_IUP_RESET_TXTCOLORS", NULL); + } + + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)motTextConvertXYToPos); + + return IUP_NOERROR; +} + +void iupdrvTextInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motTextMapMethod; + ic->LayoutUpdate = motTextLayoutUpdateMethod; + + /* Driver Dependent Attribute functions */ + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motTextSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT); + + /* IupText only */ + iupClassRegisterAttribute(ic, "PADDING", iupTextGetPaddingAttrib, motTextSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "VALUE", motTextGetValueAttrib, motTextSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTEDTEXT", motTextGetSelectedTextAttrib, motTextSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTION", motTextGetSelectionAttrib, motTextSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTIONPOS", motTextGetSelectionPosAttrib, motTextSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARET", motTextGetCaretAttrib, motTextSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARETPOS", motTextGetCaretPosAttrib, motTextSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INSERT", NULL, motTextSetInsertAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "APPEND", NULL, motTextSetAppendAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "READONLY", motTextGetReadOnlyAttrib, motTextSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "NC", iupTextGetNCAttrib, motTextSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, motTextSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FORMATTING", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); /* formatting not supported in Motif */ + iupClassRegisterAttribute(ic, "SCROLLTO", NULL, motTextSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, motTextSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINMIN", NULL, motTextSetSpinMinAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINMAX", NULL, motTextSetSpinMaxAttrib, IUPAF_SAMEASSYSTEM, "100", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPININC", NULL, motTextSetSpinIncAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINVALUE", motTextGetSpinValueAttrib, motTextSetSpinValueAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT); +} diff --git a/iup/src/mot/iupmot_timer.c b/iup/src/mot/iupmot_timer.c new file mode 100755 index 0000000..d23867e --- /dev/null +++ b/iup/src/mot/iupmot_timer.c @@ -0,0 +1,70 @@ +/** \file + * \brief Timer for the Motif Driver. + * + * See Copyright Notice in "iup.h" + */ + + +#include <stdio.h> +#include <stdlib.h> + +#include <Xm/Xm.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_assert.h" +#include "iup_timer.h" + +#include "iupmot_drv.h" + + +static void motTimerProc(XtPointer client_data, XtIntervalId *id) +{ + Ihandle *ih = (Ihandle*)client_data; + Icallback cb; + (void)id; + + if (!iupObjectCheck(ih)) /* control could be destroyed before timer callback */ + return; + + ih->serial = -1; + /* we have to restart the timer everytime */ + iupdrvTimerRun(ih); + + cb = IupGetCallback(ih, "ACTION_CB"); + if (cb) + { + if (cb(ih)==IUP_CLOSE) + IupExitLoop(); + } +} + +void iupdrvTimerRun(Ihandle *ih) +{ + unsigned int time_ms; + + if (ih->serial > 0) /* timer already started */ + return; + + time_ms = iupAttribGetInt(ih, "TIME"); + if (time_ms > 0) + ih->serial = XtAppAddTimeOut(iupmot_appcontext, time_ms, motTimerProc, (XtPointer)ih); +} + +void iupdrvTimerStop(Ihandle* ih) +{ + if (ih->serial > 0) + { + XtRemoveTimeOut(ih->serial); + ih->serial = -1; + } +} + +void iupdrvTimerInitClass(Iclass* ic) +{ + (void)ic; +} diff --git a/iup/src/mot/iupmot_tips.c b/iup/src/mot/iupmot_tips.c new file mode 100755 index 0000000..25bdbea --- /dev/null +++ b/iup/src/mot/iupmot_tips.c @@ -0,0 +1,226 @@ +/** \file + * \brief Motif Driver TIPS Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/Label.h> + +#include <stdio.h> + +#include "iup.h" + +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +/* Default offset from cursor */ +#define TIP_X_OFFSET 12 +#define TIP_Y_OFFSET 12 + +typedef struct _Imottips +{ + Widget Dialog; + Widget Label; + XtIntervalId ShowTimerId; /* Timer: from enterwin to show tip */ + XtIntervalId HideTimerId; /* Timer: from visible to hide tip */ + unsigned long ShowInterval; /* Time for tipPopupTimerId */ + unsigned long HideInterval; /* Time for tipActiveTimerId */ + int Visible; + Ihandle* ih; +} Imottips; + +static Imottips mot_tips = {0, 0, 0, 0, 0, 0}; + +static void motTipsShow(void) +{ + Window root, child; + int cx, cy, x, y; + unsigned int keys; + char* value; + + XQueryPointer(iupmot_display, RootWindow(iupmot_display, iupmot_screen), + &root, &child, &x, &y, &cx, &cy, &keys); + + value = iupAttribGet(mot_tips.ih, "TIPRECT"); + if (value) + { + int x1, x2, y1, y2, wx = x, wy = y; + sscanf(value, "%d %d %d %d", &x1, &y1, &x2, &y2); + iupdrvScreenToClient(mot_tips.ih, &wx, &wy); + if (wx < x1 || wx > x2 || wy < y1 || wy > y2) + { + iupmotTipLeaveNotify(); + return; + } + } + + XtVaSetValues(mot_tips.Dialog, + XmNx, (XtArgVal)(x+TIP_X_OFFSET), + XmNy, (XtArgVal)(y+TIP_Y_OFFSET), + NULL); + + if (mot_tips.Visible) + XRaiseWindow(iupmot_display, XtWindow(mot_tips.Dialog)); + else + XtMapWidget(mot_tips.Dialog); + + mot_tips.ShowTimerId = (XtIntervalId) NULL; + mot_tips.Visible = TRUE; +} + +static void motTipsHide(void) +{ + mot_tips.HideTimerId = (XtIntervalId) NULL; + iupmotTipLeaveNotify(); +} + +static int motTipsSet(Ihandle *ih) +{ + char* tipText = iupAttribGet(ih, "TIP"); + if (!tipText) + return FALSE; + + if (!mot_tips.Dialog) + { + mot_tips.Dialog = XtVaAppCreateShell(" ", "tip", + overrideShellWidgetClass, iupmot_display, + XmNmappedWhenManaged, False, + NULL); + + mot_tips.Label = XtVaCreateManagedWidget("label tip", + xmLabelWidgetClass, mot_tips.Dialog, /* must use IupGetAttribute to use inheritance */ + XmNforeground, iupmotColorGetPixelStr(IupGetAttribute(ih, "TIPFGCOLOR")), + XmNbackground, iupmotColorGetPixelStr(IupGetAttribute(ih, "TIPBGCOLOR")), + NULL); + + XtRealizeWidget(mot_tips.Dialog); + } + + /* set label font */ + { + XmFontList fontlist = (XmFontList)iupmotGetFontListAttrib(ih); + char* value = iupAttribGetStr(ih, "TIPFONT"); + if (value) + { + if (iupStrEqualNoCase(value, "SYSTEM")) + fontlist = NULL; + else + fontlist = iupmotGetFontList(iupAttribGet(ih, "TIPFOUNDRY"), value); + } + + if (fontlist) + XtVaSetValues(mot_tips.Label, XmNfontList, fontlist, NULL); + } + + /* set label contents */ + iupmotSetString(mot_tips.Label, XmNlabelString, tipText); + + /* set label size */ + { + int lw = 0, lh = 0; + iupdrvFontGetMultiLineStringSize(ih, tipText, &lw, &lh); + + /* add room for margin */ + lw += 2*(2); + lh += 2*(2); + + XtVaSetValues(mot_tips.Label, + XmNwidth, (XtArgVal)lw, + XmNheight, (XtArgVal)lh, + NULL); + XtVaSetValues(mot_tips.Dialog, + XmNwidth, (XtArgVal)lw, + XmNheight, (XtArgVal)lh, + NULL); + } + + mot_tips.ShowTimerId = (XtIntervalId) NULL; + mot_tips.HideTimerId = (XtIntervalId) NULL; + mot_tips.Visible = FALSE; + mot_tips.ShowInterval = 500; /* 1/2 second to show */ + + { + int delay = IupGetInt(ih, "TIPDELAY"); /* must use IupGetInt to use inheritance */ + mot_tips.HideInterval = delay + mot_tips.ShowInterval; + } + + return TRUE; +} + +int iupdrvBaseSetTipVisibleAttrib(Ihandle* ih, const char* value) +{ + /* must use IupGetAttribute to use inheritance */ + if (!IupGetAttribute(ih, "TIP")) + return 0; + + if (iupStrBoolean(value)) + iupmotTipEnterNotify(ih); + else + iupmotTipLeaveNotify(); + + return 0; +} + +void iupmotTipEnterNotify(Ihandle *ih) +{ + iupmotTipLeaveNotify(); + + if (motTipsSet(ih) == FALSE) + return; + + mot_tips.ih = ih; + + mot_tips.ShowTimerId = XtAppAddTimeOut( /* EnterWin to Show */ + iupmot_appcontext, + mot_tips.ShowInterval, + (XtTimerCallbackProc)motTipsShow, + NULL); + mot_tips.HideTimerId = XtAppAddTimeOut( /* Visible to Hide */ + iupmot_appcontext, + mot_tips.HideInterval, + (XtTimerCallbackProc)motTipsHide, + NULL); +} + +void iupmotTipLeaveNotify(void) +{ + if (mot_tips.ShowTimerId) + { + XtRemoveTimeOut(mot_tips.ShowTimerId); + mot_tips.ShowTimerId = (XtIntervalId) NULL; + } + if (mot_tips.HideTimerId) + { + XtRemoveTimeOut(mot_tips.HideTimerId); + mot_tips.HideTimerId = (XtIntervalId) NULL; + } + if (mot_tips.Visible) + { + XtUnmapWidget(mot_tips.Dialog); + mot_tips.Visible = FALSE; + } +} + +void iupmotTipsFinish(void) +{ + if (mot_tips.Dialog) + { + XtDestroyWidget(mot_tips.Dialog); + memset(&mot_tips, 0, sizeof(Imottips)); + } +} + +int iupdrvBaseSetTipAttrib(Ihandle* ih, const char* value) +{ + /* implement this stub here because of the other drivers. */ + (void)ih; + (void)value; + return 1; +} diff --git a/iup/src/mot/iupmot_toggle.c b/iup/src/mot/iupmot_toggle.c new file mode 100755 index 0000000..b18f24d --- /dev/null +++ b/iup/src/mot/iupmot_toggle.c @@ -0,0 +1,469 @@ +/** \file + * \brief Toggle Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/ToggleB.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_toggle.h" +#include "iup_drv.h" +#include "iup_image.h" +#include "iup_key.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +void iupdrvToggleAddCheckBox(int *x, int *y) +{ + (*x) += 15+6+3; + if ((*y) < 15+6) (*y) = 12+6; /* minimum height */ + (*y) += 6; +} + + +/*********************************************************************************/ + + +static int motToggleSetBgColorAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_TEXT) + { + char* parent_value = iupAttribGetInheritNativeParent(ih, "BGCOLOR"); + if (!parent_value) + { + /* if not defined at a native parent, + then change the toggle button color to the given color instead using the default */ + if (iupdrvBaseSetBgColorAttrib(ih, value)) /* let XmChangeColor do its job */ + { + parent_value = IupGetGlobal("DLGBGCOLOR"); + XtVaSetValues(ih->handle, XmNbackground, iupmotColorGetPixelStr(parent_value), NULL); /* reset just the background */ + + if (ih->data->radio) + XtVaSetValues(ih->handle, XmNselectColor, iupmotColorGetPixel(0, 0, 0), NULL); + XtVaSetValues(ih->handle, XmNunselectColor, iupmotColorGetPixelStr(value), NULL); + return 1; + } + } + else + { + /* ignore given value, must use only from parent */ + if (iupdrvBaseSetBgColorAttrib(ih, parent_value)) + { + if (ih->data->radio) + XtVaSetValues(ih->handle, XmNselectColor, iupmotColorGetPixel(0, 0, 0), NULL); + XtVaSetValues(ih->handle, XmNunselectColor, iupmotColorGetPixelStr(parent_value), NULL); + return 1; + } + } + return 0; + } + else + return iupdrvBaseSetBgColorAttrib(ih, value); +} + +static int motToggleSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_TEXT) + { + Pixel color; + + /* ignore given value, must use only from parent */ + value = iupAttribGetInheritNativeParent(ih, "BACKGROUND"); + + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + XtVaSetValues(ih->handle, XmNbackground, color, NULL); + return 1; + } + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + if (pixmap) + { + XtVaSetValues(ih->handle, XmNbackgroundPixmap, pixmap, NULL); + return 1; + } + } + } + return 0; +} + +static int motToggleSetTitleAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_TEXT) + { + iupmotSetMnemonicTitle(ih, value); + return 1; + } + + return 0; +} + +static int motToggleSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + unsigned char align; + char value1[30]="", value2[30]=""; + + if (ih->data->type == IUP_TOGGLE_TEXT) + return 0; + + iupStrToStrStr(value, value1, value2, ':'); /* value2 is ignored, NOT supported in Motif */ + + if (iupStrEqualNoCase(value1, "ARIGHT")) + align = XmALIGNMENT_END; + else if (iupStrEqualNoCase(value1, "ACENTER")) + align = XmALIGNMENT_CENTER; + else /* "ALEFT" */ + align = XmALIGNMENT_BEGINNING; + + XtVaSetValues (ih->handle, XmNalignment, align, NULL); + return 1; +} + +static int motToggleSetImageAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + iupmotSetPixmap(ih, value, XmNlabelPixmap, 0); + + if (!iupAttribGet(ih, "IMINACTIVE")) + { + /* if not active and IMINACTIVE is not defined + then automaticaly create one based on IMAGE */ + iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 1); /* make_inactive */ + } + return 1; + } + else + return 0; +} + +static int motToggleSetImInactiveAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 0); + return 1; + } + else + return 0; +} + +static int motToggleSetImPressAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + iupmotSetPixmap(ih, value, XmNselectPixmap, 0); + return 1; + } + else + return 0; +} + +static int motToggleSetValueAttrib(Ihandle* ih, const char* value) +{ + Ihandle *radio; + unsigned char check; + + if (iupStrEqualNoCase(value,"NOTDEF")) + check = XmINDETERMINATE; + else if (iupStrBoolean(value)) + check = XmSET; + else + check = XmUNSET; + + /* This is necessary because Motif toggle does not have support for radio. + It is implemented using an external RadioBox that we do not use. */ + radio = iupRadioFindToggleParent(ih); + if (radio) + { + Ihandle* last_tg; + unsigned char oldcheck; + + XtVaGetValues(ih->handle, XmNset, &oldcheck, NULL); + + last_tg = (Ihandle*)iupAttribGet(radio, "_IUPMOT_LASTTOGGLE"); + if (check) + { + if (iupObjectCheck(last_tg) && last_tg != ih) + XtVaSetValues(last_tg->handle, XmNset, XmUNSET, NULL); + iupAttribSetStr(radio, "_IUPMOT_LASTTOGGLE", (char*)ih); + } + + if (last_tg != ih && oldcheck != check) + XtVaSetValues(ih->handle, XmNset, check, NULL); + } + else + XtVaSetValues(ih->handle, XmNset, check, NULL); + + return 0; +} + +static char* motToggleGetValueAttrib(Ihandle* ih) +{ + unsigned char check = 0; + XtVaGetValues (ih->handle, XmNset, &check, NULL); + if (check == XmINDETERMINATE) + return "NOTDEF"; + else if (check == XmSET) + return "ON"; + else + return "OFF"; +} + +static int motToggleSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle && ih->data->type == IUP_TOGGLE_IMAGE) + { + XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); + } + return 0; +} + +static char* motToggleGetSelectColorAttrib(Ihandle* ih) +{ + unsigned char r, g, b; + Pixel color; + char* str = iupStrGetMemory(20); + XtVaGetValues(ih->handle, XmNselectColor, &color, NULL); + iupmotColorGetRGB(color, &r, &g, &b); + sprintf(str, "%d %d %d", (int)r, (int)g, (int)b); + return str; +} + +static int motToggleSetSelectColorAttrib(Ihandle* ih, const char *value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + XtVaSetValues(ih->handle, XmNselectColor, color, NULL); + return 1; +} + +static void motToggleValueChangedCallback(Widget w, Ihandle* ih, XmToggleButtonCallbackStruct* call_data) +{ + Ihandle *radio; + IFni cb; + int check = call_data->set; + + /* Must manually hide the tip if the toggle is pressed. */ + iupmotTipLeaveNotify(); + + /* This is necessary because Motif toggle does not have support for radio. + It is implemented using an external RadioBox that we do not use. */ + radio = iupRadioFindToggleParent(ih); + if (radio) + { + if (check) + { + Ihandle* last_tg = (Ihandle*)iupAttribGet(radio, "_IUPMOT_LASTTOGGLE"); + if (iupObjectCheck(last_tg) && last_tg != ih) + { + /* uncheck last toggle */ + XtVaSetValues(last_tg->handle, XmNset, XmUNSET, NULL); + + cb = (IFni) IupGetCallback(last_tg, "ACTION"); + if (cb && cb(last_tg, 0) == IUP_CLOSE) + IupExitLoop(); + + iupBaseCallValueChangedCb(last_tg); + } + iupAttribSetStr(radio, "_IUPMOT_LASTTOGGLE", (char*)ih); + + if (last_tg != ih) + { + cb = (IFni)IupGetCallback(ih, "ACTION"); + if (cb && cb (ih, 1) == IUP_CLOSE) + IupExitLoop(); + + iupBaseCallValueChangedCb(ih); + } + } + else + { + /* Force stay checked */ + XtVaSetValues(ih->handle, XmNset, XmSET, NULL); + } + } + else + { + if (check == XmINDETERMINATE) + check = -1; + + cb = (IFni)IupGetCallback(ih, "ACTION"); + if (cb) + { + if (cb(ih, check) == IUP_CLOSE) + IupExitLoop(); + } + + iupBaseCallValueChangedCb(ih); + } + + (void)w; +} + +static int motToggleMapMethod(Ihandle* ih) +{ + Ihandle* radio = iupRadioFindToggleParent(ih); + char* value; + int num_args = 0; + Arg args[40]; + + if (radio) + ih->data->radio = 1; + + value = iupAttribGet(ih, "IMAGE"); + if (value) + { + ih->data->type = IUP_TOGGLE_IMAGE; + iupmotSetArg(args, num_args, XmNlabelType, XmPIXMAP); + } + else + { + ih->data->type = IUP_TOGGLE_TEXT; + iupmotSetArg(args, num_args, XmNlabelType, XmSTRING); + } + + /* Core */ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Primitive */ + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupmotSetArg(args, num_args, XmNhighlightThickness, 2); + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + /* Label */ + iupmotSetArg(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNmarginTop, 0); /* no extra margins */ + iupmotSetArg(args, num_args, XmNmarginLeft, 0); + iupmotSetArg(args, num_args, XmNmarginBottom, 0); + iupmotSetArg(args, num_args, XmNmarginRight, 0); + + if (radio) + { + iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); + iupmotSetArg(args, num_args, XmNindicatorType, XmONE_OF_MANY_ROUND); + + if (!iupAttribGet(radio, "_IUPMOT_LASTTOGGLE")) + { + /* this is the first toggle in the radio, and the last toggle with VALUE=ON */ + iupAttribSetStr(ih, "VALUE","ON"); + } + } + else + { + if (ih->data->type == IUP_TOGGLE_TEXT && iupAttribGetBoolean(ih, "3STATE")) + iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_INDETERMINATE); + else + iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); + iupmotSetArg(args, num_args, XmNindicatorType, XmN_OF_MANY); + } + + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_NONE); + iupmotSetArg(args, num_args, XmNalignment, XmALIGNMENT_CENTER); + iupmotSetArg(args, num_args, XmNshadowThickness, 2); + } + else + { + iupmotSetArg(args, num_args, XmNspacing, 3); + iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK_BOX); + iupmotSetArg(args, num_args, XmNalignment, XmALIGNMENT_BEGINNING); + if (radio) + { + iupmotSetArg(args, num_args, XmNindicatorSize, 13); + iupmotSetArg(args, num_args, XmNselectColor, iupmotColorGetPixel(0, 0, 0)); + } + else + iupmotSetArg(args, num_args, XmNindicatorSize, 15); + + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupmotSetArg(args, num_args, XmNdetailShadowThickness, 2); + } + + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + xmToggleButtonWidgetClass, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + + XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + + XtAddCallback(ih->handle, XmNvalueChangedCallback, (XtCallbackProc)motToggleValueChangedCallback, (XtPointer)ih); + + /* Disable Drag Source */ + iupmotDisableDragSource(ih->handle); + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + if (ih->data->type == IUP_TOGGLE_TEXT) + iupmotSetString(ih->handle, XmNlabelString, ""); + + return IUP_NOERROR; +} + +void iupdrvToggleInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motToggleMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", iupmotGetBgColorAttrib, motToggleSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motToggleSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "TITLE", NULL, motToggleSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupToggle only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, motToggleSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ACENTER:ACENTER", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE", NULL, motToggleSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, motToggleSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMPRESS", NULL, motToggleSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE", motToggleGetValueAttrib, motToggleSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTCOLOR", motToggleGetSelectColorAttrib, motToggleSetSelectColorAttrib, NULL, NULL, IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "PADDING", iupToggleGetPaddingAttrib, motToggleSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); +} diff --git a/iup/src/mot/iupmot_tree.c b/iup/src/mot/iupmot_tree.c new file mode 100755 index 0000000..eb230af --- /dev/null +++ b/iup/src/mot/iupmot_tree.c @@ -0,0 +1,2848 @@ +#include <Xm/Xm.h> +#include <Xm/Form.h> +#include <Xm/Container.h> +#include <Xm/IconG.h> +#include <Xm/ScrolledW.h> +#include <Xm/XmosP.h> +#include <Xm/Text.h> +#include <Xm/Transfer.h> +#include <Xm/DragDrop.h> +#include <X11/keysym.h> + +#include <sys/stat.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> +#include <time.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_dialog.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvinfo.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_key.h" +#include "iup_image.h" +#include "iup_array.h" +#include "iup_tree.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +typedef struct _motTreeItemData +{ + Pixmap image, image_mask; + Pixmap image_expanded, image_expanded_mask; + unsigned char kind; + void* userdata; +} motTreeItemData; + + +static void motTreeShowEditField(Ihandle* ih, Widget wItem); +static int motTreeGetNodeId(Ihandle* ih, Widget wItem); + +typedef int (*motTreeNodeFunc)(Ihandle* ih, Widget wItem, void* userdata); + +static int motTreeForEach(Ihandle* ih, Widget wItem, motTreeNodeFunc func, void* userdata) +{ + WidgetList wItemChildList = NULL; + int i, numChild; + + if (!wItem) + wItem = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + if (!func(ih, wItem, userdata)) + return 0; + + numChild = XmContainerGetItemChildren(ih->handle, wItem, &wItemChildList); + for (i=0; i<numChild; i++) + { + /* Recursively traverse child items */ + if (!motTreeForEach(ih, wItemChildList[i], func, userdata)) + { + XtFree((char*)wItemChildList); + return 0; + } + } + if (wItemChildList) XtFree((char*)wItemChildList); + + return 1; +} + +/*****************************************************************************/ +/* COPYING ITEMS (Branches and its children) */ +/*****************************************************************************/ +/* Insert the copied item in a new location. Returns the new item. */ +static Widget motTreeCopyItem(Ihandle* ih, Widget wItem, Widget wParent, int pos, int full_copy) +{ + Widget wNewItem; + XmString title; + motTreeItemData *itemData; + Pixel fgcolor, bgcolor; + int num_args = 0; + Arg args[30]; + Pixmap image = XmUNSPECIFIED_PIXMAP, mask = XmUNSPECIFIED_PIXMAP; + unsigned char state; + + iupmotSetArg(args, num_args, XmNentryParent, wParent); + iupmotSetArg(args, num_args, XmNmarginHeight, ih->data->spacing); + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNviewType, XmSMALL_ICON); + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + + /* Get values to copy */ + XtVaGetValues(wItem, XmNlabelString, &title, + XmNuserData, &itemData, + XmNforeground, &fgcolor, + XmNsmallIconPixmap, &image, + XmNsmallIconMask, &mask, + XmNoutlineState, &state, + NULL); + + if (full_copy) /* during a full copy the userdata reference is not copied */ + { + /* create a new one */ + motTreeItemData* itemDataNew = malloc(sizeof(motTreeItemData)); + memcpy(itemDataNew, itemData, sizeof(motTreeItemData)); + itemDataNew->userdata = NULL; + itemData = itemDataNew; + } + + iupmotSetArg(args, num_args, XmNlabelString, title); + iupmotSetArg(args, num_args, XmNuserData, itemData); + iupmotSetArg(args, num_args, XmNforeground, fgcolor); + iupmotSetArg(args, num_args, XmNsmallIconPixmap, image); + iupmotSetArg(args, num_args, XmNsmallIconMask, mask); + iupmotSetArg(args, num_args, XmNoutlineState, state); + + iupmotSetArg(args, num_args, XmNentryParent, wParent); + iupmotSetArg(args, num_args, XmNpositionIndex, pos); + + XtVaGetValues(ih->handle, XmNbackground, &bgcolor, NULL); + iupmotSetArg(args, num_args, XmNbackground, bgcolor); + + wNewItem = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); + + /* Root always expanded */ + XtVaSetValues((Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"), XmNoutlineState, XmEXPANDED, NULL); + + XtRealizeWidget(wNewItem); + + return wNewItem; +} + +static void motTreeCopyChildren(Ihandle* ih, Widget wItemSrc, Widget wItemDst, int full_copy) +{ + WidgetList wItemChildList = NULL; + int i = 0; + int numChild = XmContainerGetItemChildren(ih->handle, wItemSrc, &wItemChildList); + while(i != numChild) + { + Widget wNewItem = motTreeCopyItem(ih, wItemChildList[i], wItemDst, i, full_copy); /* Use the same order they where enumerated */ + + /* Recursively transfer all the items */ + motTreeCopyChildren(ih, wItemChildList[i], wNewItem, full_copy); + + /* Go to next sibling item */ + i++; + } + + if (wItemChildList) XtFree((char*)wItemChildList); +} + +/* Copies all items in a branch to a new location. Returns the new branch node. */ +static Widget motTreeCopyNode(Ihandle* ih, Widget wItemSrc, Widget wItemDst, int full_copy) +{ + Widget wNewItem, wParent; + motTreeItemData *itemDataDst; + unsigned char stateDst; + int pos; + + XtVaGetValues(wItemDst, XmNoutlineState, &stateDst, + XmNuserData, &itemDataDst, + NULL); + + if (itemDataDst->kind == ITREE_BRANCH && stateDst == XmEXPANDED) + { + /* copy as first child of expanded branch */ + wParent = wItemDst; + pos = 0; + } + else + { + /* copy as next brother of item or collapsed branch */ + XtVaGetValues(wItemDst, XmNentryParent, &wParent, NULL); + XtVaGetValues(wItemDst, XmNpositionIndex, &pos, NULL); + pos++; + } + + wNewItem = motTreeCopyItem(ih, wItemSrc, wParent, pos, full_copy); + + motTreeCopyChildren(ih, wItemSrc, wNewItem, full_copy); + + return wNewItem; +} + +static void motTreeContainerDeselectAll(Ihandle *ih) +{ + XKeyEvent ev; + + memset(&ev, 0, sizeof(XKeyEvent)); + ev.type = KeyPress; + ev.display = XtDisplay(ih->handle); + ev.send_event = True; + ev.root = RootWindow(iupmot_display, iupmot_screen); + ev.time = clock()*CLOCKS_PER_SEC; + ev.window = XtWindow(ih->handle); + ev.state = ControlMask; + ev.keycode = XK_backslash; + ev.same_screen = True; + + XtCallActionProc(ih->handle, "ContainerDeselectAll", (XEvent*)&ev, 0, 0); +} + +static void motTreeContainerSelectAll(Ihandle *ih) +{ + XKeyEvent ev; + + memset(&ev, 0, sizeof(XKeyEvent)); + ev.type = KeyPress; + ev.display = XtDisplay(ih->handle); + ev.send_event = True; + ev.root = RootWindow(iupmot_display, iupmot_screen); + ev.time = clock()*CLOCKS_PER_SEC; + ev.window = XtWindow(ih->handle); + ev.state = ControlMask; + ev.keycode = XK_slash; + ev.same_screen = True; + + XtCallActionProc(ih->handle, "ContainerSelectAll", (XEvent*)&ev, 0, 0); +} + +static Widget motTreeGetLastVisibleNode(Ihandle* ih, Widget wItem) +{ + unsigned char itemState; + + XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL); + + if (itemState == XmEXPANDED) + { + WidgetList wChildrenTree = NULL; + int numChildren = XmContainerGetItemChildren(ih->handle, wItem, &wChildrenTree); + if(numChildren) + wItem = motTreeGetLastVisibleNode(ih, wChildrenTree[numChildren - 1]); + if (wChildrenTree) XtFree((char*)wChildrenTree); + } + + return wItem; +} + +static Widget motTreeFindVisibleNodeId(Ihandle* ih, WidgetList itemList, int numItems, Widget itemNode) +{ + Widget itemChild; + WidgetList itemChildList; + int i = 0; + int numChild; + unsigned char itemState; + + while(i != numItems) + { + /* ID control to traverse items */ + ih->data->id_control++; /* not the real id since it counts only the visible ones */ + + /* StateID founded! */ + if(itemList[i] == itemNode) + return itemList[i]; + + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + XtVaGetValues(itemList[i], XmNoutlineState, &itemState, NULL); + + /* The itemWidget has child and it is expanded (visible) */ + if (numChild && itemState == XmEXPANDED) + { + /* pass the list of children of this item */ + itemChild = motTreeFindVisibleNodeId(ih, itemChildList, numChild, itemNode); + + /* StateID founded! */ + if(itemChild) + { + XtFree((char*)itemChildList); + return itemChild; + } + } + + if (itemChildList) XtFree((char*)itemChildList); + /* Go to next sibling item */ + i++; + } + + return NULL; +} + +static Widget motTreeFindVisibleNodeFromId(Ihandle* ih, WidgetList itemList, int numItems) +{ + Widget itemChild; + WidgetList itemChildList; + int i = 0; + int numChild; + unsigned char itemState; + + while(i != numItems) + { + /* ID control to traverse items */ + ih->data->id_control--; /* not the real id since it counts only the visible ones */ + + /* StateID founded! */ + if(ih->data->id_control < 0) + return itemList[i]; + + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + XtVaGetValues(itemList[i], XmNoutlineState, &itemState, NULL); + + /* The itemWidget has child and it is expanded (visible) */ + if (numChild && itemState == XmEXPANDED) + { + /* pass the list of children of this item */ + itemChild = motTreeFindVisibleNodeFromId(ih, itemChildList, numChild); + + /* StateID founded! */ + if(ih->data->id_control < 0) + { + if (itemChildList) XtFree((char*)itemChildList); + return itemChild; + } + } + + if (itemChildList) XtFree((char*)itemChildList); + /* Go to next sibling item */ + i++; + } + + return NULL; +} + +static Widget motTreeGetNextVisibleNode(Ihandle* ih, Widget wRoot, Widget wItem) +{ + Widget wNext; + + ih->data->id_control = -1; + motTreeFindVisibleNodeId(ih, &wRoot, 1, wItem); + ih->data->id_control++; /* more 1 visible node */ + + wNext = motTreeFindVisibleNodeFromId(ih, &wRoot, 1); + + if (ih->data->id_control >= 0) + wNext = motTreeGetLastVisibleNode(ih, wRoot); + + return wNext; +} + +static Widget motTreeGetPreviousVisibleNode(Ihandle* ih, Widget wRoot, Widget wItem) +{ + ih->data->id_control = -1; + motTreeFindVisibleNodeId(ih, &wRoot, 1, wItem); + ih->data->id_control--; /* less 1 visible node */ + + if (ih->data->id_control < 0) + ih->data->id_control = 0; /* Begin of tree = Root id */ + + return motTreeFindVisibleNodeFromId(ih, &wRoot, 1); +} + +static void motTreeUpdateBgColor(Ihandle* ih, WidgetList itemList, int numItems, Pixel bgcolor) +{ + WidgetList itemChildList; + int i = 0; + int numChild; + + while(i != numItems) + { + XtVaSetValues(itemList[i], XmNbackground, bgcolor, NULL); + + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + if(numChild) + motTreeUpdateBgColor(ih, itemChildList, numChild, bgcolor); + if (itemChildList) XtFree((char*)itemChildList); + + /* Go to next sibling item */ + i++; + } +} + +static void motTreeUpdateImages(Ihandle* ih, WidgetList itemList, int numItems, int mode) +{ + motTreeItemData *itemData; + int i = 0; + + /* called when one of the default images is changed */ + + while(i != numItems) + { + /* Get node attributes */ + XtVaGetValues(itemList[i], XmNuserData, &itemData, NULL); + + if (itemData->kind == ITREE_BRANCH) + { + unsigned char itemState; + XtVaGetValues(itemList[i], XmNoutlineState, &itemState, NULL); + + if (itemState == XmEXPANDED) + { + if (mode == ITREE_UPDATEIMAGE_EXPANDED) + { + XtVaSetValues(itemList[i], XmNsmallIconPixmap, (itemData->image_expanded!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded: (Pixmap)ih->data->def_image_expanded, NULL); + XtVaSetValues(itemList[i], XmNsmallIconMask, (itemData->image_expanded_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded_mask: (Pixmap)ih->data->def_image_expanded_mask, NULL); + } + } + else + { + if (mode == ITREE_UPDATEIMAGE_COLLAPSED) + { + XtVaSetValues(itemList[i], XmNsmallIconPixmap, (itemData->image!=XmUNSPECIFIED_PIXMAP)? itemData->image: (Pixmap)ih->data->def_image_collapsed, NULL); + XtVaSetValues(itemList[i], XmNsmallIconMask, (itemData->image_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_mask: (Pixmap)ih->data->def_image_collapsed_mask, NULL); + } + } + + /* Recursively traverse child items */ + { + WidgetList itemChildList; + int numChild; + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + motTreeUpdateImages(ih, itemChildList, numChild, mode); + if (itemChildList) XtFree((char*)itemChildList); + } + } + else + { + if (mode == ITREE_UPDATEIMAGE_LEAF) + { + XtVaSetValues(itemList[i], XmNsmallIconPixmap, (itemData->image!=XmUNSPECIFIED_PIXMAP)? itemData->image: (Pixmap)ih->data->def_image_leaf, NULL); + XtVaSetValues(itemList[i], XmNsmallIconMask, (itemData->image_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_mask: (Pixmap)ih->data->def_image_leaf_mask, NULL); + } + } + + /* Go to next sibling node */ + i++; + } +} + +static int motTreeSelectFunc(Ihandle* ih, Widget wItem, int *select) +{ + int do_select = *select; + if (do_select == -1) + { + unsigned char isSelected; + XtVaGetValues(wItem, XmNvisualEmphasis, &isSelected, NULL); + do_select = (isSelected == XmSELECTED)? 0: 1; /* toggle */ + } + + if (do_select) + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + else + XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); + + (void)ih; + return 1; +} + +static void motTreeInvertAllNodeMarking(Ihandle* ih) +{ + int select = -1; + motTreeForEach(ih, NULL, (motTreeNodeFunc)motTreeSelectFunc, &select); +} + +typedef struct _motTreeRange{ + Widget wItem1, wItem2; + char inside, clear; +}motTreeRange; + +static int motTreeSelectRangeFunc(Ihandle* ih, Widget wItem, motTreeRange* range) +{ + int end_range = 0; + + if (range->inside == 0) /* detect the range start */ + { + if (range->wItem1 == wItem) range->inside=1; + else if (range->wItem2 == wItem) range->inside=1; + } + else if (range->inside == 1) /* detect the range end */ + { + if (range->wItem1 == wItem) end_range=1; + else if (range->wItem2 == wItem) end_range=1; + } + + if (range->inside == 1) /* if inside, select */ + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + else if (range->clear) /* if outside and clear, unselect */ + XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); + + if (end_range || (range->inside && range->wItem1==range->wItem2)) + range->inside=-1; /* update after selecting the node */ + + (void)ih; + return 1; +} + +static void motTreeSelectRange(Ihandle* ih, Widget wItem1, Widget wItem2, int clear) +{ + motTreeRange range; + range.wItem1 = wItem1; + range.wItem2 = wItem2; + range.inside = 0; + range.clear = (char)clear; + motTreeForEach(ih, NULL, (motTreeNodeFunc)motTreeSelectRangeFunc, &range); +} + +void motTreeExpandCollapseAllNodes(Ihandle* ih, WidgetList itemList, int numItems, unsigned char itemState) +{ + WidgetList itemChildList; + int numChild; + int i = 0; + + while(i != numItems) + { + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + + if(numChild) + { + XtVaSetValues(itemList[i], XmNoutlineState, itemState, NULL); + motTreeExpandCollapseAllNodes(ih, itemChildList, numChild, itemState); + } + + if (itemChildList) XtFree((char*)itemChildList); + /* Go to next sibling item */ + i++; + } +} + +static void motTreeDestroyItemData(Ihandle* ih, Widget wItem) +{ + motTreeItemData *itemData = NULL; + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + if (itemData) + { + IFnis cb = (IFnis)IupGetCallback(ih, "NODEREMOVED_CB"); + if (cb) cb(ih, motTreeGetNodeId(ih, wItem), (char*)itemData->userdata); + free(itemData); + XtVaSetValues(wItem, XmNuserData, NULL, NULL); + } +} + +static void motTreeRemoveChildren(Ihandle* ih, WidgetList itemList, int numItems, int del_userdata) +{ + WidgetList itemChildList; + int numChild; + int i = 0; + + while(i != numItems) + { + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + if (numChild) + motTreeRemoveChildren(ih, itemChildList, numChild, del_userdata); + + if (del_userdata) + motTreeDestroyItemData(ih, itemList[i]); + + XtDestroyWidget(itemList[i]); + + if (itemChildList) XtFree((char*)itemChildList); + /* Go to next sibling item */ + i++; + } +} + +static void motTreeRemoveNode(Ihandle* ih, Widget wItem, int del_userdata) +{ + WidgetList wChildList = NULL; + int numChild = XmContainerGetItemChildren(ih->handle, wItem, &wChildList); + if (numChild) + motTreeRemoveChildren(ih, wChildList, numChild, del_userdata); + if (del_userdata) + motTreeDestroyItemData(ih, wItem); + XtDestroyWidget(wItem); + if (wChildList) XtFree((char*)wChildList); +} + +static Widget motTreeFindNodeID(Ihandle* ih, WidgetList itemList, int numItems, Widget itemNode) +{ + Widget itemChild; + WidgetList itemChildList; + int i = 0; + int numChild; + + while(i != numItems) + { + /* ID control to traverse items */ + ih->data->id_control++; + + /* StateID founded! */ + if(itemList[i] == itemNode) + return itemList[i]; + + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + if(numChild) + { + /* pass the list of children of this item */ + itemChild = motTreeFindNodeID(ih, itemChildList, numChild, itemNode); + + /* StateID founded! */ + if(itemChild) + { + if (itemChildList) XtFree((char*)itemChildList); + return itemChild; + } + } + + if (itemChildList) XtFree((char*)itemChildList); + /* Go to next sibling item */ + i++; + } + + return NULL; +} + +static Widget motTreeFindNodeFromID(Ihandle* ih, WidgetList itemList, int numItems) +{ + Widget itemChild; + WidgetList itemChildList; + int i = 0; + int numChild; + + while(i != numItems) + { + /* ID control to traverse items */ + ih->data->id_control--; + + /* StateID founded! */ + if(ih->data->id_control < 0) + return itemList[i]; + + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + if(numChild) + { + /* pass the list of children of this item */ + itemChild = motTreeFindNodeFromID(ih, itemChildList, numChild); + + /* StateID founded! */ + if(ih->data->id_control < 0) + { + if (itemChildList) XtFree((char*)itemChildList); + return itemChild; + } + } + + if (itemChildList) XtFree((char*)itemChildList); + /* Go to next sibling item */ + i++; + } + + return NULL; +} + +static int motTreeGetNodeId(Ihandle* ih, Widget wItem) +{ + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + ih->data->id_control = -1; + if (motTreeFindNodeID(ih, &wRoot, 1, wItem)) + return ih->data->id_control; + else + return -1; +} + +static Widget motTreeFindUserDataID(Ihandle* ih, WidgetList itemList, int numItems, void* userdata) +{ + Widget itemChild; + WidgetList itemChildList; + motTreeItemData *itemData; + int i = 0; + int numChild; + + while(i != numItems) + { + /* ID control to traverse items */ + ih->data->id_control++; + + XtVaGetValues(itemList[i], XmNuserData, &itemData, NULL); + + /* StateID founded! */ + if(itemData->userdata == userdata) + return itemList[i]; + + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + if(numChild) + { + /* pass the list of children of this item */ + itemChild = motTreeFindUserDataID(ih, itemChildList, numChild, userdata); + + /* StateID founded! */ + if (itemChild) + { + if (itemChildList) XtFree((char*)itemChildList); + return itemChild; + } + } + + if (itemChildList) XtFree((char*)itemChildList); + /* Go to next sibling item */ + i++; + } + + return NULL; +} + +static int motTreeGetUserDataId(Ihandle* ih, void* userdata) +{ + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + ih->data->id_control = -1; + if (motTreeFindUserDataID(ih, &wRoot, 1, userdata)) + return ih->data->id_control; + else + return -1; +} + +static void motTreeSetFocusNode(Ihandle* ih, Widget wItem) +{ + iupAttribSetStr(ih, "_IUPTREE_LAST_FOCUS", (char*)wItem); + XmProcessTraversal(wItem, XmTRAVERSE_CURRENT); +} + +static Widget motTreeGetFocusNode(Ihandle* ih) +{ + Widget wItem = XmGetFocusWidget(ih->handle); /* returns the focus in the dialog */ + if (wItem && XtParent(wItem) == ih->handle) /* is a node */ + return wItem; + + return (Widget)iupAttribGet(ih, "_IUPTREE_LAST_FOCUS"); +} + +static Widget motTreeFindNodeFromString(Ihandle* ih, const char* name_id) +{ + if (name_id[0]) + { + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + iupStrToInt(name_id, &ih->data->id_control); + return motTreeFindNodeFromID(ih, &wRoot, 1); + } + else + return motTreeGetFocusNode(ih); +} + +static void motTreeEnterLeaveWindowEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + if (iupAttribGet(ih, "_IUPTREE_EDITFIELD")) + return; + + /* usually when one Gadget is selected different than the previous one, + leave/enter events are generated. But we could not find the exact condition, + so this is a workaround. Some leave events will be lost. */ + if (evt->type == EnterNotify) + { + if (iupAttribGet(ih, "_IUPTREE_IGNORE_ENTERLEAVE")) + { + iupAttribSetStr(ih, "_IUPTREE_IGNORE_ENTERLEAVE", NULL); + return; + } + } + else if (evt->type == LeaveNotify) + { + if (iupAttribGet(ih, "_IUPTREE_IGNORE_ENTERLEAVE")) + return; + } + + iupmotEnterLeaveWindowEvent(w, ih, evt, cont); +} + +static void motTreeFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + unsigned char selpol; + Widget wItem = XmGetFocusWidget(w); /* returns the focus in the dialog */ + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + if (XtParent(wItem) == w) /* is a node */ + iupAttribSetStr(ih, "_IUPTREE_LAST_FOCUS", (char*)wItem); + + if (wItem == NULL || wItem == wRoot) + { + iupmotFocusChangeEvent(w, ih, evt, cont); + return; + } + + XtVaGetValues(w, XmNselectionPolicy, &selpol, NULL); + if (selpol != XmSINGLE_SELECT) + return; + + if (evt->type == FocusIn && !iupStrBoolean(IupGetGlobal("CONTROLKEY"))) + { + XtVaSetValues(w, XmNselectedObjects, NULL, NULL); + XtVaSetValues(w, XmNselectedObjectCount, 0, NULL); + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + } +} + +void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* title, int add) +{ + Widget wItemPrev = motTreeFindNodeFromString(ih, name_id); + Widget wNewItem; + XmString itemTitle; + motTreeItemData *itemData, *itemDataPrev; + Pixel bgcolor, fgcolor; + int kindPrev, num_args = 0; + Arg args[30]; + + if (!wItemPrev) + return; + + itemData = calloc(1, sizeof(motTreeItemData)); + itemData->image = XmUNSPECIFIED_PIXMAP; + itemData->image_expanded = XmUNSPECIFIED_PIXMAP; + itemData->image_mask = XmUNSPECIFIED_PIXMAP; + itemData->image_expanded_mask = XmUNSPECIFIED_PIXMAP; + itemData->kind = (unsigned char)kind; + + itemTitle = XmStringCreateLocalized((String)title); + + /* Get default colors */ + XtVaGetValues(ih->handle, XmNforeground, &fgcolor, NULL); + XtVaGetValues(ih->handle, XmNbackground, &bgcolor, NULL); + + /* Get the kind of previous item */ + XtVaGetValues(wItemPrev, XmNuserData, &itemDataPrev, NULL); + kindPrev = itemDataPrev->kind; + + if (kindPrev == ITREE_BRANCH && add) + { + /* wItemPrev is parent of the new item (firstchild of it) */ + iupmotSetArg(args, num_args, XmNentryParent, wItemPrev); + iupmotSetArg(args, num_args, XmNpositionIndex, 0); + } + else + { + /* wItemPrev is sibling of the new item (set its parent to the new item) */ + Widget wItemParent; + int pos; + + XtVaGetValues(wItemPrev, XmNentryParent, &wItemParent, NULL); + XtVaGetValues(wItemPrev, XmNpositionIndex, &pos, NULL); + + iupmotSetArg(args, num_args, XmNentryParent, wItemParent); + iupmotSetArg(args, num_args, XmNpositionIndex, pos+1); + } + + iupmotSetArg(args, num_args, XmNuserData, itemData); + iupmotSetArg(args, num_args, XmNforeground, fgcolor); + iupmotSetArg(args, num_args, XmNbackground, bgcolor); + iupmotSetArg(args, num_args, XmNmarginHeight, ih->data->spacing); + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNviewType, XmSMALL_ICON); + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupmotSetArg(args, num_args, XmNlabelString, itemTitle); + + if (kind == ITREE_BRANCH) + { + if (ih->data->add_expanded) + { + iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_expanded); + iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_expanded_mask); + } + else + { + iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_collapsed); + iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_collapsed_mask); + } + } + else + { + iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_leaf); + iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_leaf_mask); + } + + + wNewItem = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); + + if (kind == ITREE_BRANCH) + { + if (ih->data->add_expanded) + { + iupAttribSetStr(ih, "_IUP_IGNORE_BRANCHOPEN", "1"); + XtVaSetValues(wNewItem, XmNoutlineState, XmEXPANDED, NULL); + } + else + XtVaSetValues(wNewItem, XmNoutlineState, XmCOLLAPSED, NULL); + } + + /* Root always expanded */ + XtVaSetValues((Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"), XmNoutlineState, XmEXPANDED, NULL); + + XtRealizeWidget(wNewItem); + XmStringFree(itemTitle); +} + +static void motTreeAddRootNode(Ihandle* ih) +{ + Widget wRootItem; + motTreeItemData *itemData; + Pixel bgcolor, fgcolor; + int num_args = 0; + Arg args[30]; + + itemData = calloc(1, sizeof(motTreeItemData)); + itemData->image = XmUNSPECIFIED_PIXMAP; + itemData->image_expanded = XmUNSPECIFIED_PIXMAP; + itemData->image_mask = XmUNSPECIFIED_PIXMAP; + itemData->image_expanded_mask = XmUNSPECIFIED_PIXMAP; + itemData->kind = ITREE_BRANCH; + + /* Get default foreground color */ + XtVaGetValues(ih->handle, XmNforeground, &fgcolor, NULL); + XtVaGetValues(ih->handle, XmNbackground, &bgcolor, NULL); + + iupmotSetArg(args, num_args, XmNentryParent, NULL); + iupmotSetArg(args, num_args, XmNuserData, itemData); + iupmotSetArg(args, num_args, XmNforeground, fgcolor); + iupmotSetArg(args, num_args, XmNbackground, bgcolor); + iupmotSetArg(args, num_args, XmNoutlineState, XmEXPANDED); + iupmotSetArg(args, num_args, XmNmarginHeight, ih->data->spacing); + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNviewType, XmSMALL_ICON); + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_expanded); + iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_expanded_mask); + + wRootItem = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); + + /* Select the new item */ + XtVaSetValues(wRootItem, XmNvisualEmphasis, XmSELECTED, NULL); + + XtRealizeWidget(wRootItem); + + /* Save the root node for later use */ + iupAttribSetStr(ih, "_IUPTREE_ROOTITEM", (char*)wRootItem); + + /* MarkStart node */ + iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)wRootItem); + + /* Set the default VALUE */ + /* In Motif this will set also the current focus */ + motTreeSetFocusNode(ih, wRootItem); +} + +/*****************************************************************************/ + +static int motTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + motTreeItemData *itemData; + unsigned char itemState; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL); + itemData->image_expanded = (Pixmap)iupImageGetImage(value, ih, 0); + if (!itemData->image_expanded) + { + itemData->image_expanded = XmUNSPECIFIED_PIXMAP; + itemData->image_expanded_mask = XmUNSPECIFIED_PIXMAP; + } + else + { + itemData->image_expanded_mask = (Pixmap)iupImageGetMask(value); + if (!itemData->image_expanded_mask) itemData->image_expanded_mask = XmUNSPECIFIED_PIXMAP; + } + + if (itemData->kind == ITREE_BRANCH && itemState == XmEXPANDED) + { + if (itemData->image_expanded == XmUNSPECIFIED_PIXMAP) + XtVaSetValues(wItem, XmNsmallIconPixmap, (Pixmap)ih->data->def_image_expanded, + XmNsmallIconMask, (Pixmap)ih->data->def_image_expanded_mask, + NULL); + else + XtVaSetValues(wItem, XmNsmallIconPixmap, itemData->image_expanded, + XmNsmallIconMask, itemData->image_expanded_mask, + NULL); + } + + return 1; +} + +static int motTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + motTreeItemData *itemData; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + itemData->image = (Pixmap)iupImageGetImage(value, ih, 0); + if (!itemData->image) + { + itemData->image = XmUNSPECIFIED_PIXMAP; + itemData->image_mask = XmUNSPECIFIED_PIXMAP; + } + else + { + itemData->image_mask = (Pixmap)iupImageGetMask(value); + if (!itemData->image_mask) itemData->image_mask = XmUNSPECIFIED_PIXMAP; + } + + if (itemData->kind == ITREE_BRANCH) + { + unsigned char itemState; + XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL); + if (itemState == XmCOLLAPSED) + { + if (itemData->image == XmUNSPECIFIED_PIXMAP) + XtVaSetValues(wItem, XmNsmallIconPixmap, (Pixmap)ih->data->def_image_collapsed, + XmNsmallIconMask, (Pixmap)ih->data->def_image_collapsed_mask, + NULL); + else + XtVaSetValues(wItem, XmNsmallIconPixmap, itemData->image, + XmNsmallIconMask, itemData->image_mask, + NULL); + } + } + else + { + if (itemData->image == XmUNSPECIFIED_PIXMAP) + XtVaSetValues(wItem, XmNsmallIconPixmap, (Pixmap)ih->data->def_image_leaf, + XmNsmallIconMask, (Pixmap)ih->data->def_image_leaf_mask, + NULL); + else + XtVaSetValues(wItem, XmNsmallIconPixmap, itemData->image, + XmNsmallIconMask, itemData->image_mask, + NULL); + } + + return 1; +} + +static int motTreeSetImageBranchExpandedAttrib(Ihandle* ih, const char* value) +{ + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + ih->data->def_image_expanded = iupImageGetImage(value, ih, 0); + if (!ih->data->def_image_expanded) + { + ih->data->def_image_expanded = (void*)XmUNSPECIFIED_PIXMAP; + ih->data->def_image_expanded_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + else + { + ih->data->def_image_expanded_mask = iupImageGetMask(value); + if (!ih->data->def_image_expanded_mask) ih->data->def_image_expanded_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + + /* Update all images, starting at root node */ + motTreeUpdateImages(ih, &wRoot, 1, ITREE_UPDATEIMAGE_EXPANDED); + + return 1; +} + +static int motTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value) +{ + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + ih->data->def_image_collapsed = iupImageGetImage(value, ih, 0); + if (!ih->data->def_image_collapsed) + { + ih->data->def_image_collapsed = (void*)XmUNSPECIFIED_PIXMAP; + ih->data->def_image_collapsed_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + else + { + ih->data->def_image_collapsed_mask = iupImageGetMask(value); + if (!ih->data->def_image_collapsed_mask) ih->data->def_image_collapsed_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + + /* Update all images, starting at root node */ + motTreeUpdateImages(ih, &wRoot, 1, ITREE_UPDATEIMAGE_COLLAPSED); + + return 1; +} + +static int motTreeSetImageLeafAttrib(Ihandle* ih, const char* value) +{ + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + ih->data->def_image_leaf = iupImageGetImage(value, ih, 0); + if (!ih->data->def_image_leaf) + { + ih->data->def_image_leaf = (void*)XmUNSPECIFIED_PIXMAP; + ih->data->def_image_leaf_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + else + { + ih->data->def_image_leaf_mask = iupImageGetMask(value); + if (!ih->data->def_image_leaf_mask) ih->data->def_image_leaf_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + + /* Update all images, starting at root node */ + motTreeUpdateImages(ih, &wRoot, 1, ITREE_UPDATEIMAGE_LEAF); + + return 1; +} + +static char* motTreeGetStateAttrib(Ihandle* ih, const char* name_id) +{ + int hasChildren; + unsigned char itemState; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + XtVaGetValues(wItem, XmNnumChildren, &hasChildren, NULL); + XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL); + + if (hasChildren) + { + if(itemState == XmEXPANDED) + return "EXPANDED"; + else + return "COLLAPSED"; + } + + return NULL; +} + +static int motTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + if (iupStrEqualNoCase(value, "EXPANDED")) + XtVaSetValues(wItem, XmNoutlineState, XmEXPANDED, NULL); + else + XtVaSetValues(wItem, XmNoutlineState, XmCOLLAPSED, NULL); + + return 0; +} + +static char* motTreeGetColorAttrib(Ihandle* ih, const char* name_id) +{ + unsigned char r, g, b; + Pixel color; + char* str; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + XtVaGetValues(wItem, XmNforeground, &color, NULL); + iupmotColorGetRGB(color, &r, &g, &b); + + str = iupStrGetMemory(20); + sprintf(str, "%d %d %d", (int)r, (int)g, (int)b); + return str; +} + +static int motTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + Pixel color; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + XtVaSetValues(wItem, XmNforeground, color, NULL); + return 0; +} + +static char* motTreeGetDepthAttrib(Ihandle* ih, const char* name_id) +{ + Widget wRoot; + int dep = 0; + char* depth; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + while((wRoot != wItem) && (wItem != NULL)) + { + XtVaGetValues(wItem, XmNentryParent, &wItem, NULL); + dep++; + } + + depth = iupStrGetMemory(10); + sprintf(depth, "%d", dep); + return depth; +} + +static int motTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + Widget wItemDst, wParent, wItemSrc; + + if (!ih->handle) /* do not store the action before map */ + return 0; + wItemSrc = motTreeFindNodeFromString(ih, name_id); + if (!wItemSrc) + return 0; + wItemDst = motTreeFindNodeFromString(ih, value); + if (!wItemDst) + return 0; + + /* If Drag item is an ancestor of Drop item then return */ + wParent = wItemDst; + while(wParent) + { + XtVaGetValues(wParent, XmNentryParent, &wParent, NULL); + if (wParent == wItemSrc) + return 0; + } + + /* Copying the node and its children to the new position */ + motTreeCopyNode(ih, wItemSrc, wItemDst, 0); /* not a full copy, preserve user data */ + + /* Deleting the node (and its children) inserted into the old position */ + motTreeRemoveNode(ih, wItemSrc, 0); /* do not delete the user data, we copy the references in CopyNode */ + + return 0; +} + +static int motTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + Widget wItemDst, wParent, wItemSrc; + + if (!ih->handle) /* do not store the action before map */ + return 0; + wItemSrc = motTreeFindNodeFromString(ih, name_id); + if (!wItemSrc) + return 0; + wItemDst = motTreeFindNodeFromString(ih, value); + if (!wItemDst) + return 0; + + /* If Drag item is an ancestor of Drop item then return */ + wParent = wItemDst; + while(wParent) + { + XtVaGetValues(wParent, XmNentryParent, &wParent, NULL); + if (wParent == wItemSrc) + return 0; + } + + /* Copying the node and its children to the new position */ + motTreeCopyNode(ih, wItemSrc, wItemDst, 1); + + return 0; +} + +static char* motTreeGetParentAttrib(Ihandle* ih, const char* name_id) +{ + Widget wItemParent; + char* str; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + /* get the parent item */ + XtVaGetValues(wItem, XmNentryParent, &wItemParent, NULL); + if (!wItemParent) + return NULL; + + str = iupStrGetMemory(10); + sprintf(str, "%d", motTreeGetNodeId(ih, wItemParent)); + return str; +} + +static char* motTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) +{ + char* str; + WidgetList wList = NULL; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + str = iupStrGetMemory(10); + sprintf(str, "%d", XmContainerGetItemChildren(ih->handle, wItem, &wList)); + if (wList) XtFree((char*)wList); + return str; +} + +static int motTreeCount(Ihandle* ih, Widget wItem) +{ + WidgetList wList = NULL; + int i, count = 0; + int childCount = XmContainerGetItemChildren(ih->handle, wItem, &wList); + count++; + for (i=0; i<childCount; i++) + count += motTreeCount(ih, wList[i]); + if (wList) XtFree((char*)wList); + return count; +} + +static char* motTreeGetCountAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(10); + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + sprintf(str, "%d", motTreeCount(ih, wRoot)); + return str; +} + +static char* motTreeGetKindAttrib(Ihandle* ih, const char* name_id) +{ + motTreeItemData *itemData; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + + if(itemData->kind == ITREE_BRANCH) + return "BRANCH"; + else + return "LEAF"; +} + +static char* motTreeGetValueAttrib(Ihandle* ih) +{ + char* str; + Widget wItem = motTreeGetFocusNode(ih); + if (!wItem) + return "0"; /* default VALUE is root */ + + str = iupStrGetMemory(10); + sprintf(str, "%d", motTreeGetNodeId(ih, wItem)); + return str; +} + +static int motTreeSetMarkAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + return 0; + + if(iupStrEqualNoCase(value, "CLEARALL")) + motTreeContainerDeselectAll(ih); + else if(iupStrEqualNoCase(value, "MARKALL")) + motTreeContainerSelectAll(ih); + else if(iupStrEqualNoCase(value, "INVERTALL")) /* INVERTALL *MUST* appear before INVERT, or else INVERTALL will never be called. */ + motTreeInvertAllNodeMarking(ih); + else if(iupStrEqualPartial(value, "INVERT")) + { + unsigned char isSelected; + Widget wItem = motTreeFindNodeFromString(ih, &value[strlen("INVERT")]); + if (!wItem) + return 0; + + XtVaGetValues(wItem, XmNvisualEmphasis, &isSelected, NULL); + if (isSelected == XmSELECTED) + XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); + else + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + } + else if(iupStrEqualNoCase(value, "BLOCK")) + { + Widget wItem = (Widget)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"); + Widget wFocusItem = motTreeGetFocusNode(ih); + if(!wFocusItem || !wItem) + return 0; + motTreeSelectRange(ih, wFocusItem, wItem, 0); + } + else + { + Widget wItem1, wItem2; + char str1[50], str2[50]; + if (iupStrToStrStr(value, str1, str2, '-')!=2) + return 0; + + wItem1 = motTreeFindNodeFromString(ih, str1); + if (!wItem1) + return 0; + wItem2 = motTreeFindNodeFromString(ih, str2); + if (!wItem2) + return 0; + + motTreeSelectRange(ih, wItem1, wItem2, 0); + } + + return 1; +} + +static int motTreeSetValueAttrib(Ihandle* ih, const char* value) +{ + Widget wRoot, wItem; + + if (motTreeSetMarkAttrib(ih, value)) + return 0; + + wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + if (iupStrEqualNoCase(value, "ROOT")) + wItem = wRoot; + else if(iupStrEqualNoCase(value, "LAST")) + wItem = motTreeGetLastVisibleNode(ih, wRoot); + else if(iupStrEqualNoCase(value, "PGUP")) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + if(!wItemFocus) + return 0; + + ih->data->id_control = -1; + motTreeFindVisibleNodeId(ih, &wRoot, 1, wItemFocus); + ih->data->id_control -= 10; /* less 10 visible nodes */ + + if(ih->data->id_control < 0) + ih->data->id_control = 0; /* Begin of tree = Root id */ + + wItem = motTreeFindVisibleNodeFromId(ih, &wRoot, 1); + } + else if(iupStrEqualNoCase(value, "PGDN")) + { + Widget wNext, wItemFocus; + + wItemFocus = motTreeGetFocusNode(ih); + if(!wItemFocus) + return 0; + + ih->data->id_control = -1; + motTreeFindVisibleNodeId(ih, &wRoot, 1, wItemFocus); + ih->data->id_control += 10; /* more 10 visible nodes */ + + wNext = motTreeFindVisibleNodeFromId(ih, &wRoot, 1); + + if (ih->data->id_control >= 0) + wNext = motTreeGetLastVisibleNode(ih, wRoot); + + wItem = wNext; + } + else if(iupStrEqualNoCase(value, "NEXT")) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + if (!wItemFocus) + return 0; + + wItem = motTreeGetNextVisibleNode(ih, wRoot, wItemFocus); + } + else if(iupStrEqualNoCase(value, "PREVIOUS")) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + if(!wItemFocus) + return 0; + + wItem = motTreeGetPreviousVisibleNode(ih, wRoot, wItemFocus); + } + else + wItem = motTreeFindNodeFromString(ih, value); + + if (!wItem) + return 0; + + /* select */ + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + { + /* clear previous selection */ + XtVaSetValues(ih->handle, XmNselectedObjects, NULL, NULL); + XtVaSetValues(ih->handle, XmNselectedObjectCount, 0, NULL); + + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + } + + /* set focus (will scroll to visible) */ + motTreeSetFocusNode(ih, wItem); + + iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", motTreeGetNodeId(ih, wItem)); + + return 0; +} + +static int motTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id) +{ + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)wItem); + + return 1; +} + +static char* motTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) +{ + unsigned char isSelected; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + XtVaGetValues(wItem, XmNvisualEmphasis, &isSelected, NULL); + + if(isSelected == XmSELECTED) + return "YES"; + else + return "NO"; +} + +static int motTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + if (iupStrBoolean(value)) + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + else + XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); + + return 0; +} + +static char* motTreeGetTitle(Widget wItem) +{ + char *title; + XmString itemTitle; + XtVaGetValues(wItem, XmNlabelString, &itemTitle, NULL); + title = iupmotConvertString(itemTitle); + XmStringFree(itemTitle); + return title; +} + +static char* motTreeGetTitleAttrib(Ihandle* ih, const char* name_id) +{ + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + return motTreeGetTitle(wItem); +} + +static int motTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + iupmotSetString(wItem, XmNlabelString, value); + + return 0; +} + +static int motTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + XmFontList fontlist = NULL; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + if (value) + { + char attr[20]; + sprintf(attr, "TITLEFOUNDRY%s", name_id); + fontlist = iupmotGetFontList(iupAttribGet(ih, attr), value); + } + XtVaSetValues(wItem, XmNrenderTable, fontlist, NULL); + + return 0; +} + +static char* motTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id) +{ + XmFontList fontlist; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + XtVaGetValues(wItem, XmNrenderTable, &fontlist, NULL); + return iupmotFindFontList(fontlist); +} + +static char* motTreeGetFindUserDataAttrib(Ihandle* ih, const char* name_id) +{ + int id; + char* str = (char*)(name_id+1); /* skip ':' */ + void* userdata = NULL; + if (sscanf(str, "%p", &userdata)!=1) + return NULL; + id = motTreeGetUserDataId(ih, userdata); + if (id == -1) + return NULL; + str = iupStrGetMemory(16); + sprintf(str, "%d", id); + return str; +} + +static char* motTreeGetUserDataAttrib(Ihandle* ih, const char* name_id) +{ + motTreeItemData *itemData; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + + return itemData->userdata; +} + +static int motTreeSetUserDataAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + motTreeItemData *itemData; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + itemData->userdata = (void*)value; + + return 0; +} + +static int motTreeSetRenameAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->show_rename) + { + IFni cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); + Widget wItemFocus = motTreeGetFocusNode(ih); + if (cbShowRename) + cbShowRename(ih, motTreeGetNodeId(ih, wItemFocus)); + motTreeShowEditField(ih, wItemFocus); + } + else + { + IFnis cbRenameNode = (IFnis)IupGetCallback(ih, "RENAMENODE_CB"); + if (cbRenameNode) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + cbRenameNode(ih, motTreeGetNodeId(ih, wItemFocus), motTreeGetTitle(wItemFocus)); + } + } + + (void)value; + return 0; +} + +static int motTreeSetDelNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + if(iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */ + { + Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + /* the root node can't be deleted */ + if(!wItem || wItem == wRoot) /* root is the unique child */ + return 0; + + /* deleting the specified node (and it's children) */ + motTreeRemoveNode(ih, wItem, 1); + } + else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */ + { + Widget wItem = motTreeFindNodeFromString(ih, name_id); + + if(!wItem) + return 0; + + { + /* deleting the selected node's children only */ + WidgetList wItemList = NULL; + int numChild = XmContainerGetItemChildren(ih->handle, wItem, &wItemList); + if(numChild) + motTreeRemoveChildren(ih, wItemList, numChild, 1); + if (wItemList) XtFree((char*)wItemList); + } + } + else if(iupStrEqualNoCase(value, "MARKED")) /* Delete the array of marked nodes */ + { + WidgetList wSelectedItemList = NULL; + Widget wRoot; + int countItems, i; + + XtVaGetValues(ih->handle, XmNselectedObjects, &wSelectedItemList, + XmNselectedObjectCount, &countItems, NULL); + + wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + for(i = 0; i < countItems; i++) + { + int ok = XmIsIconGadget(wSelectedItemList[i]); + if ((wSelectedItemList[i] != wRoot) && ok) /* the root node can't be deleted */ + motTreeRemoveNode(ih, wSelectedItemList[i], 1); + } + } + + return 0; +} + +static char* motTreeGetIndentationAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(255); + Dimension indent; + XtVaGetValues(ih->handle, XmNoutlineIndentation, &indent, NULL); + sprintf(str, "%d", (int)indent); + return str; +} + +static int motTreeSetIndentationAttrib(Ihandle* ih, const char* value) +{ + int indent; + if (iupStrToInt(value, &indent)) + XtVaSetValues(ih->handle, XmNoutlineIndentation, (Dimension)indent, NULL); + return 0; +} + +static int motTreeSetTopItemAttrib(Ihandle* ih, const char* value) +{ + Widget wItem = motTreeFindNodeFromString(ih, value); + Widget sb_win; + Widget wItemParent; + + if (!wItem) + return 0; + + /* expand all parents */ + XtVaGetValues(wItem, XmNentryParent, &wItemParent, NULL); + while(wItemParent) + { + XtVaSetValues(wItemParent, XmNoutlineState, XmEXPANDED, NULL); + XtVaGetValues(wItemParent, XmNentryParent, &wItemParent, NULL); + } + + sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + XmScrollVisible(sb_win, wItem, 0, 0); + + return 0; +} + +static int motTreeSpacingFunc(Ihandle* ih, Widget wItem, void *data) +{ + XtVaSetValues(wItem, XmNmarginHeight, ih->data->spacing, NULL); + (void)data; + return 1; +} + +static int motTreeSetSpacingAttrib(Ihandle* ih, const char* value) +{ + if (!iupStrToInt(value, &ih->data->spacing)) + ih->data->spacing = 1; + + if (ih->data->spacing < 1) + ih->data->spacing = 1; + + if (ih->handle) + { + motTreeForEach(ih, NULL, (motTreeNodeFunc)motTreeSpacingFunc, 0); + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ +} + +static int motTreeSetExpandAllAttrib(Ihandle* ih, const char* value) +{ + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + if (iupStrBoolean(value)) + motTreeExpandCollapseAllNodes(ih, &wRoot, 1, XmEXPANDED); + else + { + motTreeExpandCollapseAllNodes(ih, &wRoot, 1, XmCOLLAPSED); + + /* The root node is always expanded */ + XtVaSetValues((Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"), XmNoutlineState, XmEXPANDED, NULL); + } + + return 0; +} + +static int motTreeSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + Pixel color; + + /* ignore given value for the scrollbars, must use only from parent */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + color = iupmotColorGetPixelStr(parent_value); + if (color != (Pixel)-1) + { + Widget sb = NULL; + + iupmotSetBgColor(sb_win, color); + + XtVaGetValues(sb_win, XmNverticalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + + XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + } + + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + Widget wRoot; + Widget clipwin = NULL; + + XtVaGetValues(sb_win, XmNclipWindow, &clipwin, NULL); + if (clipwin) iupmotSetBgColor(clipwin, color); + + wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + /* Update all children, starting at root node */ + motTreeUpdateBgColor(ih, &wRoot, 1, color); + } + + iupdrvBaseSetBgColorAttrib(ih, value); /* use given value for contents */ + + /* update internal image cache */ + iupTreeUpdateImages(ih); + + return 1; +} + +static int motTreeSetFgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + XtVaSetValues(ih->handle, XmNforeground, color, NULL); + + return 1; +} + +void iupdrvTreeUpdateMarkMode(Ihandle *ih) +{ + XtVaSetValues(ih->handle, XmNselectionPolicy, (ih->data->mark_mode==ITREE_MARK_SINGLE)? XmSINGLE_SELECT: XmEXTENDED_SELECT, NULL); +} + +/************************************************************************************************/ + + +static void motTreeSetRenameCaretPos(Widget cbEdit, const char* value) +{ + int pos = 1; + + if (iupStrToInt(value, &pos)) + { + if (pos < 1) pos = 1; + pos--; /* IUP starts at 1 */ + + XtVaSetValues(cbEdit, XmNcursorPosition, pos, NULL); + } +} + +static void motTreeSetRenameSelectionPos(Widget cbEdit, const char* value) +{ + int start = 1, end = 1; + + if (iupStrToIntInt(value, &start, &end, ':') != 2) + return; + + if(start < 1 || end < 1) + return; + + start--; /* IUP starts at 1 */ + end--; + + XmTextSetSelection(cbEdit, start, end, CurrentTime); +} + +/*****************************************************************************/ + +static int motTreeCallBranchCloseCb(Ihandle* ih, Widget wItem) +{ + IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB"); + + if(cbBranchClose) + return cbBranchClose(ih, motTreeGetNodeId(ih, wItem)); + + return IUP_DEFAULT; +} + +static int motTreeCallBranchOpenCb(Ihandle* ih, Widget wItem) +{ + IFni cbBranchOpen; + + if (iupAttribGet(ih, "_IUP_IGNORE_BRANCHOPEN")) + { + iupAttribSetStr(ih, "_IUP_IGNORE_BRANCHOPEN", NULL); + return IUP_DEFAULT; + } + + cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB"); + if (cbBranchOpen) + return cbBranchOpen(ih, motTreeGetNodeId(ih, wItem)); + + return IUP_DEFAULT; +} + +static void motTreeCallMultiSelectionCb(Ihandle* ih) +{ + IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTISELECTION_CB"); + IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); + WidgetList wSelectedItemList = NULL; + Widget wRoot; + int countItems; + + wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + XtVaGetValues(ih->handle, XmNselectedObjects, &wSelectedItemList, + XmNselectedObjectCount, &countItems, NULL); + if (countItems == 0) + return; + + if (cbMulti || cbSelec) + { + int* id_rowItem = malloc(sizeof(int) * countItems); + int i = 0; + + for(i = 0; i < countItems; i++) + id_rowItem[i] = motTreeGetNodeId(ih, wSelectedItemList[i]); + + if (cbMulti) + cbMulti(ih, id_rowItem, countItems); + else + { + for (i=0; i<countItems; i++) + cbSelec(ih, id_rowItem[i], 1); + } + + free(id_rowItem); + } +} + +static int motTreeConvertXYToPos(Ihandle* ih, int x, int y) +{ + Widget wItem = XmObjectAtPoint(ih->handle, (Position)x, (Position)y); + if (wItem) + return motTreeGetNodeId(ih, wItem); + return -1; +} + +static void motTreeCallRightClickCb(Ihandle* ih, int x, int y) +{ + IFni cbRightClick = (IFni)IupGetCallback(ih, "RIGHTCLICK_CB"); + if (cbRightClick) + { + int id = motTreeConvertXYToPos(ih, x, y); + if (id != -1) + cbRightClick(ih, id); + } +} + +static void motTreeCallRenameCb(Ihandle* ih) +{ + IFnis cbRename; + Widget wItem, wEdit; + int ignore = 0; + String title = NULL; + + wItem = (Widget)iupAttribGet(ih, "_IUPTREE_SELECTED"); + wEdit = (Widget)iupAttribGet(ih, "_IUPTREE_EDITFIELD"); + + XtVaGetValues((Widget)iupAttribGet(ih, "_IUPTREE_EDITFIELD"), XmNvalue, &title, NULL); + + cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB"); + if (cbRename) + { + if (cbRename(ih, motTreeGetNodeId(ih, wItem), title) == IUP_IGNORE) + ignore = 1; + } + + if (!ignore) + iupmotSetString(wItem, XmNlabelString, title); + + XtDestroyWidget(wEdit); + + iupAttribSetStr(ih, "_IUPTREE_EDITFIELD", NULL); + iupAttribSetStr(ih, "_IUPTREE_SELECTED", NULL); +} + +static int motTreeCallDragDropCb(Ihandle* ih, Widget wItemDrag, Widget wItemDrop, int *is_ctrl) +{ + IFniiii cbDragDrop = (IFniiii)IupGetCallback(ih, "DRAGDROP_CB"); + int is_shift = 0; + char key[5]; + iupdrvGetKeyState(key); + if (key[0] == 'S') + is_shift = 1; + if (key[1] == 'C') + *is_ctrl = 1; + else + *is_ctrl = 0; + + if (cbDragDrop) + { + int drag_id = motTreeGetNodeId(ih, wItemDrag); + int drop_id = motTreeGetNodeId(ih, wItemDrop); + return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl); + } + + return IUP_CONTINUE; /* allow to move by default if callback not defined */ +} + +static void motTreeEditFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + if (evt->type == FocusOut) + motTreeCallRenameCb(ih); + + (void)cont; + (void)w; +} + +static void motTreeEditKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean *cont) +{ + KeySym motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + if (motcode == XK_Return) + { + Widget wItem = (Widget)iupAttribGet(ih, "_IUPTREE_SELECTED"); + motTreeCallRenameCb(ih); + motTreeSetFocusNode(ih, wItem); + } + else if (motcode == XK_Escape) + { + Widget wEdit = (Widget)iupAttribGet(ih, "_IUPTREE_EDITFIELD"); + Widget wItem = (Widget)iupAttribGet(ih, "_IUPTREE_SELECTED"); + + XtDestroyWidget(wEdit); + motTreeSetFocusNode(ih, wItem); + + iupAttribSetStr(ih, "_IUPTREE_EDITFIELD", NULL); + iupAttribSetStr(ih, "_IUPTREE_SELECTED", NULL); + } + + (void)cont; + (void)w; +} + +static void motTreeScrollbarOffset(Widget sb_win, Position *x, Position *y) +{ + Widget sb_horiz, sb_vert; + XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb_horiz, NULL); + if (sb_horiz) + { + int pos; + XtVaGetValues(sb_horiz, XmNvalue, &pos, NULL); + *x = *x - (Position)pos; + } + XtVaGetValues(sb_win, XmNverticalScrollBar, &sb_vert, NULL); + if (sb_vert) + { + int pos; + XtVaGetValues(sb_vert, XmNvalue, &pos, NULL); + *y = *y - (Position)pos; + } +} + +static void motTreeShowEditField(Ihandle* ih, Widget wItem) +{ + int num_args = 0, w_img = 0; + Arg args[30]; + Position x, y; + Dimension w, h; + char* child_id = iupDialogGetChildIdStr(ih); + Widget cbEdit; + XmString title; + char* value; + Pixel color; + Pixmap image = XmUNSPECIFIED_PIXMAP; + XmFontList fontlist; + Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + + XtVaGetValues(wItem, XmNx, &x, + XmNy, &y, + XmNwidth, &w, + XmNheight, &h, + XmNlabelString, &title, + XmNsmallIconPixmap, &image, + XmNforeground, &color, + XmNrenderTable, &fontlist, + NULL); + + motTreeScrollbarOffset(sb_win, &x, &y); + iupdrvImageGetInfo((void*)image, &w_img, NULL, NULL); + w_img += 3; /* add some room for borders */ + + iupmotSetArg(args, num_args, XmNx, x+w_img); /* x-position */ + iupmotSetArg(args, num_args, XmNy, y); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, w-w_img); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, h); /* default height to avoid 0 */ + iupmotSetArg(args, num_args, XmNmarginHeight, ih->data->spacing); /* default padding */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNforeground, color); + iupmotSetArg(args, num_args, XmNrenderTable, fontlist); + iupmotSetArg(args, num_args, XmNvalue, iupmotConvertString(title)); + iupmotSetArg(args, num_args, XmNtraversalOn, True); + + cbEdit = XtCreateManagedWidget( + child_id, /* child identifier */ + xmTextWidgetClass, /* widget class */ + sb_win, + args, num_args); + + /* Disable Drag Source */ + iupmotDisableDragSource(cbEdit); + + XtAddEventHandler(cbEdit, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(cbEdit, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(cbEdit, FocusChangeMask, False, (XtEventHandler)motTreeEditFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(cbEdit, KeyPressMask, False, (XtEventHandler)motTreeEditKeyPressEvent, (XtPointer)ih); + + iupAttribSetStr(ih, "_IUPTREE_SELECTED", (char*)wItem); + iupAttribSetStr(ih, "_IUPTREE_EDITFIELD", (char*)cbEdit); + + XmProcessTraversal(cbEdit, XmTRAVERSE_CURRENT); + + XmTextSetSelection(cbEdit, (XmTextPosition)0, (XmTextPosition)XmTextGetLastPosition(cbEdit), CurrentTime); + + value = iupAttribGetStr(ih, "RENAMECARET"); + if (value) + motTreeSetRenameCaretPos(cbEdit, value); + + value = iupAttribGetStr(ih, "RENAMESELECTION"); + if (value) + motTreeSetRenameSelectionPos(cbEdit, value); + + /* the parents callbacks can be called while editing + so we must avoid their processing if _IUPTREE_EDITFIELD is defined. */ +} + +static void motTreeSelectionCallback(Widget w, Ihandle* ih, XmContainerSelectCallbackStruct *nptr) +{ + IFnii cbSelec; + int is_ctrl = 0; + (void)w; + (void)nptr; + +printf("SelectionCallback(%d)\n", nptr->selected_item_count); + + if (ih->data->mark_mode == ITREE_MARK_MULTIPLE) + { + char key[5]; + iupdrvGetKeyState(key); + if (key[0] == 'S') + return; + else if (key[1] == 'C') + is_ctrl = 1; + + if (nptr->selected_item_count>1 && !is_ctrl) + { + if (IupGetCallback(ih, "MULTISELECTION_CB")) + { + if (nptr->auto_selection_type==XmAUTO_NO_CHANGE) + motTreeCallMultiSelectionCb(ih); + } + else + { + if (nptr->auto_selection_type==XmAUTO_MOTION) + motTreeCallMultiSelectionCb(ih); + } + return; + } + } + + cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); + if (cbSelec) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + int curpos = motTreeGetNodeId(ih, wItemFocus); + if (is_ctrl) + { + unsigned char isSelected; + XtVaGetValues(wItemFocus, XmNvisualEmphasis, &isSelected, NULL); + cbSelec(ih, curpos, isSelected == XmSELECTED? 1: 0); + } + else + { + int oldpos = iupAttribGetInt(ih, "_IUPTREE_OLDVALUE"); + if (oldpos != curpos) + { + cbSelec(ih, oldpos, 0); /* unselected */ + cbSelec(ih, curpos, 1); /* selected */ + + iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", curpos); + } + } + } +} + +static void motTreeDefaultActionCallback(Widget w, Ihandle* ih, XmContainerSelectCallbackStruct *nptr) +{ + unsigned char itemState; + WidgetList wSelectedItemList = NULL; + int countItems; + motTreeItemData *itemData; + Widget wItem; + (void)w; + + wSelectedItemList = nptr->selected_items; + countItems = nptr->selected_item_count; + + if (!countItems || (Widget)iupAttribGet(ih, "_IUPTREE_EDITFIELD")) + return; + + /* this works also when using multiple selection */ + wItem = wSelectedItemList[0]; + + XtVaGetValues(wItem, XmNoutlineState, &itemState, + XmNuserData, &itemData, NULL); + + if (itemData->kind == ITREE_BRANCH) + { + if (itemState == XmEXPANDED) + XtVaSetValues(wItem, XmNoutlineState, XmCOLLAPSED, NULL); + else + XtVaSetValues(wItem, XmNoutlineState, XmEXPANDED, NULL); + } + else + { + IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB"); + if (cbExecuteLeaf) + cbExecuteLeaf(ih, motTreeGetNodeId(ih, wItem)); + } +} + +static void motTreeOutlineChangedCallback(Widget w, Ihandle* ih, XmContainerOutlineCallbackStruct *nptr) +{ + motTreeItemData *itemData; + XtVaGetValues(nptr->item, XmNuserData, &itemData, NULL); + + if (nptr->reason == XmCR_EXPANDED) + { + if (motTreeCallBranchOpenCb(ih, nptr->item) == IUP_IGNORE) + nptr->new_outline_state = XmCOLLAPSED; /* prevent the change */ + else + { + XtVaSetValues(nptr->item, XmNsmallIconPixmap, (itemData->image_expanded!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded: (Pixmap)ih->data->def_image_expanded, NULL); + XtVaSetValues(nptr->item, XmNsmallIconMask, (itemData->image_expanded_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded_mask: (Pixmap)ih->data->def_image_expanded_mask, NULL); + } + } + else if (nptr->reason == XmCR_COLLAPSED) + { + if (motTreeCallBranchCloseCb(ih, nptr->item) == IUP_IGNORE) + nptr->new_outline_state = XmEXPANDED; /* prevent the change */ + else + { + XtVaSetValues(nptr->item, XmNsmallIconPixmap, (itemData->image!=XmUNSPECIFIED_PIXMAP)? itemData->image: (Pixmap)ih->data->def_image_collapsed, NULL); + XtVaSetValues(nptr->item, XmNsmallIconMask, (itemData->image_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_mask: (Pixmap)ih->data->def_image_collapsed_mask, NULL); + } + } + + (void)w; +} + +static void motTreeTraverseObscuredCallback(Widget widget, Ihandle* ih, XmTraverseObscuredCallbackStruct *cbs) +{ + (void)ih; + /* allow to do automatic scroll when navigating in the tree */ + XmScrollVisible(widget, cbs->traversal_destination, 10, 10); +} + +static void motTreeKeyReleaseEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean *cont) +{ + KeySym motcode; + + if (iupAttribGet(ih, "_IUPTREE_EDITFIELD")) + return; + + motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + if (motcode == XK_Down || motcode == XK_U || motcode == XK_Home || motcode == XK_End) + { + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && (evt->state & ShiftMask)) + motTreeCallMultiSelectionCb(ih); + } + + (void)w; + (void)cont; +} + +static void motTreeKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean *cont) +{ + KeySym motcode; + + if (iupAttribGet(ih, "_IUPTREE_EDITFIELD")) + return; + + *cont = True; + iupmotKeyPressEvent(w, ih, (XEvent*)evt, cont); + if (*cont == False) + return; + + motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + if (motcode == XK_F2) + motTreeSetRenameAttrib(ih, NULL); + else if (motcode == XK_F1) + iupmotHelpCallback(w, ih, NULL); + else if ((motcode == XK_Down || motcode == XK_Up) && (evt->state & ControlMask)) + { + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + Widget wItem; + Widget wItemFocus = motTreeGetFocusNode(ih); + + /* Ctrl+Arrows move only focus */ + if (motcode == XK_Down) + wItem = motTreeGetNextVisibleNode(ih, wRoot, wItemFocus); + else + wItem = motTreeGetPreviousVisibleNode(ih, wRoot, wItemFocus); + + motTreeSetFocusNode(ih, wItem); + *cont = False; + } + else if(motcode == XK_Home || motcode == XK_End) + { + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + Widget wItem; + + /* Not processed by Motif */ + + if (motcode == XK_Home) + wItem = wRoot; + else + wItem = motTreeGetLastVisibleNode(ih, wRoot); + + /* Ctrl+Arrows move only focus */ + if (!(evt->state & ControlMask)) + { + /* Shift+Arrows select block */ + if (evt->state & ShiftMask) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + if (!wItemFocus) + return; + motTreeSelectRange(ih, wItemFocus, wItem, 1); + } + else + { + /* clear previous selection */ + XtVaSetValues(ih->handle, XmNselectedObjects, NULL, NULL); + XtVaSetValues(ih->handle, XmNselectedObjectCount, 0, NULL); + + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + } + } + + motTreeSetFocusNode(ih, wItem); + *cont = False; + } + else if(motcode == XK_space && (evt->state & ControlMask)) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + if (wItemFocus) + { + unsigned char isSelected; + XtVaGetValues(wItemFocus, XmNvisualEmphasis, &isSelected, NULL); + if (isSelected == XmSELECTED) + XtVaSetValues(wItemFocus, XmNvisualEmphasis, XmNOT_SELECTED, NULL); + else + XtVaSetValues(wItemFocus, XmNvisualEmphasis, XmSELECTED, NULL); + } + } +} + +static void motTreeButtonEvent(Widget w, Ihandle* ih, XButtonEvent* evt, Boolean* cont) +{ + (void)w; + (void)cont; + + if (iupAttribGet(ih, "_IUPTREE_EDITFIELD")) + return; + + *cont = True; + iupmotButtonPressReleaseEvent(w, ih, (XEvent*)evt, cont); + if (*cont == False) + return; + + if (evt->type==ButtonPress) + { + iupAttribSetStr(ih, "_IUPTREE_IGNORE_ENTERLEAVE", "1"); + + if (evt->button==Button1) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + static Widget wLastItem = NULL; + static Time last = 0; + int clicktwice = 0, doubleclicktime = XtGetMultiClickTime(iupmot_display); + int elapsed = (int)(evt->time - last); + last = evt->time; + + /* stay away from double click and leave some room for clicks */ + if (elapsed > (3*doubleclicktime)/2 && elapsed <= 3*doubleclicktime) + clicktwice = 1; + + if (clicktwice && wLastItem && wLastItem==wItemFocus) + { + motTreeSetRenameAttrib(ih, NULL); + *cont = False; + } + wLastItem = wItemFocus; + } + else if (evt->button==Button3) + motTreeCallRightClickCb(ih, evt->x, evt->y); + } + else if (evt->type==ButtonRelease) + { + if (evt->button==Button1) + { + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && (evt->state & ShiftMask)) + motTreeCallMultiSelectionCb(ih); + } + } +} + +static void motTreeTransferProc(Widget drop_context, XtPointer client_data, Atom *seltype, Atom *type, XtPointer value, unsigned long *length, int format) +{ + Atom atomTreeItem = XInternAtom(iupmot_display, "TREE_ITEM", False); + Widget wItemDrop = (Widget)client_data; + Widget wItemDrag = (Widget)value; + + if (*type == atomTreeItem) + { + Widget wParent; + Ihandle* ih = NULL; + int is_ctrl; + + if (!wItemDrop || wItemDrag == wItemDrop) + return; + + wParent = wItemDrop; + while(wParent) + { + XtVaGetValues(wParent, XmNentryParent, &wParent, NULL); + if (wParent == wItemDrag) + return; + } + + XtVaGetValues(XtParent(wItemDrag), XmNuserData, &ih, NULL); + + if (motTreeCallDragDropCb(ih, wItemDrag, wItemDrop, &is_ctrl) == IUP_CONTINUE) + { + /* Copy the dragged item to the new position. */ + Widget wNewItem = motTreeCopyNode(ih, wItemDrag, wItemDrop, is_ctrl); + + if (!is_ctrl) + { + /* do not delete the user data, we copy the references in CopyNode */ + motTreeRemoveNode(ih, wItemDrag, 0); + } + + /* Select the dragged item */ + XtVaSetValues(ih->handle, XmNselectedObjects, NULL, NULL); + XtVaSetValues(ih->handle, XmNselectedObjectCount, 0, NULL); + XtVaSetValues(wNewItem, XmNvisualEmphasis, XmSELECTED, NULL); + + motTreeSetFocusNode(ih, wNewItem); + } + } + + (void)drop_context; + (void)seltype; + (void)format; + (void)length; +} + +static void motTreeDropProc(Widget w, XtPointer client_data, XmDropProcCallbackStruct* drop_data) +{ + Atom atomTreeItem = XInternAtom(iupmot_display, "TREE_ITEM", False); + XmDropTransferEntryRec transferList[2]; + Arg args[10]; + int i, num_args = 0; + Widget wItemDrop, drop_context; + Cardinal numExportTargets; + Atom *exportTargets; + Boolean found = False; + (void)client_data; + + drop_context = drop_data->dragContext; + + /* retrieve the data targets */ + iupmotSetArg(args, num_args, XmNexportTargets, &exportTargets); + iupmotSetArg(args, num_args, XmNnumExportTargets, &numExportTargets); + XtGetValues(drop_context, args, num_args); + + for (i = 0; i < (int)numExportTargets; i++) + { + if (exportTargets[i] == atomTreeItem) + { + found = True; + break; + } + } + + wItemDrop = XmObjectAtPoint(w, drop_data->x, drop_data->y); + if (!wItemDrop) + found = False; + + num_args = 0; + if ((!found) || (drop_data->dropAction != XmDROP) || (drop_data->operation != XmDROP_COPY && drop_data->operation != XmDROP_MOVE)) + { + iupmotSetArg(args, num_args, XmNtransferStatus, XmTRANSFER_FAILURE); + iupmotSetArg(args, num_args, XmNnumDropTransfers, 0); + } + else + { + /* set up transfer requests for drop site */ + transferList[0].target = atomTreeItem; + transferList[0].client_data = (XtPointer)wItemDrop; + iupmotSetArg(args, num_args, XmNdropTransfers, transferList); + iupmotSetArg(args, num_args, XmNnumDropTransfers, 1); + iupmotSetArg(args, num_args, XmNtransferProc, motTreeTransferProc); + } + + XmDropTransferStart(drop_context, args, num_args); +} + +static void motTreeDragDropFinishCallback(Widget drop_context, XtPointer client_data, XtPointer call_data) +{ + Widget source_icon = NULL; + XtVaGetValues(drop_context, XmNsourceCursorIcon, &source_icon, NULL); + if (source_icon) + XtDestroyWidget(source_icon); + (void)call_data; + (void)client_data; +} + +static void motTreeDragMotionCallback(Widget drop_context, Widget wItemDrag, XmDragMotionCallbackStruct* drag_motion) +{ + Ihandle* ih = NULL; + XtVaGetValues(XtParent(wItemDrag), XmNuserData, &ih, NULL); + if (!iupAttribGet(ih, "NODRAGFEEDBACK")) + { + Widget wItem; + int x = drag_motion->x; + int y = drag_motion->y; + iupdrvScreenToClient(ih, &x, &y); + wItem = XmObjectAtPoint(ih->handle, (Position)x, (Position)y); + if (wItem) + { + XtVaSetValues(ih->handle, XmNselectedObjects, NULL, NULL); + XtVaSetValues(ih->handle, XmNselectedObjectCount, 0, NULL); + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + } + } + (void)drop_context; +} + +static Boolean motTreeConvertProc(Widget drop_context, Atom *selection, Atom *target, Atom *type_return, + XtPointer *value_return, unsigned long *length_return, int *format_return) +{ + Atom atomMotifDrop = XInternAtom(iupmot_display, "_MOTIF_DROP", False); + Atom atomTreeItem = XInternAtom(iupmot_display, "TREE_ITEM", False); + Widget wItemDrag = NULL; + + /* check if we are dealing with a drop */ + if (*selection != atomMotifDrop || *target != atomTreeItem) + return False; + + XtVaGetValues(drop_context, XmNclientData, &wItemDrag, NULL); + if (!wItemDrag) + return False; + + /* format the value for transfer */ + *type_return = atomTreeItem; + *value_return = (XtPointer)wItemDrag; + *length_return = 1; + *format_return = 32; + return True; +} + +static void motTreeStartDrag(Widget w, XButtonEvent* evt, String* params, Cardinal* num_params) +{ + Atom atomTreeItem = XInternAtom(iupmot_display, "TREE_ITEM", False); + Atom exportList[1]; + Widget drag_icon, drop_context; + Pixmap pixmap = 0, mask = 0; + int num_args = 0; + Arg args[40]; + Pixel fg, bg; + Widget wItemDrag = XmObjectAtPoint(w, (Position)evt->x, (Position)evt->y); + if (!wItemDrag) + return; + + XtVaGetValues(wItemDrag, XmNsmallIconPixmap, &pixmap, + XmNsmallIconMask, &mask, + XmNbackground, &bg, + XmNforeground, &fg, + NULL); + + iupmotSetArg(args, num_args, XmNpixmap, pixmap); + iupmotSetArg(args, num_args, XmNmask, mask); + drag_icon = XmCreateDragIcon(w, "drag_icon", args, num_args); + + exportList[0] = atomTreeItem; + + /* specify resources for DragContext for the transfer */ + num_args = 0; + iupmotSetArg(args, num_args, XmNcursorBackground, bg); + iupmotSetArg(args, num_args, XmNcursorForeground, fg); + /* iupmotSetArg(args, num_args, XmNsourcePixmapIcon, drag_icon); works, but only outside the dialog, inside disapears */ + iupmotSetArg(args, num_args, XmNsourceCursorIcon, drag_icon); /* does not work, shows the default cursor */ + iupmotSetArg(args, num_args, XmNexportTargets, exportList); + iupmotSetArg(args, num_args, XmNnumExportTargets, 1); + iupmotSetArg(args, num_args, XmNdragOperations, XmDROP_MOVE|XmDROP_COPY); + iupmotSetArg(args, num_args, XmNconvertProc, motTreeConvertProc); + iupmotSetArg(args, num_args, XmNclientData, wItemDrag); + + /* start the drag and register a callback to clean up when done */ + drop_context = XmDragStart(w, (XEvent*)evt, args, num_args); + XtAddCallback(drop_context, XmNdragDropFinishCallback, (XtCallbackProc)motTreeDragDropFinishCallback, NULL); + XtAddCallback(drop_context, XmNdragMotionCallback, (XtCallbackProc)motTreeDragMotionCallback, (XtPointer)wItemDrag); + + (void)params; + (void)num_params; +} + +static void motTreeEnableDragDrop(Widget w) +{ + Atom atomTreeItem = XInternAtom(iupmot_display, "TREE_ITEM", False); + Atom importList[1]; + Arg args[40]; + int num_args = 0; + char dragTranslations[] = "#override <Btn2Down>: StartDrag()"; + static int do_rec = 0; + if (!do_rec) + { + XtActionsRec rec = {"StartDrag", (XtActionProc)motTreeStartDrag}; + XtAppAddActions(iupmot_appcontext, &rec, 1); + do_rec = 1; + } + XtOverrideTranslations(w, XtParseTranslationTable(dragTranslations)); + + importList[0] = atomTreeItem; + iupmotSetArg(args, num_args, XmNimportTargets, importList); + iupmotSetArg(args, num_args, XmNnumImportTargets, 1); + iupmotSetArg(args, num_args, XmNdropSiteOperations, XmDROP_MOVE|XmDROP_COPY); + iupmotSetArg(args, num_args, XmNdropProc, motTreeDropProc); + XmDropSiteUpdate(w, args, num_args); + + XtVaSetValues(XmGetXmDisplay(iupmot_display), XmNenableDragIcon, True, NULL); +} + +static int motTreeMapMethod(Ihandle* ih) +{ + int num_args = 0; + Arg args[40]; + Widget parent = iupChildTreeGetNativeParentHandle(ih); + char* child_id = iupDialogGetChildIdStr(ih); + Widget sb_win; + + /******************************/ + /* Create the scrolled window */ + /******************************/ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAUTOMATIC); + iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE); + iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmAS_NEEDED); + iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ + iupmotSetArg(args, num_args, XmNborderWidth, 0); + iupmotSetArg(args, num_args, XmNshadowThickness, 2); + + sb_win = XtCreateManagedWidget( + child_id, /* child identifier */ + xmScrolledWindowWidgetClass, /* widget class */ + parent, /* widget parent */ + args, num_args); + + if (!sb_win) + return IUP_ERROR; + + XtAddCallback (sb_win, XmNtraverseObscuredCallback, (XtCallbackProc)motTreeTraverseObscuredCallback, (XtPointer)ih); + + parent = sb_win; + child_id = "container"; + + num_args = 0; + + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupmotSetArg(args, num_args, XmNhighlightThickness, 2); + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + + iupmotSetArg(args, num_args, XmNlayoutType, XmOUTLINE); + iupmotSetArg(args, num_args, XmNentryViewType, XmSMALL_ICON); + iupmotSetArg(args, num_args, XmNselectionPolicy, XmSINGLE_SELECT); + iupmotSetArg(args, num_args, XmNoutlineIndentation, 20); + + if (iupAttribGetBoolean(ih, "HIDELINES")) + iupmotSetArg(args, num_args, XmNoutlineLineStyle, XmNO_LINE); + else + iupmotSetArg(args, num_args, XmNoutlineLineStyle, XmSINGLE); + + if (iupAttribGetBoolean(ih, "HIDEBUTTONS")) + iupmotSetArg(args, num_args, XmNoutlineButtonPolicy, XmOUTLINE_BUTTON_ABSENT); + else + iupmotSetArg(args, num_args, XmNoutlineButtonPolicy, XmOUTLINE_BUTTON_PRESENT); + + ih->handle = XtCreateManagedWidget( + child_id, /* child identifier */ + xmContainerWidgetClass, /* widget class */ + parent, /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)parent); + + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)motTreeEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)motTreeEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)motTreeFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)motTreeKeyPressEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyReleaseMask, False, (XtEventHandler)motTreeKeyReleaseEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)motTreeButtonEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, PointerMotionMask, False, (XtEventHandler)iupmotPointerMotionEvent, (XtPointer)ih); + + /* Callbacks */ + /* XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); NOT WORKING */ + XtAddCallback(ih->handle, XmNoutlineChangedCallback, (XtCallbackProc)motTreeOutlineChangedCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNdefaultActionCallback, (XtCallbackProc)motTreeDefaultActionCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motTreeSelectionCallback, (XtPointer)ih); + + XtRealizeWidget(parent); + + if (ih->data->show_dragdrop) + { + motTreeEnableDragDrop(ih->handle); + XtVaSetValues(ih->handle, XmNuserData, ih, NULL); /* to be used in motTreeTransferProc */ + } + else + iupmotDisableDragSource(ih->handle); + + /* Force background update before setting the images */ + { + char* value = iupAttribGet(ih, "BGCOLOR"); + if (value) + { + motTreeSetBgColorAttrib(ih, value); + iupAttribSetStr(ih, "BGCOLOR", NULL); + } + } + + /* Initialize the default images */ + ih->data->def_image_leaf = iupImageGetImage("IMGLEAF", ih, 0); + if (!ih->data->def_image_leaf) + { + ih->data->def_image_leaf = (void*)XmUNSPECIFIED_PIXMAP; + ih->data->def_image_leaf_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + else + { + ih->data->def_image_leaf_mask = iupImageGetMask("IMGLEAF"); + if (!ih->data->def_image_leaf_mask) ih->data->def_image_leaf_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + + ih->data->def_image_collapsed = iupImageGetImage("IMGCOLLAPSED", ih, 0); + if (!ih->data->def_image_collapsed) + { + ih->data->def_image_collapsed = (void*)XmUNSPECIFIED_PIXMAP; + ih->data->def_image_collapsed_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + else + { + ih->data->def_image_collapsed_mask = iupImageGetMask("IMGCOLLAPSED"); + if (!ih->data->def_image_collapsed_mask) ih->data->def_image_collapsed_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + + ih->data->def_image_expanded = iupImageGetImage("IMGEXPANDED", ih, 0); + if (!ih->data->def_image_expanded) + { + ih->data->def_image_expanded = (void*)XmUNSPECIFIED_PIXMAP; + ih->data->def_image_expanded_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + else + { + ih->data->def_image_expanded_mask = iupImageGetMask("IMGEXPANDED"); + if (!ih->data->def_image_expanded_mask) ih->data->def_image_expanded_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + + motTreeAddRootNode(ih); + + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)motTreeConvertXYToPos); + + return IUP_NOERROR; +} + +void iupdrvTreeInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motTreeMapMethod; + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motTreeSetBgColorAttrib, "TXTBGCOLOR", NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, motTreeSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT); + + /* IupTree Attributes - GENERAL */ + iupClassRegisterAttribute(ic, "EXPANDALL", NULL, motTreeSetExpandAllAttrib, NULL, NULL, IUPAF_WRITEONLY||IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INDENTATION", motTreeGetIndentationAttrib, motTreeSetIndentationAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "COUNT", motTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPACING", iupTreeGetSpacingAttrib, motTreeSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "TOPITEM", NULL, motTreeSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + + /* IupTree Attributes - IMAGES */ + iupClassRegisterAttributeId(ic, "IMAGE", NULL, motTreeSetImageAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "IMAGEEXPANDED", NULL, motTreeSetImageExpandedAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "IMAGELEAF", NULL, motTreeSetImageLeafAttrib, IUPAF_SAMEASSYSTEM, "IMGLEAF", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGEBRANCHCOLLAPSED", NULL, motTreeSetImageBranchCollapsedAttrib, IUPAF_SAMEASSYSTEM, "IMGCOLLAPSED", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGEBRANCHEXPANDED", NULL, motTreeSetImageBranchExpandedAttrib, IUPAF_SAMEASSYSTEM, "IMGEXPANDED", IUPAF_NO_INHERIT); + + /* IupTree Attributes - NODES */ + iupClassRegisterAttributeId(ic, "STATE", motTreeGetStateAttrib, motTreeSetStateAttrib, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "DEPTH", motTreeGetDepthAttrib, NULL, IUPAF_READONLY|IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "KIND", motTreeGetKindAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "PARENT", motTreeGetParentAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "COLOR", motTreeGetColorAttrib, motTreeSetColorAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "NAME", motTreeGetTitleAttrib, motTreeSetTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLE", motTreeGetTitleAttrib, motTreeSetTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "USERDATA", motTreeGetUserDataAttrib, motTreeSetUserDataAttrib, IUPAF_NO_STRING|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "CHILDCOUNT", motTreeGetChildCountAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLEFONT", motTreeGetTitleFontAttrib, motTreeSetTitleFontAttrib, IUPAF_NO_INHERIT); + + /* IupTree Attributes - MARKS */ + iupClassRegisterAttributeId(ic, "MARKED", motTreeGetMarkedAttrib, motTreeSetMarkedAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARK", NULL, motTreeSetMarkAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "STARTING", NULL, motTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARKSTART", NULL, motTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute (ic, "VALUE", motTreeGetValueAttrib, motTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupTree Attributes - ACTION */ + iupClassRegisterAttributeId(ic, "DELNODE", NULL, motTreeSetDelNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "RENAME", NULL, motTreeSetRenameAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "MOVENODE", NULL, motTreeSetMoveNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "COPYNODE", NULL, motTreeSetCopyNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "FINDUSERDATA", motTreeGetFindUserDataAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); +} diff --git a/iup/src/mot/iupmot_val.c b/iup/src/mot/iupmot_val.c new file mode 100755 index 0000000..200d2b4 --- /dev/null +++ b/iup/src/mot/iupmot_val.c @@ -0,0 +1,488 @@ +/** \file + * \brief Valuator Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/Scale.h> +#include <Xm/SeparatoG.h> +#include <X11/keysym.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_val.h" +#include "iup_image.h" +#include "iup_drv.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +void iupdrvValGetMinSize(Ihandle* ih, int *w, int *h) +{ + int ticks_size = 0; + if (iupAttribGetInt(ih, "SHOWTICKS")) + ticks_size = 8; + + if (ih->data->type == IVAL_HORIZONTAL) + { + *w = 30; + *h = 20+ticks_size; + } + else + { + *w = 20+ticks_size; + *h = 30; + } +} + +static void motValRemoveOldTicks(Widget scale) +{ + WidgetList children = (WidgetList)0; + Cardinal num_children = (Cardinal)0; + Cardinal i; + String name; + + XtVaGetValues(scale, XmNchildren, &children, + XmNnumChildren, &num_children, + NULL); + + for (i = 0; i < num_children; i++) + { + if (XmIsSeparatorGadget(children[i])) + { + if ((name = XtName(children[i])) != (String)0) + { + if ((strcmp(name, "BigTic") == 0) || + (strcmp(name, "MedTic") == 0) || + (strcmp(name, "SmallTic") == 0)) + { + XtDestroyWidget(children[i]); + } + } + } + } +} + +static int motValSetShowTicksAttrib(Ihandle* ih, const char* value) +{ + int tick_freq, show_ticks; + + if (!ih->data->show_ticks) /* can only set if already not zero */ + return 0; + + show_ticks = atoi(value); + if (show_ticks<2) show_ticks=2; + ih->data->show_ticks = show_ticks; + + motValRemoveOldTicks(ih->handle); + + /* Defines the interval frequency for tick marks */ + tick_freq = SHRT_MAX/(show_ticks-1); + XmScaleSetTicks(ih->handle, tick_freq, 0, 0, 8, 0, 0); + return 0; +} + +static int motValSetPageStepAttrib(Ihandle* ih, const char* value) +{ + int pagesize; + ih->data->pagestep = atof(value); + pagesize = (int)(ih->data->pagestep*SHRT_MAX); + XtVaSetValues(ih->handle, XmNscaleMultiple, pagesize, NULL); + return 0; /* do not store value in hash table */ +} + +static int motValSetStepAttrib(Ihandle* ih, const char* value) +{ + ih->data->step = atof(value); + return 0; /* do not store value in hash table */ +} + +static int motValSetValueAttrib(Ihandle* ih, const char* value) +{ + int ival; + + ih->data->val = atof(value); + iupValCropValue(ih); + + ival = (int)(((ih->data->val-ih->data->vmin)/(ih->data->vmax - ih->data->vmin))*SHRT_MAX); + XtVaSetValues(ih->handle, XmNvalue, ival, NULL); + + return 0; /* do not store value in hash table */ +} + +static int motValSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color; + unsigned char r, g, b; + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + r = (r*8)/10; + g = (g*8)/10; + b = (b*8)/10; + + color = iupmotColorGetPixel(r, g, b); + if (color != (Pixel)-1) + { + Widget w = XtNameToWidget(ih->handle, "*Scrollbar"); + XtVaSetValues(w, XmNtroughColor, color, NULL); + } + + return iupdrvBaseSetBgColorAttrib(ih, value); +} + +static int motValSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + Pixel color; + + /* ignore given value, must use only from parent */ + value = iupAttribGetInheritNativeParent(ih, "BACKGROUND"); + + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + XtVaSetValues(ih->handle, XmNbackground, color, NULL); + return 1; + } + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + if (pixmap) + { + XtVaSetValues(ih->handle, XmNbackgroundPixmap, pixmap, NULL); + return 1; + } + } + return 0; +} + + +/*********************************************************************************************/ + + +static void motValCallAction(Ihandle* ih, int ival, int cb_state) +{ + double old_val = ih->data->val; + IFn cb; + + ih->data->val = (((double)ival/(double)SHRT_MAX)*(ih->data->vmax - ih->data->vmin)) + ih->data->vmin; + iupValCropValue(ih); + + cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB"); + if (cb) + { + if (ih->data->val == old_val) + return; + + cb(ih); + } + else + { + IFnd cb_old; + if (cb_state == 0) + cb_old = (IFnd) IupGetCallback(ih, "MOUSEMOVE_CB"); + else if (cb_state == -1) + cb_old = (IFnd) IupGetCallback(ih, "BUTTON_RELEASE_CB"); + else + cb_old = (IFnd) IupGetCallback(ih, "BUTTON_PRESS_CB"); + + if (cb_old) + cb_old(ih, ih->data->val); + } +} + +static void motValIncPageValue(Ihandle *ih, int dir) +{ + int pagesize, ival; + pagesize = (int)(ih->data->pagestep*SHRT_MAX); + + if (ih->data->inverted) + dir *= -1; + + XtVaGetValues(ih->handle, XmNvalue, &ival, NULL); + ival += dir*pagesize; + if (ival < 0) ival = 0; + if (ival > SHRT_MAX) ival = SHRT_MAX; + XtVaSetValues(ih->handle, XmNvalue, ival, NULL); + + motValCallAction(ih, ival, 1); +} + +static void motValIncLineValue(Ihandle *ih, int dir) +{ + int linesize, ival; + linesize = (int)(ih->data->step*SHRT_MAX); + + if (ih->data->inverted) + dir *= -1; + + XtVaGetValues(ih->handle, XmNvalue, &ival, NULL); + ival += dir*linesize; + if (ival < 0) ival = 0; + if (ival > SHRT_MAX) ival = SHRT_MAX; + XtVaSetValues(ih->handle, XmNvalue, ival, NULL); + + motValCallAction(ih, ival, 1); +} + +static void motValKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean *cont) +{ + KeySym motcode; + + *cont = True; + iupmotKeyPressEvent(w, ih, (XEvent*)evt, cont); + if (*cont == False) + return; + + motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + + /* add missing support for numeric keyboard */ + /* add missing support for left/right in vertical + and up/down in horizontal */ + if (motcode == XK_Left || motcode == XK_KP_Left || + motcode == XK_Up || motcode == XK_KP_Up) + { + motValIncLineValue(ih, -1); + *cont = False; + return; + } + if (motcode == XK_Right || motcode == XK_KP_Right || + motcode == XK_Down || motcode == XK_KP_Down) + { + motValIncLineValue(ih, 1); + *cont = False; + return; + } + if (motcode == XK_Prior || motcode == XK_KP_Page_Up) + { + motValIncPageValue(ih, -1); + *cont = False; + return; + } + if (motcode == XK_Next || motcode == XK_KP_Page_Down) + { + motValIncPageValue(ih, 1); + *cont = False; + return; + } + + /* change Home and End default behaviour */ + if (ih->data->inverted) + { + if (motcode==XK_Home || motcode==XK_KP_Home) + { + int ival = SHRT_MAX; /* set to maximum */ + XtVaSetValues(ih->handle, XmNvalue, ival, NULL); + motValCallAction(ih, ival, 1); + *cont = False; + return; + } + if (motcode==XK_End || motcode==XK_KP_End) + { + int ival = 0; /* set to minimum */ + XtVaSetValues(ih->handle, XmNvalue, ival, NULL); + motValCallAction(ih, ival, 1); + *cont = False; + return; + } + } + else + { + /* add missing support for numeric keyboard */ + if (motcode==XK_KP_Home) + { + int ival = 0; /* set to minimum */ + XtVaSetValues(ih->handle, XmNvalue, ival, NULL); + motValCallAction(ih, ival, 1); + *cont = False; + return; + } + if (motcode==XK_KP_End) + { + int ival = SHRT_MAX; /* set to maximum */ + XtVaSetValues(ih->handle, XmNvalue, ival, NULL); + motValCallAction(ih, ival, 1); + *cont = False; + return; + } + } +} + +static void motValValueChangedCallback(Widget w, Ihandle* ih, XmScaleCallbackStruct *cbs) +{ + int cb_state = 1; + + if(cbs->reason == XmCR_DRAG) + cb_state = 0; + else if (cbs->event && (cbs->event->type==ButtonRelease || cbs->event->type==KeyRelease)) + cb_state = -1; + + motValCallAction(ih, cbs->value, cb_state); + + (void)w; +} + +static void motValButtonPressReleaseEvent(Widget w, Ihandle* ih, XButtonEvent* evt, Boolean* cont) +{ + (void)w; + (void)cont; + + /* When Button1 is pressed, the Scrollbar loses its focus to the scale, + So we avoid calling GETFOCUS/KILLFOCUS. + */ + + if (evt->type==ButtonPress && evt->button==Button1) + { + iupAttribSetStr(ih, "_IUPVAL_IGNOREFOCUS", "1"); + } + if (evt->type==ButtonRelease && evt->button==Button1) + { + iupAttribSetStr(ih, "_IUPVAL_IGNOREFOCUS", NULL); + iupAttribSetStr(ih, "_IUPVAL_IGNOREKILLFOCUS", "1"); + } +} + +static void motValFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + if (iupAttribGet(ih, "_IUPVAL_IGNOREFOCUS")) + return; + + if (evt->type == FocusOut && iupAttribGet(ih, "_IUPVAL_IGNOREKILLFOCUS")) + { + iupAttribSetStr(ih, "_IUPVAL_IGNOREKILLFOCUS", NULL); + return; + } + + iupmotFocusChangeEvent(w, ih, evt, cont); +} + + +/*********************************************************************************************/ + + +static int motValMapMethod(Ihandle* ih) +{ + int num_args = 0; + Arg args[30]; + int show_ticks; + + /* Core */ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Primitive */ + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupmotSetArg(args, num_args, XmNhighlightThickness, 2); + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + /* Scale */ + iupmotSetArg(args, num_args, XmNminimum, 0); + iupmotSetArg(args, num_args, XmNmaximum, SHRT_MAX); + iupmotSetArg(args, num_args, XmNslidingMode, XmSLIDER); + iupmotSetArg(args, num_args, XmNsliderMark, XmETCHED_LINE); + iupmotSetArg(args, num_args, XmNsliderSize, 16); + iupmotSetArg(args, num_args, XmNshowValue, XmNONE); + + if (ih->data->type == IVAL_HORIZONTAL) + { + iupmotSetArg(args, num_args, XmNorientation, XmHORIZONTAL); + if (ih->data->inverted) + iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_LEFT); + else + iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_RIGHT); + } + else + { + iupmotSetArg(args, num_args, XmNorientation, XmVERTICAL); + if (ih->data->inverted) + iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_TOP); + else + iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_BOTTOM); + } + + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + xmScaleWidgetClass, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + /* callbacks */ + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + + /* XmScale changes the default behavior of these, must set directly into the scrollbar */ + /* XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); */ + /* XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); */ + + XtAddCallback(ih->handle, XmNdragCallback, (XtCallbackProc)motValValueChangedCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNvalueChangedCallback, (XtCallbackProc)motValValueChangedCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + + { + Widget sb = XtNameToWidget(ih->handle, "Scrollbar"); /* TODO: Test this in other Motifs */ + if (sb) + { + XtAddEventHandler(sb, FocusChangeMask, False, (XtEventHandler)motValFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(sb, KeyPressMask, False, (XtEventHandler)motValKeyPressEvent, (XtPointer)ih); + XtAddEventHandler(sb, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)motValButtonPressReleaseEvent, (XtPointer)ih); + } + } + + /* Ticks can only be created before XtRealizeWidget */ + show_ticks = iupAttribGetInt(ih, "SHOWTICKS"); + if (show_ticks) + { + if (show_ticks<2) show_ticks=2; + ih->data->show_ticks = show_ticks; /* non zero value, can be changed later, but not to zero */ + } + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + return IUP_NOERROR; +} + +void iupdrvValInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motValMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motValSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motValSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + + /* IupVal only */ + iupClassRegisterAttribute(ic, "VALUE", iupValGetValueAttrib, motValSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PAGESTEP", iupValGetPageStepAttrib, motValSetPageStepAttrib, IUPAF_SAMEASSYSTEM, "0.1", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWTICKS", iupValGetShowTicksAttrib, motValSetShowTicksAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "STEP", iupValGetStepAttrib, motValSetStepAttrib, IUPAF_SAMEASSYSTEM, "0.01", IUPAF_NO_INHERIT); +} diff --git a/iup/src/mot/iupunix_help.c b/iup/src/mot/iupunix_help.c new file mode 100755 index 0000000..02be1da --- /dev/null +++ b/iup/src/mot/iupunix_help.c @@ -0,0 +1,44 @@ +/** \file + * \brief Motif Driver IupHelp + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "iup.h" + +#include "iup_str.h" + +int IupHelp(const char *url) +{ + char *cmd; + int ret; + char *browser = getenv("IUP_HELPAPP"); + if (!browser) + browser = IupGetGlobal("HELPAPP"); + + if (!browser) + { + char* system = IupGetGlobal("SYSTEM"); + if (iupStrEqualNoCase(system, "Linux") || + iupStrEqualNoCase(system, "FreeBSD")) + browser = "firefox"; + else if (iupStrEqualNoCase(system, "Darwin")) + browser = "safari"; + else if (iupStrEqualPartial(system, "CYGWIN")) + browser = "iexplore"; + else + browser = "netscape"; + } + + cmd = (char*)malloc(sizeof(char)*(strlen(url)+strlen(browser)+3)); + sprintf(cmd, "%s %s &", browser, url); + ret = system(cmd); + free(cmd); + if (ret == -1) + return -1; + return 1; +} diff --git a/iup/src/mot/iupunix_info.c b/iup/src/mot/iupunix_info.c new file mode 100755 index 0000000..b522638 --- /dev/null +++ b/iup/src/mot/iupunix_info.c @@ -0,0 +1,305 @@ +/** \file + * \brief UNIX System Information + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <sys/stat.h> + +/* This module should depend only on IUP core headers + and UNIX system headers. NO Motif headers allowed. */ + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <sys/utsname.h> +#include <unistd.h> +#include <errno.h> +#include <sys/stat.h> + +#include "iup_str.h" +#include "iup_drvinfo.h" + + +int iupdrvMakeDirectory(const char* name) +{ + mode_t oldmask = umask((mode_t)0); + int fail = mkdir(name, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | + S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH); + umask (oldmask); + if (fail) + return 0; + return 1; +} + +int iupdrvIsFile(const char* name) +{ + struct stat status; + if (stat(name, &status) != 0) + return 0; + if (S_ISDIR(status.st_mode)) + return 0; + return 1; +} + +int iupdrvIsDirectory(const char* name) +{ + struct stat status; + if (stat(name, &status) != 0) + return 0; + if (S_ISDIR(status.st_mode)) + return 1; + return 0; +} + +char* iupdrvGetCurrentDirectory(void) +{ + size_t size = 256; + char *buffer = (char *)malloc(size); + + for (;;) + { + if (getcwd(buffer, size) != NULL) + return buffer; + + if (errno != ERANGE) + { + free(buffer); + return NULL; + } + + size += size; + buffer = (char *)realloc(buffer, size); + } + + return NULL; +} + +int iupdrvSetCurrentDirectory(const char* dir) +{ + return chdir(dir) == 0? 1: 0; +} + +int iupdrvGetWindowDecor(void* wnd, int *border, int *caption) +{ + XWindowAttributes wa; + wa.x = 0; wa.y = 0; + XGetWindowAttributes((Display*)iupdrvGetDisplay(), (Window)wnd, &wa); + if (wa.x > 0 && wa.y > 0 && wa.y >= wa.x) + { + *border = wa.x; + *caption = wa.y - *border; + return 1; + } + + *border = 0; + *caption = 0; + + return 0; +} + +static int xGetWorkAreaSize(Display* display, int screen, int *width, int *height) +{ + /* _NET_WORKAREA, x, y, width, height CARDINAL[][4]/32 */ + static Atom workarea = 0; + Atom type; + long *data; + int format; + unsigned long after, ndata; + + if (!workarea) + workarea = XInternAtom(display, "_NET_WORKAREA", False); + + XGetWindowProperty(display, RootWindow(display, screen), + workarea, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &ndata, + &after, (unsigned char **)&data); + if (type != XA_CARDINAL || data == NULL) + { + if (data) XFree(data); + return 0; + } + + *width = data[2]; /* get only for the first desktop */ + *height = data[3]; + + XFree(data); + return 1; +} + +void iupdrvGetScreenSize(int *width, int *height) +{ + Display* display = (Display*)iupdrvGetDisplay(); + int screen = XDefaultScreen(display); + if (!xGetWorkAreaSize(display, screen, width, height)) + { + *width = DisplayWidth(display, screen); + *height = DisplayHeight(display, screen); + } +} + +void iupdrvGetFullSize(int *width, int *height) +{ + Display* display = (Display*)iupdrvGetDisplay(); + int screen = XDefaultScreen(display); + Window root = RootWindow(display, screen); + XWindowAttributes wa; + XGetWindowAttributes(display, root, &wa); + *width = wa.width; + *height = wa.height; +} + +static int xCheckVisualInfo(Display* drv_display, int bpp) +{ + int nitems; + XVisualInfo info, *ret_info; + + info.depth = bpp; + ret_info = XGetVisualInfo(drv_display, VisualDepthMask, &info, &nitems); + if (ret_info != NULL) + { + XFree(ret_info); + return 1; + } + return 0; +} + +int iupdrvGetScreenDepth(void) +{ + static int first = 1; + static int bpp; + + if (first) + { + Display* drv_display = (Display*)iupdrvGetDisplay(); + + if (xCheckVisualInfo(drv_display, 24)) + { + bpp = 24; + return bpp; + } + + if (xCheckVisualInfo(drv_display, 16)) + { + bpp = 16; + return bpp; + } + + if (xCheckVisualInfo(drv_display, 8)) + { + bpp = 8; + return bpp; + } + + if (xCheckVisualInfo(drv_display, 4)) + { + bpp = 4; + return bpp; + } + + bpp = 2; + + first = 0; + } + + return bpp; +} + +void iupdrvGetCursorPos(int *x, int *y) +{ + Window root, child; + int cx, cy; + unsigned int keys; + Display* display = (Display*)iupdrvGetDisplay(); + int screen = XDefaultScreen(display); + + XQueryPointer(display, RootWindow(display, screen), + &root, &child, x, y, &cx, &cy, &keys); +} + +static int xCheckModifier(KeyCode* modifiermap, int max_keypermod, int index, const char* keys) +{ + int i; + for (i = 0; i < max_keypermod; i++) + { + KeyCode key = modifiermap[max_keypermod * index + i]; + if (key) + { + int KeyIndex = key / 8; + int KeyMask = 1 << (key % 8); + if (keys[KeyIndex] & KeyMask) + return 1; + } + } + return 0; +} + +void iupdrvGetKeyState(char* key) +{ + char keys[32]; + Display* display = (Display*)iupdrvGetDisplay(); + XModifierKeymap *modMap = XGetModifierMapping(display); + XQueryKeymap(display, keys); + + if (xCheckModifier(modMap->modifiermap, modMap->max_keypermod, ShiftMapIndex, keys)) + key[0] = 'S'; + else + key[0] = ' '; + if (xCheckModifier(modMap->modifiermap, modMap->max_keypermod, ControlMapIndex, keys)) + key[1] = 'C'; + else + key[1] = ' '; + if (xCheckModifier(modMap->modifiermap, modMap->max_keypermod, Mod1MapIndex, keys) || + xCheckModifier(modMap->modifiermap, modMap->max_keypermod, Mod5MapIndex, keys)) + key[2] = 'A'; + else + key[2] = ' '; + if (xCheckModifier(modMap->modifiermap, modMap->max_keypermod, Mod4MapIndex, keys)) + key[3] = 'Y'; + else + key[3] = ' '; + + key[4] = 0; + + XFreeModifiermap(modMap); +} + +char *iupdrvGetSystemName(void) +{ + struct utsname un; + char *str = iupStrGetMemory(50); + + uname(&un); + strcpy(str, un.sysname); + + return str; +} + +char *iupdrvGetSystemVersion(void) +{ + struct utsname un; + char *str = iupStrGetMemory(60); + + uname(&un); + strcpy(str, un.release); + strcat(str, "."); + strcat(str, un.version); + + return str; +} + +char *iupdrvGetComputerName(void) +{ + char* str = iupStrGetMemory(50); + gethostname(str, 50); + return str; +} + +char *iupdrvGetUserName(void) +{ + return (char*)getlogin(); +} diff --git a/iup/src/win/iupwin_brush.c b/iup/src/win/iupwin_brush.c new file mode 100755 index 0000000..228e6d4 --- /dev/null +++ b/iup/src/win/iupwin_brush.c @@ -0,0 +1,62 @@ +/** \file + * \brief Windows Brush Cache + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> + +#include <windows.h> + +#include "iup.h" +#include "iup_array.h" + +#include "iupwin_brush.h" + + +typedef struct _IwinBrush +{ + HBRUSH hbrush; + COLORREF color; +} IwinBrush; + +static Iarray* win_brushes = NULL; + +HBRUSH iupwinBrushGet(COLORREF color) +{ + int i, count = iupArrayCount(win_brushes); + + /* If a brush with the desired color already exists... */ + IwinBrush* brushes = (IwinBrush*)iupArrayGetData(win_brushes); + for (i = 0; i < count; i++) + { + if (brushes[i].color == color) + return brushes[i].hbrush; + } + + /* If it doesn't exist, it should be created... */ + brushes = (IwinBrush*)iupArrayInc(win_brushes); + + brushes[i].color = color; + brushes[i].hbrush = CreateSolidBrush(color); + + return brushes[i].hbrush; +} + +void iupwinBrushInit(void) +{ + win_brushes = iupArrayCreate(50, sizeof(IwinBrush)); +} + +void iupwinBrushFinish(void) +{ + int i, count = iupArrayCount(win_brushes); + IwinBrush* brushes = (IwinBrush*)iupArrayGetData(win_brushes); + for (i = 0; i < count; i++) + { + DeleteObject(brushes[i].hbrush); + brushes[i].hbrush = NULL; + } + iupArrayDestroy(win_brushes); +} diff --git a/iup/src/win/iupwin_brush.h b/iup/src/win/iupwin_brush.h new file mode 100755 index 0000000..463f323 --- /dev/null +++ b/iup/src/win/iupwin_brush.h @@ -0,0 +1,26 @@ +/** \file + * \brief Windows Brush Cache + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPWIN_BRUSH_H +#define __IUPWIN_BRUSH_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* returns a brush from the brush cache. */ +HBRUSH iupwinBrushGet(COLORREF c); + +/* initializes the brush cache */ +void iupwinBrushInit(void); +void iupwinBrushFinish(void); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/win/iupwin_button.c b/iup/src/win/iupwin_button.c new file mode 100755 index 0000000..7f780e3 --- /dev/null +++ b/iup/src/win/iupwin_button.c @@ -0,0 +1,715 @@ +/** \file + * \brief Button Control + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> +#include <commctrl.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_button.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_image.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" +#include "iupwin_draw.h" + + +#ifndef CDIS_SHOWKEYBOARDCUES +#define CDIS_SHOWKEYBOARDCUES 0x0200 /* it is defined only when _WIN32_WINNT >= 0x0501 */ +#endif + + +static int winButtonGetBorder(void) +{ + return 4; +} + +void iupdrvButtonAddBorders(int *x, int *y) +{ + int border_size = winButtonGetBorder()*2; + (*x) += border_size; + (*y) += border_size; +} + +/****************************************************************/ + +static int winButtonCalcAlignPosX(int horiz_alignment, int rect_width, int width, int xpad, int shift) +{ + int x; + + if (horiz_alignment == IUP_ALIGN_ARIGHT) + x = rect_width - (width + 2*xpad); + else if (horiz_alignment == IUP_ALIGN_ACENTER) + x = (rect_width - (width + 2*xpad))/2; + else /* ALEFT */ + x = 0; + + x += xpad; + + if (shift) + x++; + + return x; +} + +static int winButtonCalcAlignPosY(int vert_alignment, int rect_height, int height, int ypad, int shift) +{ + int y; + + if (vert_alignment == IUP_ALIGN_ABOTTOM) + y = rect_height - (height + 2*ypad); + else if (vert_alignment == IUP_ALIGN_ATOP) + y = 0; + else /* ACENTER */ + y = (rect_height - (height + 2*ypad))/2; + + y += ypad; + + if (shift) + y++; + + return y; +} + +static HBITMAP winButtonGetBitmap(Ihandle* ih, UINT itemState, int *shift, int *w, int *h, int *bpp, HBITMAP *hMask) +{ + char *name; + int make_inactive = 0; + HBITMAP hBitmap; + *hMask = NULL; + + if (itemState & ODS_DISABLED) + { + name = iupAttribGet(ih, "IMINACTIVE"); + if (!name) + { + name = iupAttribGet(ih, "IMAGE"); + make_inactive = 1; + } + } + else + { + name = iupAttribGet(ih, "IMPRESS"); + if (itemState & ODS_SELECTED && name) + { + if (shift && !iupAttribGetStr(ih, "IMPRESSBORDER")) + *shift = 0; + } + else + name = iupAttribGet(ih, "IMAGE"); + } + + hBitmap = iupImageGetImage(name, ih, make_inactive); + + /* must use this info, since image can be a driver image loaded from resources */ + iupdrvImageGetInfo(hBitmap, w, h, bpp); + + if (*bpp == 8) + *hMask = iupdrvImageCreateMask(IupGetHandle(name)); + + return hBitmap; +} + +static void winButtonDrawImageText(Ihandle* ih, HDC hDC, int rect_width, int rect_height, int border, UINT itemState) +{ + int xpad = ih->data->horiz_padding + border, + ypad = ih->data->vert_padding + border; + int x, y, width, height, + txt_x, txt_y, txt_width, txt_height, + img_x, img_y, img_width, img_height, + bpp, shift = 0; + HFONT hFont = (HFONT)iupwinGetHFontAttrib(ih); + HBITMAP hBitmap, hMask; + COLORREF fgcolor; + + char* title = iupdrvBaseGetTitleAttrib(ih); + char* str = iupStrProcessMnemonic(title, NULL, 0); /* remove & */ + iupdrvFontGetMultiLineStringSize(ih, str, &txt_width, &txt_height); + if (str && str!=title) free(str); + + if (itemState & ODS_DISABLED) + fgcolor = GetSysColor(COLOR_GRAYTEXT); + else + fgcolor = ih->data->fgcolor; + + hBitmap = winButtonGetBitmap(ih, itemState, NULL, &img_width, &img_height, &bpp, &hMask); + if (!hBitmap) + return; + + if (ih->data->img_position == IUP_IMGPOS_RIGHT || + ih->data->img_position == IUP_IMGPOS_LEFT) + { + width = img_width + txt_width + ih->data->spacing; + height = iupMAX(img_height, txt_height); + } + else + { + width = iupMAX(img_width, txt_width); + height = img_height + txt_height + ih->data->spacing; + } + + if (itemState & ODS_SELECTED && !iupwin_comctl32ver6) + shift = 1; + + x = winButtonCalcAlignPosX(ih->data->horiz_alignment, rect_width, width, xpad, shift); + y = winButtonCalcAlignPosY(ih->data->vert_alignment, rect_height, height, ypad, shift); + + switch(ih->data->img_position) + { + case IUP_IMGPOS_TOP: + img_y = y; + txt_y = y + img_height + ih->data->spacing; + if (img_width > txt_width) + { + img_x = x; + txt_x = x + (img_width-txt_width)/2; + } + else + { + img_x = x + (txt_width-img_width)/2; + txt_x = x; + } + break; + case IUP_IMGPOS_BOTTOM: + img_y = y + txt_height + ih->data->spacing; + txt_y = y; + if (img_width > txt_width) + { + img_x = x; + txt_x = x + (img_width-txt_width)/2; + } + else + { + img_x = x + (txt_width-img_width)/2; + txt_x = x; + } + break; + case IUP_IMGPOS_RIGHT: + img_x = x + txt_width + ih->data->spacing; + txt_x = x; + if (img_height > txt_height) + { + img_y = y; + txt_y = y + (img_height-txt_height)/2; + } + else + { + img_y = y + (txt_height-img_height)/2; + txt_y = y; + } + break; + default: /* IUP_IMGPOS_LEFT */ + img_x = x; + txt_x = x + img_width + ih->data->spacing; + if (img_height > txt_height) + { + img_y = y; + txt_y = y + (img_height-txt_height)/2; + } + else + { + img_y = y + (txt_height-img_height)/2; + txt_y = y; + } + break; + } + + iupwinDrawBitmap(hDC, hBitmap, hMask, img_x, img_y, img_width, img_height, bpp); + iupwinDrawText(hDC, title, txt_x, txt_y, txt_width, txt_height, hFont, fgcolor, 0); + + if (hMask) + DeleteObject(hMask); +} + +static void winButtonDrawImage(Ihandle* ih, HDC hDC, int rect_width, int rect_height, int border, UINT itemState) +{ + int xpad = ih->data->horiz_padding + border, + ypad = ih->data->vert_padding + border; + int x, y, width, height, bpp, shift = 0; + HBITMAP hBitmap, hMask; + + if (itemState & ODS_SELECTED && !iupwin_comctl32ver6) + shift = 1; + + hBitmap = winButtonGetBitmap(ih, itemState, &shift, &width, &height, &bpp, &hMask); + if (!hBitmap) + return; + + x = winButtonCalcAlignPosX(ih->data->horiz_alignment, rect_width, width, xpad, shift); + y = winButtonCalcAlignPosY(ih->data->vert_alignment, rect_height, height, ypad, shift); + + iupwinDrawBitmap(hDC, hBitmap, hMask, x, y, width, height, bpp); + + if (hMask) + DeleteObject(hMask); +} + +static void winButtonDrawText(Ihandle* ih, HDC hDC, int rect_width, int rect_height, int border, UINT itemState) +{ + int xpad = ih->data->horiz_padding + border, + ypad = ih->data->vert_padding + border; + int x, y, width, height, shift = 0; + COLORREF fgcolor; + + char* title = iupdrvBaseGetTitleAttrib(ih); + if (title) + { + HFONT hFont = (HFONT)iupwinGetHFontAttrib(ih); + char* str = iupStrProcessMnemonic(title, NULL, 0); /* remove & */ + iupdrvFontGetMultiLineStringSize(ih, str, &width, &height); + if (str && str!=title) free(str); + + if (itemState & ODS_DISABLED) + fgcolor = GetSysColor(COLOR_GRAYTEXT); + else + fgcolor = ih->data->fgcolor; + + if (itemState & ODS_SELECTED && !iupwin_comctl32ver6) + shift = 1; + + x = winButtonCalcAlignPosX(ih->data->horiz_alignment, rect_width, width, xpad, shift); + y = winButtonCalcAlignPosY(ih->data->vert_alignment, rect_height, height, ypad, shift); + + iupwinDrawText(hDC, title, x, y, width, height, hFont, fgcolor, 0); + } + else + { + /* fill with the background color if defined at the element */ + char* bgcolor = iupAttribGet(ih, "BGCOLOR"); + if (bgcolor) + { + RECT rect; + unsigned char r=0, g=0, b=0; + iupStrToRGB(bgcolor, &r, &g, &b); + SetDCBrushColor(hDC, RGB(r,g,b)); + rect.left = xpad; + rect.top = ypad; + rect.right = rect_width - xpad; + rect.bottom = rect_height - ypad; + FillRect(hDC, &rect, (HBRUSH)GetStockObject(DC_BRUSH)); + } + } +} + +static void winButtonDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem) +{ + iupwinBitmapDC bmpDC; + int border, draw_border; + int width = drawitem->rcItem.right - drawitem->rcItem.left; + int height = drawitem->rcItem.bottom - drawitem->rcItem.top; + + HDC hDC = iupwinDrawCreateBitmapDC(&bmpDC, drawitem->hDC, width, height); + + iupwinDrawParentBackground(ih, hDC, &drawitem->rcItem); + + if ((drawitem->itemState & ODS_FOCUS) && !(drawitem->itemState & ODS_HOTLIGHT)) + drawitem->itemState |= ODS_DEFAULT; + + border = winButtonGetBorder(); + + if (ih->data->type & IUP_BUTTON_IMAGE && iupAttribGet(ih, "IMPRESS") && !iupAttribGetStr(ih, "IMPRESSBORDER")) + draw_border = 0; + else + { + if (iupAttribGetBoolean(ih, "FLAT")) + { + if (drawitem->itemState & ODS_HOTLIGHT || iupAttribGet(ih, "_IUPWINBUT_ENTERWIN")) + draw_border = 1; + else + draw_border = 0; + } + else + draw_border = 1; + } + + if (draw_border) + iupwinDrawButtonBorder(ih->handle, hDC, &drawitem->rcItem, drawitem->itemState); + + if (ih->data->type == IUP_BUTTON_IMAGE) + winButtonDrawImage(ih, hDC, width, height, border, drawitem->itemState); + else if (ih->data->type == IUP_BUTTON_TEXT) + winButtonDrawText(ih, hDC, width, height, border, drawitem->itemState); + else /* both */ + winButtonDrawImageText(ih, hDC, width, height, border, drawitem->itemState); + + if (drawitem->itemState & ODS_FOCUS) + { + border--; + iupdrvDrawFocusRect(ih, hDC, border, border, width-2*border, height-2*border); + } + + iupwinDrawDestroyBitmapDC(&bmpDC); +} + + +/***********************************************************************************************/ + + +static int winButtonSetImageAttrib(Ihandle* ih, const char* value) +{ + (void)value; + if (ih->data->type != IUP_BUTTON_TEXT) + { + iupdrvDisplayUpdate(ih); + return 1; + } + else + return 0; +} + +static int winButtonSetImInactiveAttrib(Ihandle* ih, const char* value) +{ + (void)value; + if (ih->data->type != IUP_BUTTON_TEXT) + { + iupdrvDisplayUpdate(ih); + return 1; + } + else + return 0; +} + +static int winButtonSetImPressAttrib(Ihandle* ih, const char* value) +{ + (void)value; + if (ih->data->type != IUP_BUTTON_TEXT) + { + iupdrvDisplayUpdate(ih); + return 1; + } + else + return 0; +} + +static int winButtonSetActiveAttrib(Ihandle* ih, const char* value) +{ + /* redraw IMINACTIVE image if any */ + if (ih->data->type != IUP_BUTTON_TEXT) + iupdrvDisplayUpdate(ih); + + return iupBaseSetActiveAttrib(ih, value); +} + +static int winButtonSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + char value1[30]="", value2[30]=""; + + iupStrToStrStr(value, value1, value2, ':'); + + if (iupStrEqualNoCase(value1, "ARIGHT")) + ih->data->horiz_alignment = IUP_ALIGN_ARIGHT; + else if (iupStrEqualNoCase(value1, "ALEFT")) + ih->data->horiz_alignment = IUP_ALIGN_ALEFT; + else /* "ACENTER" */ + ih->data->horiz_alignment = IUP_ALIGN_ACENTER; + + if (iupStrEqualNoCase(value2, "ABOTTOM")) + ih->data->vert_alignment = IUP_ALIGN_ABOTTOM; + else if (iupStrEqualNoCase(value2, "ATOP")) + ih->data->vert_alignment = IUP_ALIGN_ATOP; + else /* "ACENTER" */ + ih->data->vert_alignment = IUP_ALIGN_ACENTER; + + iupdrvDisplayRedraw(ih); + + return 1; +} + +static char* winButtonGetAlignmentAttrib(Ihandle *ih) +{ + char* horiz_align2str[3] = {"ALEFT", "ACENTER", "ARIGHT"}; + char* vert_align2str[3] = {"ATOP", "ACENTER", "ABOTTOM"}; + char *str = iupStrGetMemory(50); + sprintf(str, "%s:%s", horiz_align2str[ih->data->horiz_alignment], vert_align2str[ih->data->vert_alignment]); + return str; +} + +static int winButtonSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle) + iupdrvDisplayRedraw(ih); + return 0; +} + +static int winButtonSetBgColorAttrib(Ihandle* ih, const char* value) +{ + /* update internal image cache for controls that have the IMAGE attribute */ + if (ih->data->type != IUP_BUTTON_TEXT) + { + iupAttribSetStr(ih, "BGCOLOR", value); + iupImageUpdateParent(ih); + iupdrvDisplayRedraw(ih); + } + return 1; +} + +static char* winButtonGetBgColorAttrib(Ihandle* ih) +{ + /* the most important use of this is to provide + the correct background for images */ + if (iupwin_comctl32ver6 && !iupAttribGet(ih, "IMPRESS")) + { + COLORREF cr; + if (iupwinDrawGetThemeButtonBgColor(ih->handle, &cr)) + { + char* str = iupStrGetMemory(20); + sprintf(str, "%d %d %d", (int)GetRValue(cr), (int)GetGValue(cr), (int)GetBValue(cr)); + return str; + } + } + + if (iupAttribGet(ih, "IMPRESS")) + return iupBaseNativeParentGetBgColorAttrib(ih); + else + return NULL; +} + +static int winButtonSetFgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + if (iupStrToRGB(value, &r, &g, &b)) + { + ih->data->fgcolor = RGB(r,g,b); + iupdrvDisplayRedraw(ih); + } + return 1; +} + +/****************************************************************************************/ + +static int winButtonProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + if (ih->data->type != IUP_BUTTON_TEXT) + { + /* redraw IMPRESS image if any */ + if ((msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) && iupAttribGet(ih, "IMPRESS")) + iupdrvDisplayRedraw(ih); + } + + switch (msg) + { + case WM_XBUTTONDBLCLK: + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + case WM_XBUTTONDOWN: + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + { + iupwinButtonDown(ih, msg, wp, lp); + break; + } + case WM_XBUTTONUP: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + { + iupwinButtonUp(ih, msg, wp, lp); + + /* BN_CLICKED will NOT be notified when not receiving the focus */ + if (msg==WM_LBUTTONUP && !iupAttribGetBoolean(ih, "FOCUSONCLICK")) + { + Icallback cb = IupGetCallback(ih, "ACTION"); + if (cb && cb(ih) == IUP_CLOSE) + IupExitLoop(); + } + + break; + } + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + if (wp==VK_RETURN) + { + /* enter activates the button */ + iupdrvActivate(ih); + + *result = 0; + return 1; /* abort default processing, or the default button will be activated, + in this case even if there is a default button, this button must be activated instead. */ + } + break; + case WM_MOUSELEAVE: + if (!iupwin_comctl32ver6) + { + iupAttribSetStr(ih, "_IUPWINBUT_ENTERWIN", NULL); + iupdrvDisplayRedraw(ih); + } + break; + case WM_MOUSEMOVE: + if (!iupwin_comctl32ver6) + { + if (!iupAttribGet(ih, "_IUPWINBUT_ENTERWIN")) + { + iupAttribSetStr(ih, "_IUPWINBUT_ENTERWIN", "1"); + iupdrvDisplayRedraw(ih); + } + } + break; + case WM_SETFOCUS: + { + HWND previous = (HWND)wp; + if (!iupAttribGetBoolean(ih, "FOCUSONCLICK") && wp && iupAttribGet(ih, "_IUPWIN_ENTERWIN")) + { + SetFocus(previous); + *result = 0; + return 1; + } + } + break; + } + + return iupwinBaseProc(ih, msg, wp, lp, result); +} + +static int winButtonWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) +{ + if (msg_info->code == NM_CUSTOMDRAW) + { + NMCUSTOMDRAW *customdraw = (NMCUSTOMDRAW*)msg_info; + + if (customdraw->dwDrawStage==CDDS_PREERASE) + { + DRAWITEMSTRUCT drawitem; + drawitem.itemState = 0; + + if (customdraw->uItemState & CDIS_DISABLED) + drawitem.itemState |= ODS_DISABLED; + else if (customdraw->uItemState & CDIS_SELECTED) + drawitem.itemState |= ODS_SELECTED; + else if (customdraw->uItemState & CDIS_HOT) + drawitem.itemState |= ODS_HOTLIGHT; + else if (customdraw->uItemState & CDIS_DEFAULT) + drawitem.itemState |= ODS_DEFAULT; + + if (customdraw->uItemState & CDIS_FOCUS && (customdraw->uItemState & CDIS_SHOWKEYBOARDCUES)) + drawitem.itemState |= ODS_FOCUS; + + drawitem.hDC = customdraw->hdc; + drawitem.rcItem = customdraw->rc; + + winButtonDrawItem(ih, (void*)&drawitem); /* Simulate a WM_DRAWITEM */ + + *result = CDRF_SKIPDEFAULT; + return 1; + } + } + + return 0; /* result not used */ +} + +static int winButtonWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp) +{ + int cmd = HIWORD(wp); + switch (cmd) + { + case BN_DOUBLECLICKED: + case BN_CLICKED: + { + Icallback cb = IupGetCallback(ih, "ACTION"); + if (cb && cb(ih) == IUP_CLOSE) + IupExitLoop(); + } + } + + (void)lp; + return 0; /* not used */ +} + +static int winButtonMapMethod(Ihandle* ih) +{ + char* value; + DWORD dwStyle = WS_CHILD | + BS_NOTIFY; /* necessary because of the base messages */ + + if (!ih->parent) + return IUP_ERROR; + + /* Buttons with the BS_PUSHBUTTON style do NOT use the returned brush in WM_CTLCOLORBTN. + Buttons with these styles are always drawn with the default system colors. + So FGCOLOR and BGCOLOR do NOT work. + The BS_FLAT style does NOT completely remove the borders. With XP styles is ignored. So FLAT do NOT work. + BCM_SETTEXTMARGIN is not working. + Buttons with images and with XP styles do NOT draw the focus feedback. + Can NOT remove the borders when using IMPRESS. + So IUP will draw its own button, + but uses the Windows functions to draw text and images in native format. */ + if (iupwin_comctl32ver6) + dwStyle |= BS_PUSHBUTTON; /* it will be an ownerdraw because we use NM_CUSTOMDRAW */ + else + dwStyle |= BS_OWNERDRAW; + + value = iupAttribGet(ih, "IMAGE"); + if (value) + { + ih->data->type = IUP_BUTTON_IMAGE; + + value = iupAttribGet(ih, "TITLE"); + if (value) + ih->data->type |= IUP_BUTTON_TEXT; + } + else + ih->data->type = IUP_BUTTON_TEXT; + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + dwStyle |= WS_TABSTOP; + + if (!iupwinCreateWindowEx(ih, "BUTTON", 0, dwStyle)) + return IUP_ERROR; + + /* Process WM_COMMAND */ + IupSetCallback(ih, "_IUPWIN_COMMAND_CB", (Icallback)winButtonWmCommand); + + /* Process BUTTON_CB */ + IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winButtonProc); + + if (iupwin_comctl32ver6) + IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winButtonWmNotify); /* Process WM_NOTIFY */ + else + IupSetCallback(ih, "_IUPWIN_DRAWITEM_CB", (Icallback)winButtonDrawItem); /* Process WM_DRAWITEM */ + + return IUP_NOERROR; +} + +void iupdrvButtonInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = winButtonMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, winButtonSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", winButtonGetBgColorAttrib, winButtonSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, winButtonSetFgColorAttrib, "DLGFGCOLOR", NULL, IUPAF_NOT_MAPPED); /* force the new default value */ + iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, iupdrvBaseSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupButton only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", winButtonGetAlignmentAttrib, winButtonSetAlignmentAttrib, "ACENTER:ACENTER", NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE", NULL, winButtonSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, winButtonSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMPRESS", NULL, winButtonSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FOCUSONCLICK", NULL, NULL, "YES", NULL, IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "PADDING", iupButtonGetPaddingAttrib, winButtonSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); +} diff --git a/iup/src/win/iupwin_canvas.c b/iup/src/win/iupwin_canvas.c new file mode 100755 index 0000000..bb88b8a --- /dev/null +++ b/iup/src/win/iupwin_canvas.c @@ -0,0 +1,724 @@ +/** \file + * \brief Canvas Control + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <limits.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_canvas.h" +#include "iup_key.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" +#include "iupwin_brush.h" + + +static void winCanvasSetScrollInfo(HWND hWnd, int imin, int imax, int ipos, int ipage, int flag) +{ + SCROLLINFO scrollinfo; + scrollinfo.cbSize = sizeof(SCROLLINFO); + scrollinfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; + scrollinfo.nPage = ipage; + scrollinfo.nPos = ipos; + scrollinfo.nMax = imax; + scrollinfo.nMin = imin; + SetScrollInfo(hWnd, flag, &scrollinfo, TRUE); +} + +static int winCanvasSetBgColorAttrib(Ihandle *ih, const char *value) +{ + (void)value; + iupdrvDisplayUpdate(ih); + return 1; +} + +static int winCanvasSetDXAttrib(Ihandle *ih, const char *value) +{ + if (ih->data->sb & IUP_SB_HORIZ) + { + double posx, xmin, xmax; + float dx; + int iposx, ipagex; + + if (!iupStrToFloat(value, &dx)) + return 1; + + xmin = iupAttribGetFloat(ih, "XMIN"); + xmax = iupAttribGetFloat(ih, "XMAX"); + posx = ih->data->posx; + + iupCanvasCalcScrollIntPos(xmin, xmax, dx, posx, + IUP_SB_MIN, IUP_SB_MAX, &ipagex, &iposx); + + if (dx >= (xmax-xmin)) + { + if (iupAttribGetBoolean(ih, "XAUTOHIDE")) + ShowScrollBar(ih->handle, SB_HORZ, FALSE); + else + EnableScrollBar(ih->handle, SB_HORZ, ESB_DISABLE_BOTH); + return 1; + } + else + { + ShowScrollBar(ih->handle, SB_HORZ, TRUE); + EnableScrollBar(ih->handle, SB_HORZ, ESB_ENABLE_BOTH); + } + + winCanvasSetScrollInfo(ih->handle, IUP_SB_MIN, IUP_SB_MAX, iposx, ipagex, SB_HORZ); + + /* update position because it could be corrected */ + iupCanvasCalcScrollRealPos(xmin, xmax, &posx, + IUP_SB_MIN, IUP_SB_MAX, ipagex, &iposx); + + ih->data->posx = (float)posx; + } + return 1; +} + +static int winCanvasSetPosXAttrib(Ihandle *ih, const char *value) +{ + if (ih->data->sb & IUP_SB_HORIZ) + { + double xmin, xmax, dx; + float posx; + int iposx, ipagex; + + if (!iupStrToFloat(value, &posx)) + return 1; + + xmin = iupAttribGetFloat(ih, "XMIN"); + xmax = iupAttribGetFloat(ih, "XMAX"); + dx = iupAttribGetFloat(ih, "DX"); + + if (posx < xmin) posx = (float)xmin; + if (posx > (xmax - dx)) posx = (float)(xmax - dx); + ih->data->posx = posx; + + iupCanvasCalcScrollIntPos(xmin, xmax, dx, posx, + IUP_SB_MIN, IUP_SB_MAX, &ipagex, &iposx); + + SetScrollPos(ih->handle,SB_HORZ,iposx,TRUE); + } + return 1; +} + +static int winCanvasSetDYAttrib(Ihandle *ih, const char *value) +{ + if (ih->data->sb & IUP_SB_VERT) + { + double posy, ymin, ymax; + float dy; + int iposy, ipagey; + + if (!iupStrToFloat(value, &dy)) + return 1; + + ymin = iupAttribGetFloat(ih, "YMIN"); + ymax = iupAttribGetFloat(ih, "YMAX"); + posy = ih->data->posy; + + iupCanvasCalcScrollIntPos(ymin, ymax, dy, posy, + IUP_SB_MIN, IUP_SB_MAX, &ipagey, &iposy); + + if (dy >= (ymax-ymin)) + { + if (iupAttribGetBoolean(ih, "YAUTOHIDE")) + ShowScrollBar(ih->handle, SB_VERT, FALSE); + else + EnableScrollBar(ih->handle, SB_VERT, ESB_DISABLE_BOTH); + return 1; + } + else + { + ShowScrollBar(ih->handle, SB_VERT, TRUE); + EnableScrollBar(ih->handle, SB_VERT, ESB_ENABLE_BOTH); + } + + winCanvasSetScrollInfo(ih->handle, IUP_SB_MIN, IUP_SB_MAX, iposy, ipagey, SB_VERT); + + /* update position because it could be corrected */ + iupCanvasCalcScrollRealPos(ymin, ymax, &posy, + IUP_SB_MIN, IUP_SB_MAX, ipagey, &iposy); + + ih->data->posy = (float)posy; + } + return 1; +} + +static int winCanvasSetPosYAttrib(Ihandle *ih, const char *value) +{ + if (ih->data->sb & IUP_SB_VERT) + { + double ymin, ymax, dy; + float posy; + int iposy, ipagey; + + if (!iupStrToFloat(value, &posy)) + return 1; + + ymin = iupAttribGetFloat(ih, "YMIN"); + ymax = iupAttribGetFloat(ih, "YMAX"); + dy = iupAttribGetFloat(ih, "DY"); + + if (posy < ymin) posy = (float)ymin; + if (posy > (ymax - dy)) posy = (float)(ymax - dy); + ih->data->posy = posy; + + iupCanvasCalcScrollIntPos(ymin, ymax, dy, posy, + IUP_SB_MIN, IUP_SB_MAX, &ipagey, &iposy); + + SetScrollPos(ih->handle,SB_VERT,iposy,TRUE); + } + return 1; +} + +static void winCanvasGetScrollInfo(HWND hWnd, int *ipos, int *ipage, int flag, int track) +{ + SCROLLINFO scrollinfo; + scrollinfo.cbSize = sizeof(SCROLLINFO); + if (track) + scrollinfo.fMask = SIF_PAGE | SIF_TRACKPOS; + else + scrollinfo.fMask = SIF_PAGE | SIF_POS; + GetScrollInfo(hWnd, flag, &scrollinfo); + *ipage = scrollinfo.nPage; + if (track) + *ipos = scrollinfo.nTrackPos; + else + *ipos = scrollinfo.nPos; +} + +static void winCanvasUpdateHorScroll(Ihandle* ih, WORD winop) +{ + IFniff cb; + double xmin, xmax, posx, linex; + int ipagex, iposx, ilinex, op; + + /* unused */ + if (winop == SB_TOP || + winop == SB_BOTTOM || + winop == SB_ENDSCROLL) + return; + + xmax = iupAttribGetFloat(ih,"XMAX"); + xmin = iupAttribGetFloat(ih,"XMIN"); + + winCanvasGetScrollInfo(ih->handle, &iposx, &ipagex, SB_HORZ, winop==SB_THUMBTRACK? 1: 0); + + if (!iupAttribGet(ih,"LINEX")) + { + ilinex = ipagex/10; + if (!ilinex) + ilinex = 1; + } + else + { + /* line and page convertions are the same */ + linex = iupAttribGetFloat(ih,"LINEX"); + iupCanvasCalcScrollIntPos(xmin, xmax, linex, 0, + IUP_SB_MIN, IUP_SB_MAX, &ilinex, NULL); + } + + switch (winop) + { + case SB_LINEDOWN: + iposx = iposx + ilinex; + op = IUP_SBRIGHT; + break; + case SB_LINEUP: + iposx = iposx - ilinex; + op = IUP_SBLEFT; + break; + case SB_PAGEDOWN: + iposx = iposx + ipagex; + op = IUP_SBPGRIGHT; + break; + case SB_PAGEUP: + iposx = iposx - ipagex; + op = IUP_SBPGLEFT; + break; + case SB_THUMBTRACK: + op = IUP_SBDRAGH; + break; + case SB_THUMBPOSITION: + op = IUP_SBPOSH; + break; + default: + return; + } + + iupCanvasCalcScrollRealPos(xmin, xmax, &posx, + IUP_SB_MIN, IUP_SB_MAX, ipagex, &iposx); + + SetScrollPos(ih->handle,SB_HORZ,iposx,TRUE); + ih->data->posx = (float)posx; + + cb = (IFniff)IupGetCallback(ih,"SCROLL_CB"); + if (cb) + cb(ih,op,(float)posx,ih->data->posy); + else + { + IFnff cb = (IFnff)IupGetCallback(ih,"ACTION"); + if (cb) + cb (ih, (float)posx, ih->data->posy); + } +} + +static void winCanvasUpdateVerScroll(Ihandle* ih, WORD winop) +{ + IFniff cb; + double ymin, ymax, posy, liney; + int ipagey, iposy, iliney, op; + + /* unused */ + if (winop == SB_TOP || + winop == SB_BOTTOM || + winop == SB_ENDSCROLL) + return; + + ymax = iupAttribGetFloat(ih,"YMAX"); + ymin = iupAttribGetFloat(ih,"YMIN"); + + winCanvasGetScrollInfo(ih->handle, &iposy, &ipagey, SB_VERT, winop==SB_THUMBTRACK? 1: 0); + + if (!iupAttribGet(ih, "LINEY")) + { + iliney = ipagey/10; + if (!iliney) + iliney = 1; + } + else + { + /* line and page convertions are the same */ + liney = iupAttribGetFloat(ih,"LINEY"); + iupCanvasCalcScrollIntPos(ymin, ymax, liney, 0, + IUP_SB_MIN, IUP_SB_MAX, &iliney, NULL); + } + + switch (winop) + { + case SB_LINEDOWN: + iposy = iposy + iliney; + op = IUP_SBDN; + break; + case SB_LINEUP: + iposy = iposy - iliney; + op = IUP_SBUP; + break; + case SB_PAGEDOWN: + iposy = iposy + ipagey; + op = IUP_SBPGDN; + break; + case SB_PAGEUP: + iposy = iposy - ipagey; + op = IUP_SBPGUP; + break; + case SB_THUMBTRACK: + op = IUP_SBDRAGV; + break; + case SB_THUMBPOSITION: + op = IUP_SBPOSV; + break; + default: + return; + } + + iupCanvasCalcScrollRealPos(ymin, ymax, &posy, + IUP_SB_MIN, IUP_SB_MAX, ipagey, &iposy); + + SetScrollPos(ih->handle,SB_VERT,iposy,TRUE); + ih->data->posy = (float)posy; + + cb = (IFniff)IupGetCallback(ih,"SCROLL_CB"); + if (cb) + cb(ih, op, ih->data->posx,(float)posy); + else + { + IFnff cb = (IFnff)IupGetCallback(ih,"ACTION"); + if (cb) + cb (ih, ih->data->posx, (float)posy); + } +} + +static int winCanvasProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + switch (msg) + { + case WM_ERASEBKGND: + /* only paint background if ACTION is not defined */ + if (!IupGetCallback(ih, "ACTION")) + { + RECT rect; + HDC hdc = (HDC)wp; + COLORREF color; + iupwinGetColorRef(ih, "BGCOLOR", &color); + GetClientRect(ih->handle, &rect); + FillRect(hdc, &rect, iupwinBrushGet(color)); + } + /* always return non zero value */ + *result = 1; + return 1; + case WM_PAINT: + { + IFnff cb = (IFnff)IupGetCallback(ih, "ACTION"); + if (cb) + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(ih->handle, &ps); + iupAttribSetStr(ih, "HDC_WMPAINT", (char*)&hdc); + iupAttribSetStrf(ih, "CLIPRECT", "%d %d %d %d", ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right-ps.rcPaint.left, ps.rcPaint.bottom-ps.rcPaint.top); + + cb(ih, ih->data->posx, ih->data->posy); + + iupAttribSetStr(ih, "CLIPRECT", NULL); + iupAttribSetStr(ih, "HDC_WMPAINT", NULL); + EndPaint(ih->handle, &ps); + } + break; + } + case WM_SIZE: + { + IFnii cb = (IFnii)IupGetCallback(ih, "RESIZE_CB"); + if (cb) + { + RECT rect; + GetClientRect(ih->handle, &rect); + cb(ih, rect.right-rect.left, rect.bottom-rect.top); + /* w=LOWORD (lp), h=HIWORD(lp) can not be used because and invalid size + at the first time of WM_SIZE with scroolbars. */ + } + *result = 0; + return 1; + } + case WM_GETDLGCODE: + /* avoid beeps when keys are pressed */ + *result = DLGC_WANTCHARS|DLGC_WANTARROWS; + return 1; + case WM_MOUSEWHEEL: + { + IFnfiis cb = (IFnfiis)IupGetCallback(ih, "WHEEL_CB"); + short delta = (short)HIWORD(wp); + if (cb) + { + char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; + POINT p; + p.x = LOWORD(lp); p.y = HIWORD(lp); + ScreenToClient(ih->handle, &p); + + iupwinButtonKeySetStatus(LOWORD(wp), status, 0); + + cb(ih, (float)delta/120.0f, p.x, p.y, status); + } + else + { + if (ih->data->sb & IUP_SB_VERT) + { + int i, winop = delta>0? SB_LINEUP: SB_LINEDOWN; + delta = (short)abs(delta/120); + for (i=0; i < delta; i++) + SendMessage(ih->handle, WM_VSCROLL, MAKELONG(winop, 0), 0); + } + } + + *result = 0; + return 1; + } + case WM_XBUTTONDBLCLK: + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + case WM_XBUTTONDOWN: + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + { + /* Force focus on canvas click */ + if (iupAttribGetBoolean(ih, "CANFOCUS")) + SetFocus(ih->handle); + + SetCapture(ih->handle); + + if (iupwinButtonDown(ih, msg, wp, lp)) + { + /* refresh the cursor, it could have been changed in BUTTON_CB */ + SendMessage(ih->handle, WM_SETCURSOR, (WPARAM)ih->handle, MAKELPARAM(1,WM_MOUSEMOVE)); + } + + if (msg==WM_XBUTTONDOWN || msg==WM_XBUTTONDBLCLK) + *result = 1; + else + *result = 0; + return 1; + } + case WM_MOUSEMOVE: + { + if (iupwinMouseMove(ih, msg, wp, lp)) + { + /* refresh the cursor, it could have been changed in MOTION_CB */ + SendMessage(ih->handle, WM_SETCURSOR, (WPARAM)ih->handle, MAKELPARAM(1,WM_MOUSEMOVE)); + } + + break; /* let iupwinBaseProc process enter/leavewin */ + } + case WM_XBUTTONUP: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + { + ReleaseCapture(); + + if (iupwinButtonUp(ih, msg, wp, lp)) + { + /* refresh the cursor, it could have been changed in BUTTON_CB */ + SendMessage(ih->handle, WM_SETCURSOR, (WPARAM)ih->handle, MAKELPARAM(1,WM_MOUSEMOVE)); + } + + *result = 0; + if (msg==WM_XBUTTONUP) + *result = 1; + return 1; + } + case WM_KILLFOCUS: + { + if (GetCapture() == ih->handle) + ReleaseCapture(); + break; + } + case WM_SETCURSOR: + { + if (ih->handle == (HWND)wp && LOWORD(lp)==HTCLIENT) + { + HCURSOR hCur = (HCURSOR)iupAttribGet(ih, "_IUPWIN_HCURSOR"); + if (hCur) + { + SetCursor(hCur); + *result = 1; + return 1; + } + else if (iupAttribGet(ih, "CURSOR")) + { + SetCursor(NULL); + *result = 1; + return 1; + } + } + break; + } + case WM_INITMENU: + /* abort capture if a menu is opened */ + ReleaseCapture(); + break; + case WM_VSCROLL: + winCanvasUpdateVerScroll(ih, LOWORD(wp)); + *result = 0; + return 1; + case WM_HSCROLL: + winCanvasUpdateHorScroll(ih, LOWORD(wp)); + *result = 0; + return 1; + } + + /* can be a container */ + if (ih->firstchild) + return iupwinBaseContainerProc(ih, msg, wp, lp, result); + else + return iupwinBaseProc(ih, msg, wp, lp, result); +} + +static void winCanvasRegisterClass(void) +{ + WNDCLASS wndclass; + ZeroMemory(&wndclass, sizeof(WNDCLASS)); + + wndclass.hInstance = iupwin_hinstance; + wndclass.lpszClassName = "IupCanvas"; + wndclass.lpfnWndProc = (WNDPROC)iupwinBaseWinProc; + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; /* using CS_OWNDC will minimize the work of cdActivate in the CD library */ + wndclass.hbrBackground = NULL; /* remove the background to optimize redraw */ + + RegisterClass(&wndclass); +} + +static int winCanvasMapMethod(Ihandle* ih) +{ + CLIENTCREATESTRUCT clientstruct; + void *clientdata = NULL; + char *classname; + DWORD dwStyle = WS_CHILD, dwExStyle = 0; + + if (!ih->parent) + return IUP_ERROR; + + if (ih->iclass->is_interactive) + { + if (iupAttribGetBoolean(ih, "CANFOCUS")) + dwStyle |= WS_TABSTOP; + } + + if (ih->firstchild) /* can be a container */ + { + dwStyle |= WS_CLIPSIBLINGS; + + if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED")) + dwExStyle |= WS_EX_COMPOSITED; + else + dwStyle |= WS_CLIPCHILDREN; + } + + if (iupAttribGetBoolean(ih, "MDICLIENT")) + { + /* creating a MDI Client that will be inside the MDI Frame, + it will work as parent of all MDI children */ + Ihandle *winmenu = IupGetAttributeHandle(ih, "MDIMENU"); + + classname = "mdiclient"; + + iupAttribSetStr(ih, "BORDER", "NO"); + + iupAttribSetStr(IupGetDialog(ih), "MDICLIENT_HANDLE", (char*)ih); + + clientdata = &clientstruct; + clientstruct.hWindowMenu = winmenu? winmenu->handle: NULL; + + /* The system increments the identifier + for each additional MDI child window the application creates, + and reassigns identifiers when the application + destroys a window to keep the range of identifiers contiguous. */ + clientstruct.idFirstChild = IUP_MDICHILD_START; + } + else + classname = "IupCanvas"; + + if (iupAttribGetBoolean(ih, "BORDER")) + dwStyle |= WS_BORDER; + + ih->data->sb = iupBaseGetScrollbar(ih); + if (ih->data->sb & IUP_SB_HORIZ) + dwStyle |= WS_HSCROLL; + if (ih->data->sb & IUP_SB_VERT) + dwStyle |= WS_VSCROLL; + + ih->serial = iupDialogGetChildId(ih); + + ih->handle = CreateWindowEx(dwExStyle,/* extended style */ + classname, /* window class */ + NULL, /* title */ + dwStyle, /* window style */ + 0, /* x-position */ + 0, /* y-position */ + 10, /* default width to avoid 0 */ + 10, /* default height to avoid 0 */ + iupChildTreeGetNativeParentHandle(ih), /* window parent */ + (HMENU)ih->serial, /* child identifier */ + iupwin_hinstance, /* instance of app. */ + clientdata); + + if (!ih->handle) + return IUP_ERROR; + + /* associate HWND with Ihandle*, all Win32 controls must call this. */ + iupwinHandleSet(ih); + + IupSetCallback(ih, "_IUPWIN_OLDPROC_CB", (Icallback)DefWindowProc); + IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winCanvasProc); + + /* configure for DRAG&DROP */ + if (IupGetCallback(ih, "DROPFILES_CB")) + iupAttribSetStr(ih, "DRAGDROP", "YES"); + + return IUP_NOERROR; +} + +static void winCanvasMDICloseChildren(Ihandle* client) +{ + HWND hWndChild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0); + + /* As long as the MDI client has a child, close it */ + while (hWndChild) + { + Ihandle* child = iupwinHandleGet(hWndChild); + if (iupObjectCheck(child) && iupAttribGetBoolean(child, "MDICHILD")) + IupDestroy(child); + + hWndChild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0); + } +} + +static void winCanvasUnMapMethod(Ihandle* ih) +{ + if (iupAttribGetBoolean(ih, "MDICLIENT")) + { + /* hide the MDI client window to avoid multiple re-paints */ + ShowWindow(ih->handle, SW_HIDE); + + /* must destroy all MDI Children */ + winCanvasMDICloseChildren(ih); + + DestroyWindow(ih->handle); + + /* mdiclient class is not a IUP class, must return here */ + return; + } + + /* remove the association before destroying */ + iupwinHandleRemove(ih); + + /* remove from parent and destroys window */ + SetParent(ih->handle, NULL); + DestroyWindow(ih->handle); +} + +static void winCanvasReleaseMethod(Iclass* ic) +{ + (void)ic; + if (iupwinClassExist("IupCanvas")) + UnregisterClass("IupCanvas", iupwin_hinstance); +} + +void iupdrvCanvasInitClass(Iclass* ic) +{ + if (!iupwinClassExist("IupCanvas")) + winCanvasRegisterClass(); + + /* Driver Dependent Class functions */ + ic->Map = winCanvasMapMethod; + ic->UnMap = winCanvasUnMapMethod; + ic->Release = winCanvasReleaseMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winCanvasSetBgColorAttrib, "255 255 255", NULL, IUPAF_DEFAULT); /* force new default value */ + + /* IupCanvas only */ + iupClassRegisterAttribute(ic, "DRAWSIZE", iupdrvBaseGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "DX", NULL, winCanvasSetDXAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "DY", NULL, winCanvasSetDYAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "POSX", iupCanvasGetPosXAttrib, winCanvasSetPosXAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "POSY", iupCanvasGetPosYAttrib, winCanvasSetPosYAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "XAUTOHIDE", NULL, NULL, "YES", NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "YAUTOHIDE", NULL, NULL, "YES", NULL, IUPAF_NOT_MAPPED); + + /* IupCanvas Windows only */ + iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "HWND", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT); +} diff --git a/iup/src/win/iupwin_clipboard.c b/iup/src/win/iupwin_clipboard.c new file mode 100755 index 0000000..1e0fab4 --- /dev/null +++ b/iup/src/win/iupwin_clipboard.c @@ -0,0 +1,190 @@ +/** \file + * \brief Clipboard for the Windows Driver. + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_image.h" + +#include "iupwin_drv.h" + + +static int winClipboardSetTextAttrib(Ihandle *ih, const char *value) +{ + HANDLE hHandle; + void* clip_str; + int size = strlen(value)+1; + (void)ih; + + if (!OpenClipboard(NULL)) + return 0; + + hHandle = GlobalAlloc(GMEM_MOVEABLE, size); + if (!hHandle) + return 0; + + clip_str = GlobalLock(hHandle); + CopyMemory(clip_str, value, size); + GlobalUnlock(hHandle); + + EmptyClipboard(); + SetClipboardData(CF_TEXT, hHandle); + CloseClipboard(); + + return 0; +} + +static char* winClipboardGetTextAttrib(Ihandle *ih) +{ + HANDLE hHandle; + char* str; + (void)ih; + + if (!OpenClipboard(NULL)) + return NULL; + + hHandle = GetClipboardData(CF_TEXT); + if (!hHandle) + { + CloseClipboard(); + return NULL; + } + + str = iupStrGetMemoryCopy((char*)GlobalLock(hHandle)); + + GlobalUnlock(hHandle); + CloseClipboard(); + return str; +} + +static int winClipboardSetImageAttrib(Ihandle *ih, const char *value) +{ + HBITMAP hBitmap; + + if (!OpenClipboard(NULL)) + return 0; + + hBitmap = (HBITMAP)iupImageGetImage(value, ih, 0); + iupImageClearCache(ih, hBitmap); + + EmptyClipboard(); + SetClipboardData(CF_BITMAP, (HANDLE)hBitmap); + CloseClipboard(); + + return 0; +} + +static int winClipboardSetNativeImageAttrib(Ihandle *ih, const char *value) +{ + if (!OpenClipboard(NULL)) + return 0; + + EmptyClipboard(); + SetClipboardData(CF_DIB, (HANDLE)value); + CloseClipboard(); + + (void)ih; + return 0; +} + +static HANDLE winCopyHandle(HANDLE hHandle) +{ + void *src_data, *dst_data; + SIZE_T size = GlobalSize(hHandle); + HANDLE hNewHandle = GlobalAlloc(GMEM_MOVEABLE, size); + if (!hNewHandle) + return NULL; + + src_data = GlobalLock(hHandle); + dst_data = GlobalLock(hNewHandle); + CopyMemory(dst_data, src_data, size); + GlobalUnlock(hHandle); + GlobalUnlock(hNewHandle); + + return hNewHandle; +} + +static char* winClipboardGetNativeImageAttrib(Ihandle *ih) +{ + HANDLE hHandle; + + if (!OpenClipboard(NULL)) + return 0; + + hHandle = GetClipboardData(CF_DIB); + if (!hHandle) + { + CloseClipboard(); + return NULL; + } + + hHandle = winCopyHandle(hHandle); /* must duplicate because CloseClipboard will invalidate the handle */ + CloseClipboard(); + + (void)ih; + return (char*)hHandle; +} + +static char* winClipboardGetTextAvailableAttrib(Ihandle *ih) +{ + int check; + (void)ih; + OpenClipboard(NULL); + check = IsClipboardFormatAvailable(CF_TEXT); + CloseClipboard(); + if (check) + return "YES"; + else + return "NO"; +} + +static char* winClipboardGetImageAvailableAttrib(Ihandle *ih) +{ + int check; + (void)ih; + OpenClipboard(NULL); + check = IsClipboardFormatAvailable(CF_DIB); + CloseClipboard(); + if (check) + return "YES"; + else + return "NO"; +} + +/******************************************************************************/ + +Ihandle* IupClipboard(void) +{ + return IupCreate("clipboard"); +} + +Iclass* iupClipboardGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "clipboard"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPECONTROL; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 0; + + /* Attribute functions */ + iupClassRegisterAttribute(ic, "TEXT", winClipboardGetTextAttrib, winClipboardSetTextAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NATIVEIMAGE", winClipboardGetNativeImageAttrib, winClipboardSetNativeImageAttrib, NULL, NULL, IUPAF_NO_STRING|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE", NULL, winClipboardSetImageAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TEXTAVAILABLE", winClipboardGetTextAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGEAVAILABLE", winClipboardGetImageAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} diff --git a/iup/src/win/iupwin_colordlg.c b/iup/src/win/iupwin_colordlg.c new file mode 100755 index 0000000..f0baa79 --- /dev/null +++ b/iup/src/win/iupwin_colordlg.c @@ -0,0 +1,133 @@ +/** \file + * \brief IupColorDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> +#include <stdio.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_dialog.h" + + +#define IUP_COLOR_RED 706 + +static UINT_PTR winColorDlgHookProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) +{ + (void)wParam; + if (uiMsg == WM_INITDIALOG) + { + HWND hWndItem; + CHOOSECOLOR* choosecolor = (CHOOSECOLOR*)lParam; + Ihandle* ih = (Ihandle*)choosecolor->lCustData; + + char* value = iupAttribGet(ih, "TITLE"); + if (value) + SetWindowText(hWnd, value); + + ih->handle = hWnd; + iupDialogUpdatePosition(ih); + ih->handle = NULL; /* reset handle */ + iupAttribSetStr(ih, "HWND", (char*)hWnd); /* used by HELP_CB in winDialogBaseProc */ + + hWndItem = GetDlgItem(hWnd, IUP_COLOR_RED); + SetFocus(hWndItem); + } + return 0; +} + +static char* winColorDlgColorsToString(COLORREF* lpCustColors) +{ + int i, inc, off = 0; + char iup_str[20]; + char* str = iupStrGetMemory(300); + for (i=0; i < 16; i++) + { + inc = sprintf(iup_str, "%d %d %d;", (int)GetRValue(*lpCustColors), (int)GetGValue(*lpCustColors), (int)GetBValue(*lpCustColors)); + memcpy(str+off, iup_str, inc); + off += inc; + lpCustColors++; + } + str[off-1] = 0; /* remove last separator */ + return str; +} + +static void winColorDlgStringToColors(char* str, COLORREF* lpCustColors) +{ + int i = 0; + unsigned char r, g, b; + + while (str && *str && i < 16) + { + if (iupStrToRGB(str, &r, &g, &b)) + *lpCustColors = RGB(r,g,b); + + str = strchr(str, ';'); + if (str) str++; + i++; + lpCustColors++; + } +} + +static int winColorDlgPopup(Ihandle* ih, int x, int y) +{ + InativeHandle* parent = iupDialogGetNativeParent(ih); + CHOOSECOLOR choosecolor; + unsigned char r, g, b; + COLORREF lpCustColors[16]; + char* value; + + iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */ + iupAttribSetInt(ih, "_IUPDLG_Y", y); + + if (!parent) + parent = GetActiveWindow(); + + iupStrToRGB(iupAttribGet(ih, "VALUE"), &r, &g, &b); + + ZeroMemory(lpCustColors, 16*sizeof(COLORREF)); + + value = iupAttribGetStr(ih, "COLORTABLE"); + if (value) + winColorDlgStringToColors(value, lpCustColors); + + ZeroMemory(&choosecolor, sizeof(CHOOSECOLOR)); + choosecolor.lStructSize = sizeof(CHOOSECOLOR); + choosecolor.hwndOwner = parent; + choosecolor.rgbResult = RGB(r, g, b); + choosecolor.lpCustColors = lpCustColors; + choosecolor.lCustData = (LPARAM)ih; + + choosecolor.Flags = CC_RGBINIT|CC_FULLOPEN; + if (IupGetCallback(ih, "HELP_CB")) + choosecolor.Flags |= CC_SHOWHELP; + + choosecolor.Flags |= CC_ENABLEHOOK; + choosecolor.lpfnHook = (LPCCHOOKPROC)winColorDlgHookProc; + + if (!ChooseColor(&choosecolor)) + { + iupAttribSetStr(ih, "VALUE", NULL); + iupAttribSetStr(ih, "COLORTABLE", NULL); + iupAttribSetStr(ih, "STATUS", NULL); + return IUP_NOERROR; + } + + iupAttribSetStrf(ih, "VALUE", "%d %d %d", GetRValue(choosecolor.rgbResult), + GetGValue(choosecolor.rgbResult), + GetBValue(choosecolor.rgbResult)); + iupAttribSetStr(ih, "COLORTABLE", winColorDlgColorsToString(lpCustColors)); + iupAttribSetStr(ih, "STATUS", "1"); + + return IUP_NOERROR; +} + +void iupdrvColorDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = winColorDlgPopup; +} diff --git a/iup/src/win/iupwin_common.c b/iup/src/win/iupwin_common.c new file mode 100755 index 0000000..a1a7c0f --- /dev/null +++ b/iup/src/win/iupwin_common.c @@ -0,0 +1,865 @@ +/** \file + * \brief Windows Base Procedure + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <windows.h> +#include <commctrl.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_key.h" +#include "iup_str.h" +#include "iup_class.h" +#include "iup_attrib.h" +#include "iup_focus.h" +#include "iup_image.h" +#include "iup_dialog.h" +#include "iup_drvinfo.h" +#include "iup_drv.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" +#include "iupwin_brush.h" + + +#ifndef XBUTTON1 +#define XBUTTON1 0x0001 /* not defined in MingW3 */ +#endif + +int iupwinClassExist(const char* name) +{ + WNDCLASS WndClass; + if (GetClassInfo(iupwin_hinstance, name, &WndClass)) + return 1; + return 0; +} + +int iupwinGetScreenRes(void) +{ + int res; + HDC ScreenDC = GetDC(NULL); + res = GetDeviceCaps(ScreenDC, LOGPIXELSY); + ReleaseDC(NULL, ScreenDC); + return res; +} + +void iupdrvActivate(Ihandle* ih) +{ + /* do not use BM_CLICK because it changes the focus + and does not animates the button press */ + SendMessage(ih->handle, BM_SETSTATE, TRUE, 0); + IupFlush(); + Sleep(150); + SendMessage(GetParent(ih->handle), WM_COMMAND, MAKEWPARAM(0, BN_CLICKED), (LPARAM)ih->handle); + SendMessage(ih->handle, BM_SETSTATE, FALSE, 0); +} + +WCHAR* iupwinStrChar2Wide(const char* str) +{ + if (str) + { + int len = strlen(str)+1; + WCHAR* wstr = malloc(len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, len); + return wstr; + } + + return NULL; +} + +int iupdrvGetScrollbarSize(void) +{ + int xv = GetSystemMetrics(SM_CXVSCROLL); + int yh = GetSystemMetrics(SM_CYHSCROLL); + return xv > yh ? xv : yh; +} + +void iupdrvReparent(Ihandle* ih) +{ + SetParent(ih->handle, iupChildTreeGetNativeParentHandle(ih)); +} + +void iupdrvBaseLayoutUpdateMethod(Ihandle *ih) +{ + SetWindowPos(ih->handle, NULL, ih->x, ih->y, ih->currentwidth, ih->currentheight, + SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER); +} + +void iupdrvDisplayRedraw(Ihandle *ih) +{ + /* REDRAW Now */ + RedrawWindow(ih->handle,NULL,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_NOCHILDREN|RDW_UPDATENOW); +} + +void iupdrvDisplayUpdate(Ihandle *ih) +{ + /* Post a REDRAW */ + RedrawWindow(ih->handle,NULL,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_NOCHILDREN); +} + +void iupdrvScreenToClient(Ihandle* ih, int *x, int *y) +{ + POINT p; + p.x = *x; + p.y = *y; + ScreenToClient(ih->handle, &p); + *x = p.x; + *y = p.y; +} + +static void winTrackMouse(HWND hwnd, int enter) +{ + TRACKMOUSEEVENT mouse; + mouse.cbSize = sizeof(TRACKMOUSEEVENT); + + if (enter) + mouse.dwFlags = TME_HOVER; + else + mouse.dwFlags = TME_LEAVE; + + mouse.hwndTrack = hwnd; + mouse.dwHoverTime = 1; + TrackMouseEvent(&mouse); +} + +static void winCallEnterLeaveWindow(Ihandle *ih, int enter) +{ + Icallback cb = NULL; + + if (!ih->iclass->is_interactive) + return; + + if (enter) + { + winTrackMouse(ih->handle, 0); + + if (!iupAttribGetInt(ih, "_IUPWIN_ENTERWIN")) + { + cb = IupGetCallback(ih,"ENTERWINDOW_CB"); + iupAttribSetStr(ih, "_IUPWIN_ENTERWIN", "1"); + } + } + else + { + cb = IupGetCallback(ih,"LEAVEWINDOW_CB"); + iupAttribSetStr(ih, "_IUPWIN_ENTERWIN", NULL); + } + + if (cb) + cb(ih); +} + +void iupwinMergeStyle(Ihandle* ih, DWORD old_mask, DWORD value) +{ + DWORD dwStyle = GetWindowLong(ih->handle, GWL_STYLE); + dwStyle &= ~(old_mask); /* clear old bits */ + dwStyle |= value; + SetWindowLong(ih->handle, GWL_STYLE, dwStyle); +} + +void iupwinSetStyle(Ihandle* ih, DWORD value, int set) +{ + DWORD dwStyle = GetWindowLong(ih->handle, GWL_STYLE); + if (set) + dwStyle |= value; + else + dwStyle &= ~(value); + SetWindowLong(ih->handle, GWL_STYLE, dwStyle); +} + +int iupwinBaseProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + (void)lp; + + switch (msg) + { + case WM_GETDLGCODE: + { + *result = DLGC_WANTALLKEYS; + return 1; + } + case WM_NOTIFY: /* usually sent only to parent, + but TIPs are configured to be handled here */ + { + NMHDR* msg_info = (NMHDR*)lp; + if (msg_info->code == TTN_GETDISPINFO) + iupwinTipsGetDispInfo(lp); + break; + } + case WM_DROPFILES: + iupwinDropFiles((HDROP)wp, ih); + break; + case WM_HELP: + { + Ihandle* child; + HELPINFO* help_info = (HELPINFO*)lp; + + if (help_info->iContextType == HELPINFO_MENUITEM) + child = iupwinMenuGetItemHandle((HMENU)help_info->hItemHandle, (int)help_info->iCtrlId); + else + child = iupwinHandleGet(help_info->hItemHandle); + + if (child) + { + Icallback cb = (Icallback) IupGetCallback(child, "HELP_CB"); + if (cb) + { + if (cb(child) == IUP_CLOSE) + IupExitLoop(); + + *result = 0; + return 1; /* abort default processing */ + } + } + break; + } + case WM_MOUSELEAVE: + winCallEnterLeaveWindow(ih, 0); + break; + case WM_MOUSEMOVE: + winCallEnterLeaveWindow(ih, 1); + break; + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + if (!iupwinKeyEvent(ih, (int)wp, 1)) + { + *result = 0; + return 1; /* abort default processing */ + } + break; + case WM_SYSKEYUP: + case WM_KEYUP: + { + int ret; + if (wp == VK_SNAPSHOT) /* called only on key up */ + { + ret = iupwinKeyEvent(ih, (int)wp, 1); + if (ret && iupObjectCheck(ih)) + ret = iupwinKeyEvent(ih, (int)wp, 0); + } + else + ret = iupwinKeyEvent(ih, (int)wp, 0); + + if (!ret) + { + *result = 0; + return 1; /* abort default processing */ + } + + break; + } + case WM_SETFOCUS: + iupwinWmSetFocus(ih); + break; + case WM_KILLFOCUS: + iupCallKillFocusCb(ih); + break; + case WOM_CLOSE: + case WOM_DONE: + case WOM_OPEN: + { + IFni cb = (IFni)IupGetCallback(ih, "WOM_CB"); + if (cb) + { + int v = -2; /* Error */ + switch(msg) + { + case WOM_OPEN: v = 1; break; + case WOM_DONE: v = 0; break; + case WOM_CLOSE: v = -1; break; + } + cb(ih, v); + } + break; + } + } + + return 0; +} + +LRESULT CALLBACK iupwinBaseWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + int ret = 0; + LRESULT result = 0; + IwinProc winProc; + WNDPROC oldProc; + Ihandle *ih; + + ih = iupwinHandleGet(hwnd); + if (!ih) + return DefWindowProc(hwnd, msg, wp, lp); /* should never happen */ + + /* retrieve the control previous procedure for subclassing */ + oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB"); + + /* check if the element defines a custom procedure */ + winProc = (IwinProc)IupGetCallback(ih, "_IUPWIN_CTRLPROC_CB"); + if (winProc) + ret = winProc(ih, msg, wp, lp, &result); + else + ret = iupwinBaseProc(ih, msg, wp, lp, &result); + + if (ret) + return result; + else + return CallWindowProc(oldProc, hwnd, msg, wp, lp); +} + +static Ihandle* winContainerWmCommandGetIhandle(Ihandle *ih, WPARAM wp, LPARAM lp) +{ + /* WPARAM - if HIWORD is 0 if the message is from a menu. + or HIWORD is 1 if the message is from an accelerator. + or HIWORD is the notification code if the message is from a control. + LOWORD is the identifier. + LPARAM - the control sending the message or 0. */ + + Ihandle *child = NULL; + + if (HIWORD(wp)==0 && lp==0 && LOWORD(wp)>10) + { + Ihandle* dlg_menu = IupGetAttributeHandle(ih, "MENU"); + if (dlg_menu) + child = iupwinMenuGetItemHandle((HMENU)dlg_menu->handle, LOWORD(wp)); /* menu */ + } + else + { + if (lp==0) + child = ih; /* native parent */ + else + { + child = iupwinHandleGet((void*)lp); /* control */ + if (!child) + child = iupwinHandleGet((void*)GetParent((HWND)lp)); /* control */ + } + } + + return child; +} + +int iupwinBaseContainerProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + /* All messages here are sent to the parent Window, + but they are usefull for child controls. */ + + switch (msg) + { + case WM_COMMAND: + { + Ihandle* child = winContainerWmCommandGetIhandle(ih, wp, lp); + if (child) + { + IFnii cb = (IFnii)IupGetCallback(child, "_IUPWIN_COMMAND_CB"); + if (cb) + cb(child, wp, lp); + } + + break; + } + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORBTN: + case WM_CTLCOLORSCROLLBAR: + case WM_CTLCOLORSTATIC: + { + Ihandle* child = iupwinHandleGet((void*)lp); + if (child) + { + IFctlColor cb = (IFctlColor)IupGetCallback(child, "_IUPWIN_CTLCOLOR_CB"); + if (cb) + return cb(child, (HDC)wp, result); + } + break; + } + case WM_DRAWITEM: /* for OWNERDRAW controls */ + { + Ihandle *child = NULL; + DRAWITEMSTRUCT *drawitem = (LPDRAWITEMSTRUCT)lp; + if (!drawitem) + break; + + if (wp == 0) /* a menu */ + child = iupwinMenuGetItemHandle((HMENU)drawitem->hwndItem, drawitem->itemID); + else + child = iupwinHandleGet(drawitem->hwndItem); + + if (child) + { + IFdrawItem cb = (IFdrawItem)IupGetCallback(child, "_IUPWIN_DRAWITEM_CB"); + if (cb) + { + cb(child, (void*)drawitem); + *result = TRUE; + return 1; + } + } + break; + } + case WM_HSCROLL: + case WM_VSCROLL: + { + Ihandle *child = iupwinHandleGet((void*)lp); + if (child) + { + IFni cb = (IFni)IupGetCallback(child, "_IUPWIN_CUSTOMSCROLL_CB"); + if (cb) + cb(child, LOWORD(wp)); + } + break; + } + case WM_NOTIFY: /* Currently, the following controls support custom draw functionality: + Header, List-view, Rebar, Toolbar, ToolTip, Trackbar, Tree-view. + And for Button if using Windows XP Style. */ + { + Ihandle *child; + NMHDR* msg_info = (NMHDR*)lp; + if (!msg_info) + break; + + child = iupwinHandleGet(msg_info->hwndFrom); + if (child) + { + IFnotify cb = (IFnotify)IupGetCallback(child, "_IUPWIN_NOTIFY_CB"); + if (cb) + { + if (cb(child, (void*)msg_info, result)) + return 1; + } + } + break; + } + } + + return iupwinBaseProc(ih, msg, wp, lp, result); +} + +void iupwinChangeProc(Ihandle *ih, WNDPROC new_proc) +{ + IupSetCallback(ih, "_IUPWIN_OLDPROC_CB", (Icallback)GetWindowLongPtr(ih->handle, GWLP_WNDPROC)); + SetWindowLongPtr(ih->handle, GWLP_WNDPROC, (LONG_PTR)new_proc); +} + +void iupdrvBaseUnMapMethod(Ihandle* ih) +{ + WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB"); + if (oldProc) + { + SetWindowLongPtr(ih->handle, GWLP_WNDPROC, (LONG_PTR)oldProc); + IupSetCallback(ih, "_IUPWIN_OLDPROC_CB", NULL); + } + + /* remove the association before destroying */ + iupwinHandleRemove(ih); + + /* destroys window (it will remove from parent) */ + DestroyWindow(ih->handle); +} + +void iupwinDropFiles(HDROP hDrop, Ihandle *ih) +{ + char *filename; + int i, numFiles, numchar, ret; + POINT point; + + IFnsiii cb = (IFnsiii)IupGetCallback(ih, "DROPFILES_CB"); + if (!cb) return; + + numFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); + DragQueryPoint(hDrop, &point); + for (i = 0; i < numFiles; i++) + { + numchar = DragQueryFile(hDrop, i, NULL, 0); + filename = malloc(numchar+1); + if (!filename) + break; + + DragQueryFile(hDrop, i, filename, numchar+1); + + ret = cb(ih, filename, numFiles-i-1, (int) point.x, (int) point.y); + + free(filename); + + if (ret == IUP_IGNORE) + break; + } + DragFinish(hDrop); +} + +int iupwinGetColorRef(Ihandle *ih, char *name, COLORREF *color) +{ + unsigned char r, g, b; + /* must use IupGetAttribute to use inheritance */ + if (iupStrToRGB(IupGetAttribute(ih, name), &r, &g, &b)) + { + *color = RGB(r,g,b); + return 1; + } + return 0; +} + +int iupwinGetParentBgColor(Ihandle* ih, COLORREF* cr) +{ + unsigned char r, g, b; + char* color = iupBaseNativeParentGetBgColorAttrib(ih); + if (iupStrToRGB(color, &r, &g, &b)) + { + *cr = RGB(r,g,b); + return 1; + } + return 0; +} + +int iupdrvBaseSetZorderAttrib(Ihandle* ih, const char* value) +{ + if (IsWindowVisible(ih->handle)) + { + if (iupStrEqualNoCase(value, "TOP")) + SetWindowPos(ih->handle, HWND_TOP, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE); + else + SetWindowPos(ih->handle, HWND_BOTTOM, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE); + } + + return 0; +} + +void iupdrvSetVisible(Ihandle* ih, int visible) +{ + ShowWindow(ih->handle, visible? SW_SHOWNORMAL: SW_HIDE); +} + +int iupdrvIsVisible(Ihandle* ih) +{ + return IsWindowVisible(ih->handle); +} + +int iupdrvIsActive(Ihandle* ih) +{ + return IsWindowEnabled(ih->handle); +} + +void iupdrvSetActive(Ihandle* ih, int enable) +{ + EnableWindow(ih->handle, enable); +} + +int iupdrvBaseSetTitleAttrib(Ihandle* ih, const char* value) +{ + if (!value) value = ""; + SetWindowText(ih->handle, value); + return 0; +} + +char* iupdrvBaseGetTitleAttrib(Ihandle* ih) +{ + int nc = GetWindowTextLength(ih->handle); + if (nc) + { + char* str = iupStrGetMemory(nc+1); + GetWindowText(ih->handle, str, nc+1); + return str; + } + else + return NULL; +} + +int iupwinSetDragDropAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + DragAcceptFiles(ih->handle, TRUE); + else + DragAcceptFiles(ih->handle, FALSE); + return 1; +} + +char *iupdrvBaseGetXAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(20); + RECT rect; + GetWindowRect(ih->handle, &rect); + sprintf(str, "%d", (int)rect.left); + return str; +} + +char *iupdrvBaseGetYAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(20); + RECT rect; + GetWindowRect(ih->handle, &rect); + sprintf(str, "%d", (int)rect.top); + return str; +} + +char* iupdrvBaseGetClientSizeAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(20); + RECT rect; + GetClientRect(ih->handle, &rect); + sprintf(str, "%dx%d", (int)(rect.right-rect.left), (int)(rect.bottom-rect.top)); + return str; +} + +#ifndef IDC_HAND +#define IDC_HAND MAKEINTRESOURCE(32649) +#endif +#ifndef IDC_APPSTARTING +#define IDC_APPSTARTING MAKEINTRESOURCE(32650) +#endif +#ifndef IDC_HELP +#define IDC_HELP MAKEINTRESOURCE(32651) +#endif + +static HCURSOR winGetCursor(Ihandle* ih, const char* name) +{ + static struct { + const char* iupname; + const char* sysname; + } table[] = { + {"NONE", NULL}, + {"NULL", NULL}, + {"ARROW", IDC_ARROW}, + {"BUSY", IDC_WAIT}, + {"CROSS", IDC_CROSS}, + {"HAND", IDC_HAND}, + {"MOVE", IDC_SIZEALL}, + {"RESIZE_N", IDC_SIZENS}, + {"RESIZE_S", IDC_SIZENS}, + {"RESIZE_NS", IDC_SIZENS}, + {"RESIZE_W", IDC_SIZEWE}, + {"RESIZE_E", IDC_SIZEWE}, + {"RESIZE_WE", IDC_SIZEWE}, + {"RESIZE_NE", IDC_SIZENESW}, + {"RESIZE_SE", IDC_SIZENWSE}, + {"RESIZE_NW", IDC_SIZENWSE}, + {"RESIZE_SW", IDC_SIZENESW}, + {"TEXT", IDC_IBEAM}, + {"HELP", IDC_HELP}, + {"IUP", IDC_HELP}, + {"NO", IDC_NO}, + {"UPARROW", IDC_UPARROW}, + {"APPSTARTING", IDC_APPSTARTING} + }; + + HCURSOR cur; + char str[50]; + int i, count = sizeof(table)/sizeof(table[0]); + + /* check the cursor cache first (per control)*/ + sprintf(str, "_IUPWIN_CURSOR_%s", name); + cur = (HCURSOR)iupAttribGet(ih, str); + if (cur) + return cur; + + /* check the pre-defined IUP names first */ + for (i = 0; i < count; i++) + { + if (iupStrEqualNoCase(name, table[i].iupname)) + { + if (table[i].sysname) + cur = LoadCursor(NULL, table[i].sysname); + else + cur = NULL; + + break; + } + } + + if (i == count) + { + /* check other system cursors */ + /* cursor PEN is handled here */ + if (iupStrEqualNoCase(name, "PEN")) + name = "CURSOR_PEN"; + + /* check for an name defined cursor */ + cur = iupImageGetCursor(name); + } + + iupAttribSetStr(ih, str, (char*)cur); + return cur; +} + +int iupdrvBaseSetCursorAttrib(Ihandle* ih, const char* value) +{ + /* Cursor can be NULL in Windows. */ + HCURSOR hCur = winGetCursor(ih, value); + iupAttribSetStr(ih, "_IUPWIN_HCURSOR", (char*)hCur); /* To be used in WM_SETCURSOR */ + /* refresh the cursor */ + SendMessage(ih->handle, WM_SETCURSOR, (WPARAM)ih->handle, MAKELPARAM(1,WM_MOUSEMOVE)); + return 1; +} + +void iupdrvBaseRegisterCommonAttrib(Iclass* ic) +{ + iupClassRegisterAttribute(ic, "HFONT", iupwinGetHFontAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); +} + +int iupwinButtonDown(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp) +{ + char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; + int ret, doubleclick = 0; + int b = 0; + + IFniiiis cb = (IFniiiis) IupGetCallback(ih, "BUTTON_CB"); + if (!cb) + return 0; + + if (msg==WM_XBUTTONDBLCLK || + msg==WM_LBUTTONDBLCLK || + msg==WM_MBUTTONDBLCLK || + msg==WM_RBUTTONDBLCLK) + doubleclick = 1; + + iupwinButtonKeySetStatus(LOWORD(wp), status, doubleclick); + + if (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONDBLCLK) + b = IUP_BUTTON1; + else if (msg==WM_MBUTTONDOWN || msg==WM_MBUTTONDBLCLK) + b = IUP_BUTTON2; + else if (msg==WM_RBUTTONDOWN || msg==WM_RBUTTONDBLCLK) + b = IUP_BUTTON3; + else if (msg==WM_XBUTTONDOWN || msg==WM_XBUTTONDBLCLK) + { + if (HIWORD(wp) == XBUTTON1) + b = IUP_BUTTON4; + else + b = IUP_BUTTON5; + } + + ret = cb(ih, b, 1, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp), status); + if (ret == IUP_CLOSE) + IupExitLoop(); + else if (ret == IUP_IGNORE) + return -1; + + return 1; +} + +int iupwinButtonUp(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp) +{ + char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; + int ret, b=0; + IFniiiis cb = (IFniiiis) IupGetCallback(ih, "BUTTON_CB"); + if (!cb) + return 0; + + iupwinButtonKeySetStatus(LOWORD(wp), status, 0); + + /* also updates the button status, since wp could not have the flag */ + if (msg==WM_LBUTTONUP) + { + b = IUP_BUTTON1; + iupKEYSETBUTTON1(status); + } + else if (msg==WM_MBUTTONUP) + { + b = IUP_BUTTON2; + iupKEYSETBUTTON2(status); + } + else if (msg==WM_RBUTTONUP) + { + b = IUP_BUTTON3; + iupKEYSETBUTTON3(status); + } + else if (msg==WM_XBUTTONUP) + { + if (HIWORD(wp) == XBUTTON1) + { + b = IUP_BUTTON4; + iupKEYSETBUTTON4(status); + } + else + { + b = IUP_BUTTON5; + iupKEYSETBUTTON5(status); + } + } + + ret = cb(ih, b, 0, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp), status); + if (ret == IUP_CLOSE) + IupExitLoop(); + else if (ret == IUP_IGNORE) + return -1; + + return 1; +} + +int iupwinMouseMove(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp) +{ + IFniis cb = (IFniis)IupGetCallback(ih, "MOTION_CB"); + if (cb) + { + char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; + iupwinButtonKeySetStatus(LOWORD(wp), status, 0); + cb(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp), status); + return 1; + } + (void)msg; + return 0; +} + +int iupwinCreateWindowEx(Ihandle* ih, LPCSTR lpClassName, DWORD dwExStyle, DWORD dwStyle) +{ + ih->serial = iupDialogGetChildId(ih); + + ih->handle = CreateWindowEx(dwExStyle, /* extended window style */ + lpClassName, /* window class */ + NULL, /* title */ + dwStyle, /* window style */ + 0, /* x-position */ + 0, /* y-position */ + 10, /* default width to avoid 0 */ + 10, /* default height to avoid 0 */ + iupChildTreeGetNativeParentHandle(ih), /* window parent */ + (HMENU)ih->serial, /* child identifier */ + iupwin_hinstance, /* instance of app. */ + NULL); + + if (!ih->handle) + return 0; + + /* associate HWND with Ihandle*, all Win32 controls must call this. */ + iupwinHandleSet(ih); + + /* replace the WinProc to handle base callbacks */ + iupwinChangeProc(ih, iupwinBaseWinProc); + + return 1; +} + +char* iupwinGetClipboardText(Ihandle* ih) +{ + HANDLE Handle; + char* str; + + if (!IsClipboardFormatAvailable(CF_TEXT)) + return NULL; + + if (!OpenClipboard(ih->handle)) + return NULL; + + Handle = GetClipboardData(CF_TEXT); + if (!Handle) + { + CloseClipboard(); + return NULL; + } + + str = (char*)GlobalLock(Handle); + str = iupStrDup(str); + + GlobalUnlock(Handle); + + CloseClipboard(); + + return str; +} diff --git a/iup/src/win/iupwin_dialog.c b/iup/src/win/iupwin_dialog.c new file mode 100755 index 0000000..39fdc0c --- /dev/null +++ b/iup/src/win/iupwin_dialog.c @@ -0,0 +1,1439 @@ +/** \file + * \brief IupDialog class + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_dlglist.h" +#include "iup_attrib.h" +#include "iup_drv.h" +#include "iup_drvinfo.h" +#include "iup_drvfont.h" +#include "iup_focus.h" +#include "iup_str.h" +#define _IUPDLG_PRIVATE +#include "iup_dialog.h" +#include "iup_image.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" +#include "iupwin_brush.h" +#include "iupwin_info.h" + + +#define IWIN_TRAY_NOTIFICATION 102 + +static int WM_HELPMSG; + +static int winDialogSetBgColorAttrib(Ihandle* ih, const char* value); +static int winDialogSetTrayAttrib(Ihandle *ih, const char *value); + +/**************************************************************** + Utilities +****************************************************************/ + +int iupdrvDialogIsVisible(Ihandle* ih) +{ + return iupdrvIsVisible(ih); +} + +void iupdrvDialogUpdateSize(Ihandle* ih) +{ + RECT rect; + GetWindowRect(ih->handle, &rect); + ih->currentwidth = rect.right-rect.left; + ih->currentheight = rect.bottom-rect.top; +} + +void iupdrvDialogGetSize(InativeHandle* handle, int *w, int *h) +{ + RECT rect; + GetWindowRect(handle, &rect); + if (w) *w = rect.right-rect.left; + if (h) *h = rect.bottom-rect.top; +} + +void iupdrvDialogSetVisible(Ihandle* ih, int visible) +{ + ShowWindow(ih->handle, visible? ih->data->cmd_show: SW_HIDE); +} + +void iupdrvDialogGetPosition(InativeHandle* handle, int *x, int *y) +{ + RECT rect; + GetWindowRect(handle, &rect); + if (x) *x = rect.left; + if (y) *y = rect.top; +} + +void iupdrvDialogSetPosition(Ihandle *ih, int x, int y) +{ + /* Only moves the window and places it at the top of the Z order. */ + SetWindowPos(ih->handle, HWND_TOP, x, y, 0, 0, SWP_NOSIZE); +} + +void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu) +{ + if (ih->data->menu) + *menu = iupdrvMenuGetMenuBarSize(ih->data->menu); + else + *menu = 0; + + if (ih->handle) + { + iupdrvGetWindowDecor(ih->handle, border, caption); + + if (*menu) + *caption -= *menu; + } + else + { + int has_titlebar = iupAttribGetBoolean(ih, "MAXBOX") || + iupAttribGetBoolean(ih, "MINBOX") || + iupAttribGetBoolean(ih, "MENUBOX") || + IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ + + *caption = 0; + if (has_titlebar) + { + if (iupAttribGetBoolean(ih, "TOOLBOX") && iupAttribGet(ih, "PARENTDIALOG")) + *caption = GetSystemMetrics(SM_CYSMCAPTION); /* tool window */ + else + *caption = GetSystemMetrics(SM_CYCAPTION); /* normal window */ + } + + *border = 0; + if (iupAttribGetBoolean(ih, "RESIZE")) + { + *border = GetSystemMetrics(SM_CXFRAME); /* Thickness of the sizing border around the perimeter of a window */ + } /* that can be resized, in pixels. */ + else if (has_titlebar) + { + *border = GetSystemMetrics(SM_CXFIXEDFRAME); /* Thickness of the frame around the perimeter of a window */ + } /* that has a caption but is not sizable, in pixels. */ + else if (iupAttribGetBoolean(ih, "BORDER")) + { + *border = GetSystemMetrics(SM_CXBORDER); + } + } +} + +int iupdrvDialogSetPlacement(Ihandle* ih) +{ + char* placement; + + ih->data->cmd_show = SW_SHOWNORMAL; + ih->data->show_state = IUP_SHOW; + + if (iupAttribGetBoolean(ih, "FULLSCREEN")) + return 1; + + placement = iupAttribGet(ih, "PLACEMENT"); + if (!placement) + { + if (IsIconic(ih->handle) || IsZoomed(ih->handle)) + ih->data->show_state = IUP_RESTORE; + return 0; + } + + if (iupStrEqualNoCase(placement, "MAXIMIZED")) + { + ih->data->cmd_show = SW_SHOWMAXIMIZED; + ih->data->show_state = IUP_MAXIMIZE; + } + else if (iupStrEqualNoCase(placement, "MINIMIZED")) + { + ih->data->cmd_show = SW_SHOWMINIMIZED; + ih->data->show_state = IUP_MINIMIZE; + } + else if (iupStrEqualNoCase(placement, "FULL")) + { + int width, height, x, y; + int caption, border, menu; + iupdrvDialogGetDecoration(ih, &border, &caption, &menu); + + /* the dialog will cover the task bar */ + iupdrvGetFullSize(&width, &height); + + /* position the decoration and menu outside the screen */ + x = -(border); + y = -(border+caption+menu); + + width += 2*border; + height += 2*border + caption + menu; + + /* set the new size and position */ + /* WM_SIZE will update the layout */ + SetWindowPos(ih->handle, HWND_TOP, x, y, width, height, 0); + + if (IsIconic(ih->handle) || IsZoomed(ih->handle)) + ih->data->show_state = IUP_RESTORE; + } + + iupAttribSetStr(ih, "PLACEMENT", NULL); /* reset to NORMAL */ + + return 1; +} + +static int winDialogMDICloseChildren(Ihandle* ih) +{ + Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE"); + if (iupObjectCheck(client)) + { + HWND hWndChild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0); + + /* As long as the MDI client has a child, close it */ + while (hWndChild) + { + Ihandle* child = iupwinHandleGet(hWndChild); + if (iupObjectCheck(child) && iupAttribGetBoolean(child, "MDICHILD")) + { + Icallback cb = IupGetCallback(child, "CLOSE_CB"); + if (cb) + { + int ret = cb(child); + if (ret == IUP_IGNORE) + return 0; + if (ret == IUP_CLOSE) + IupExitLoop(); + } + + IupDestroy(child); + } + + hWndChild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0); + } + } + return 1; +} + + +/**************************************************************************** + WindowProc +****************************************************************************/ + + +static Ihandle* winMinMaxHandle = NULL; + +static int winDialogCheckMinMaxInfo(Ihandle* ih, MINMAXINFO* minmax) +{ + int min_w = 1, min_h = 1; /* MINSIZE default value */ + int max_w = 65535, max_h = 65535; /* MAXSIZE default value */ + + iupStrToIntInt(iupAttribGet(ih, "MINSIZE"), &min_w, &min_h, 'x'); + iupStrToIntInt(iupAttribGet(ih, "MAXSIZE"), &max_w, &max_h, 'x'); + + minmax->ptMinTrackSize.x = min_w; + minmax->ptMinTrackSize.y = min_h; + minmax->ptMaxTrackSize.x = max_w; + minmax->ptMaxTrackSize.y = max_h; + + if (winMinMaxHandle == ih) + winMinMaxHandle = NULL; + + return 1; +} + +static void winDialogResize(Ihandle* ih, int width, int height) +{ + IFnii cb; + + iupdrvDialogUpdateSize(ih); + + cb = (IFnii)IupGetCallback(ih, "RESIZE_CB"); + if (!cb || cb(ih, width, height)!=IUP_IGNORE) /* width and height here are for the client area */ + { + ih->data->ignore_resize = 1; + IupRefresh(ih); + ih->data->ignore_resize = 0; + } +} + +static int winDialogBaseProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + if (iupwinBaseContainerProc(ih, msg, wp, lp, result)) + return 1; + + iupwinMenuDialogProc(ih, msg, wp, lp); + + switch (msg) + { + case WM_GETMINMAXINFO: + { + if (winDialogCheckMinMaxInfo(ih, (MINMAXINFO*)lp)) + { + *result = 0; + return 1; + } + break; + } + case WM_MOVE: + { + IFnii cb = (IFnii)IupGetCallback(ih, "MOVE_CB"); + RECT rect; + GetWindowRect(ih->handle, &rect); /* ignore LPARAM because they are the clientpos and not X/Y */ + if (cb) cb(ih, rect.left, rect.top); + break; + } + case WM_SIZE: + { + if (ih->data->ignore_resize) + break; + + switch(wp) + { + case SIZE_MINIMIZED: + { + if (ih->data->show_state != IUP_MINIMIZE) + { + IFni show_cb = (IFni)IupGetCallback(ih, "SHOW_CB"); + if (show_cb && show_cb(ih, IUP_MINIMIZE) == IUP_CLOSE) + IupExitLoop(); + ih->data->show_state = IUP_MINIMIZE; + } + break; + } + case SIZE_MAXIMIZED: + { + if (ih->data->show_state != IUP_MAXIMIZE) + { + IFni show_cb = (IFni)IupGetCallback(ih, "SHOW_CB"); + if (show_cb && show_cb(ih, IUP_MAXIMIZE) == IUP_CLOSE) + IupExitLoop(); + ih->data->show_state = IUP_MAXIMIZE; + } + + winDialogResize(ih, LOWORD(lp), HIWORD(lp)); + break; + } + case SIZE_RESTORED: + { + if (ih->data->show_state == IUP_MAXIMIZE || ih->data->show_state == IUP_MINIMIZE) + { + IFni show_cb = (IFni)IupGetCallback(ih, "SHOW_CB"); + if (show_cb && show_cb(ih, IUP_RESTORE) == IUP_CLOSE) + IupExitLoop(); + ih->data->show_state = IUP_RESTORE; + } + + winDialogResize(ih, LOWORD(lp), HIWORD(lp)); + break; + } + } + + break; + } + case WM_USER+IWIN_TRAY_NOTIFICATION: + { + int dclick = 0; + int button = 0; + int pressed = 0; + + switch (lp) + { + case WM_LBUTTONDOWN: + pressed = 1; + button = 1; + break; + case WM_MBUTTONDOWN: + pressed = 1; + button = 2; + break; + case WM_RBUTTONDOWN: + pressed = 1; + button = 3; + break; + case WM_LBUTTONDBLCLK: + dclick = 1; + button = 1; + break; + case WM_MBUTTONDBLCLK: + dclick = 1; + button = 2; + break; + case WM_RBUTTONDBLCLK: + dclick = 1; + button = 3; + break; + case WM_LBUTTONUP: + button = 1; + break; + case WM_MBUTTONUP: + button = 2; + break; + case WM_RBUTTONUP: + button = 3; + break; + } + + if (button != 0) + { + IFniii cb = (IFniii)IupGetCallback(ih, "TRAYCLICK_CB"); + if (cb && cb(ih, button, pressed, dclick) == IUP_CLOSE) + IupExitLoop(); + } + + break; + } + case WM_CLOSE: + { + Icallback cb = IupGetCallback(ih, "CLOSE_CB"); + if (cb) + { + int ret = cb(ih); + if (ret == IUP_IGNORE) + { + *result = 0; + return 1; + } + if (ret == IUP_CLOSE) + IupExitLoop(); + } + + /* child mdi is automatically destroyed */ + if (iupAttribGetBoolean(ih, "MDICHILD")) + IupDestroy(ih); + else + { + if (!winDialogMDICloseChildren(ih)) + { + *result = 0; + return 1; + } + + IupHide(ih); /* IUP default processing */ + } + + *result = 0; + return 1; + } + case WM_SETCURSOR: + { + if (ih->handle == (HWND)wp && LOWORD(lp)==HTCLIENT) + { + HCURSOR hCur = (HCURSOR)iupAttribGet(ih, "_IUPWIN_HCURSOR"); + if (hCur) + { + SetCursor(hCur); + *result = 1; + return 1; + } + else if (iupAttribGet(ih, "CURSOR")) + { + SetCursor(NULL); + *result = 1; + return 1; + } + } + break; + } + case WM_ERASEBKGND: + { + HBITMAP hBitmap = (HBITMAP)iupAttribGet(ih, "_IUPWIN_BACKGROUND_BITMAP"); + if (hBitmap) + { + RECT rect; + HDC hdc = (HDC)wp; + + HBRUSH hBrush = CreatePatternBrush(hBitmap); + GetClientRect(ih->handle, &rect); + FillRect(hdc, &rect, hBrush); + DeleteObject(hBrush); + + /* return non zero value */ + *result = 1; + return 1; + } + else + { + unsigned char r, g, b; + char* color = iupAttribGet(ih, "_IUPWIN_BACKGROUND_COLOR"); + if (iupStrToRGB(color, &r, &g, &b)) + { + RECT rect; + HDC hdc = (HDC)wp; + + SetDCBrushColor(hdc, RGB(r,g,b)); + GetClientRect(ih->handle, &rect); + FillRect(hdc, &rect, (HBRUSH)GetStockObject(DC_BRUSH)); + + /* return non zero value */ + *result = 1; + return 1; + } + } + break; + } + case WM_DESTROY: + { + /* Since WM_CLOSE changed the Windows default processing */ + /* WM_DESTROY is NOT received by IupDialogs */ + /* Except when they are children of other IupDialogs and the parent is destroyed. */ + /* So we have to destroy the child dialog. */ + /* The application is responsable for destroying the children before this happen. */ + IupDestroy(ih); + break; + } + } + + if (msg == (UINT)WM_HELPMSG) + { + Ihandle* child = NULL; + DWORD* struct_ptr = (DWORD*)lp; + if (*struct_ptr == sizeof(CHOOSECOLOR)) + { + CHOOSECOLOR* choosecolor = (CHOOSECOLOR*)lp; + child = (Ihandle*)choosecolor->lCustData; + } + if (*struct_ptr == sizeof(CHOOSEFONT)) + { + CHOOSEFONT* choosefont = (CHOOSEFONT*)lp; + child = (Ihandle*)choosefont->lCustData; + } + + if (child) + { + Icallback cb = IupGetCallback(child, "HELP_CB"); + if (cb && cb(child) == IUP_CLOSE) + EndDialog((HWND)iupAttribGet(child, "HWND"), IDCANCEL); + } + } + + return 0; +} + +static LRESULT CALLBACK winDialogProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + LRESULT result; + Ihandle *ih = iupwinHandleGet(hwnd); + if (!ih) + { + /* the first time WM_GETMINMAXINFO is called, Ihandle is not associated yet */ + if (msg == WM_GETMINMAXINFO && winMinMaxHandle) + { + if (winDialogCheckMinMaxInfo(winMinMaxHandle, (MINMAXINFO*)lp)) + return 0; + } + + return DefWindowProc(hwnd, msg, wp, lp); + } + + if (winDialogBaseProc(ih, msg, wp, lp, &result)) + return result; + + return DefWindowProc(hwnd, msg, wp, lp); +} + +static LRESULT CALLBACK winDialogMDIChildProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + LRESULT result; + Ihandle *ih = iupwinHandleGet(hwnd); + if (!ih) + { + /* the first time WM_GETMINMAXINFO is called, Ihandle is not associated yet */ + if (msg == WM_GETMINMAXINFO && winMinMaxHandle) + { + if (winDialogCheckMinMaxInfo(winMinMaxHandle, (MINMAXINFO*)lp)) + return 0; + } + + return DefMDIChildProc(hwnd, msg, wp, lp); + } + + switch (msg) + { + case WM_MDIACTIVATE: + { + HWND hNewActive = (HWND)lp; + if (hNewActive == ih->handle) + { + Icallback cb = (Icallback)IupGetCallback(ih, "MDIACTIVATE_CB"); + if (cb) cb(ih); + } + break; + } + } + + if (winDialogBaseProc(ih, msg, wp, lp, &result)) + return result; + + return DefMDIChildProc(hwnd, msg, wp, lp); +} + +static Ihandle* winDialogGetMdiChildId(Ihandle* ih, int mdi_child_id) +{ + int id, max_child_id, real_id = -1; + char name[50]; + Ihandle* child; + + max_child_id = iupAttribGetInt(ih, "_IUPWIN_MAX_MDI_ID"); + + for (id = 0; id < max_child_id; id++) + { + sprintf(name, "_IUPWIN_MDI_ID_[%d]", id); + child = (Ihandle*)iupAttribGet(ih, name); + if (iupObjectCheck(child)) + { + real_id++; + if (real_id == mdi_child_id) + return child; + } + } + + return NULL; +} + +static LRESULT CALLBACK winDialogMDIFrameProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + LRESULT result; + HWND hWndClient = NULL; + Ihandle *ih = iupwinHandleGet(hwnd); + if (!ih) + { + /* the first time WM_GETMINMAXINFO is called, Ihandle is not associated yet */ + if (msg == WM_GETMINMAXINFO && winMinMaxHandle) + { + if (winDialogCheckMinMaxInfo(winMinMaxHandle, (MINMAXINFO*)lp)) + return 0; + } + + return DefFrameProc(hwnd, hWndClient, msg, wp, lp); + } + + { + Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE"); + if (client) hWndClient = client->handle; + } + + if (winDialogBaseProc(ih, msg, wp, lp, &result)) + return result; + + switch (msg) + { + case WM_MENUCOMMAND: + { + int menuId = GetMenuItemID((HMENU)lp, (int)wp); + if (menuId >= IUP_MDICHILD_START && hWndClient) + { + Ihandle* child = winDialogGetMdiChildId(ih, menuId-IUP_MDICHILD_START); + if (child) + SendMessage(hWndClient, WM_MDIACTIVATE, (WPARAM)child->handle, 0); + break; + } + } + } + + + return DefFrameProc(hwnd, hWndClient, msg, wp, lp); +} + +static void winDialogRegisterClass(int mdi) +{ + char* name; + WNDCLASS wndclass; + WNDPROC winproc; + ZeroMemory(&wndclass, sizeof(WNDCLASS)); + + if (mdi == 2) + { + name = "IupDialogMDIChild"; + winproc = (WNDPROC)winDialogMDIChildProc; + } + else if (mdi == 1) + { + name = "IupDialogMDIFrame"; + winproc = (WNDPROC)winDialogMDIFrameProc; + } + else + { + if (mdi == -1) + name = "IupDialogControl"; + else + name = "IupDialog"; + winproc = (WNDPROC)winDialogProc; + } + + wndclass.hInstance = iupwin_hinstance; + wndclass.lpszClassName = name; + wndclass.lpfnWndProc = (WNDPROC)winproc; + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + + /* To use a standard system color, must increase the background-color value by one */ + if (mdi == 1) + wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1); + else + wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + + if (mdi == 0) + wndclass.style |= CS_SAVEBITS; + + if (mdi == -1) + wndclass.style |= CS_HREDRAW | CS_VREDRAW; + + RegisterClass(&wndclass); +} + + +/**************************************************************** + dialog class functions +****************************************************************/ + + +static int winDialogMapMethod(Ihandle* ih) +{ + InativeHandle* native_parent; + DWORD dwStyle = WS_CLIPSIBLINGS, + dwExStyle = 0; + int has_titlebar = 0, + has_border = 0; + char* classname = "IupDialog"; + + char* title = iupAttribGet(ih, "TITLE"); + if (title) + has_titlebar = 1; + + if (iupAttribGetBoolean(ih, "DIALOGFRAME")) + { + iupAttribSetStr(ih, "RESIZE", "NO"); + iupAttribSetStr(ih, "MINBOX", "NO"); + } + + if (iupAttribGetBoolean(ih, "RESIZE")) + dwStyle |= WS_THICKFRAME; + else + iupAttribSetStr(ih, "MAXBOX", "NO"); /* Must also remove this to RESIZE=NO work */ + + if (iupAttribGetBoolean(ih, "MAXBOX")) + { + dwStyle |= WS_MAXIMIZEBOX; + has_titlebar = 1; + } + + if (iupAttribGetBoolean(ih, "MINBOX")) + { + dwStyle |= WS_MINIMIZEBOX; + has_titlebar = 1; + } + + if (iupAttribGetBoolean(ih, "MENUBOX")) + { + dwStyle |= WS_SYSMENU; + has_titlebar = 1; + } + + if (iupAttribGetBoolean(ih, "BORDER") || has_titlebar) + has_border = 1; + + if (iupAttribGetBoolean(ih, "MDICHILD")) + { + static int mdi_child_id = 0; + Ihandle *client; + char name[50]; + + /* must have a parent dialog (the mdi frame) */ + Ihandle* parent = IupGetAttributeHandle(ih, "PARENTDIALOG"); + if (!parent || !parent->handle) + return IUP_ERROR; + + /* set when the mdi client is mapped */ + client = (Ihandle*)iupAttribGet(parent, "MDICLIENT_HANDLE"); + if (!client) + return IUP_ERROR; + + /* store the mdi client handle in each mdi child also */ + iupAttribSetStr(ih, "MDICLIENT_HANDLE", (char*)client); + + sprintf(name, "_IUPWIN_MDI_ID_[%d]", mdi_child_id); + iupAttribSetStr(parent, name, (char*)ih); + mdi_child_id++; + iupAttribSetInt(parent, "_IUPWIN_MAX_MDI_ID", mdi_child_id); + + classname = "IupDialogMDIChild"; + + /* The actual parent is the mdi client */ + native_parent = client->handle; + + dwStyle |= WS_CHILD; + if (has_titlebar) + dwStyle |= WS_CAPTION; + else if (has_border) + dwStyle |= WS_BORDER; + + if (!IupGetName(ih)) + iupAttribSetHandleName(ih); + } + else + { + native_parent = iupDialogGetNativeParent(ih); + + if (native_parent) + { + dwStyle |= WS_POPUP; + + if (has_titlebar) + dwStyle |= WS_CAPTION; + else if (has_border) + dwStyle |= WS_BORDER; + } + else + { + if (has_titlebar) + { + dwStyle |= WS_OVERLAPPED; + } + else + { + if (has_border) + dwStyle |= WS_POPUP | WS_BORDER; + else + dwStyle |= WS_POPUP; + + dwExStyle |= WS_EX_NOACTIVATE; /* this will hide it from the taskbar */ + } + } + + if (iupAttribGet(ih, "MDIFRAME")) + classname = "IupDialogMDIFrame"; + } + + if (iupAttribGetBoolean(ih, "TOOLBOX") && native_parent) + dwExStyle |= WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE; + + if (iupAttribGetBoolean(ih, "DIALOGFRAME") && native_parent) + dwExStyle |= WS_EX_DLGMODALFRAME; /* this will hide the MENUBOX but not the close button */ + + if (iupAttribGetBoolean(ih, "COMPOSITED")) + dwExStyle |= WS_EX_COMPOSITED; + else + dwStyle |= WS_CLIPCHILDREN; + + if (iupAttribGetBoolean(ih, "HELPBUTTON")) + dwExStyle |= WS_EX_CONTEXTHELP; + + if (iupAttribGetBoolean(ih, "CONTROL") && native_parent) + { + /* TODO: this were used by LuaCom to create embeded controls, + don't know if it is still working */ + dwStyle = WS_CHILD | WS_TABSTOP | WS_CLIPCHILDREN; + classname = "IupDialogControl"; + } + + /* CreateWindowEx will send WM_GETMINMAXINFO before Ihandle is associated with HWND */ + if (iupAttribGet(ih, "MINSIZE") || iupAttribGet(ih, "MAXSIZE")) + winMinMaxHandle = ih; + + /* size will be updated in IupRefresh -> winDialogLayoutUpdate */ + /* position will be updated in iupDialogShowXY */ + + if (iupAttribGetBoolean(ih, "MDICHILD")) + ih->handle = CreateMDIWindow(classname, + title, /* title */ + dwStyle, /* style */ + 0, /* x-position */ + 0, /* y-position */ + 100, /* horizontal size - set this to avoid size calculation problems */ + 100, /* vertical size */ + native_parent, /* owner window */ + iupwin_hinstance, /* instance of app. */ + 0); /* no creation parameters */ + else + ih->handle = CreateWindowEx(dwExStyle, /* extended styles */ + classname, /* class */ + title, /* title */ + dwStyle, /* style */ + 0, /* x-position */ + 0, /* y-position */ + 100, /* horizontal size - set this to avoid size calculation problems */ + 100, /* vertical size */ + native_parent, /* owner window */ + (HMENU)0, /* Menu or child-window identifier */ + iupwin_hinstance, /* instance of app. */ + NULL); /* no creation parameters */ + if (!ih->handle) + return IUP_ERROR; + + /* associate HWND with Ihandle*, all Win32 controls must call this. */ + iupwinHandleSet(ih); + + if (iupStrEqual(classname, "IupDialogMDIChild")) /* hides the mdi child */ + ShowWindow(ih->handle, SW_HIDE); + + /* configure for DRAG&DROP */ + if (IupGetCallback(ih, "DROPFILES_CB")) + iupAttribSetStr(ih, "DRAGDROP", "YES"); + + /* Reset attributes handled during creation that */ + /* also can be changed later, and can be consulted from the native system. */ + iupAttribSetStr(ih, "TITLE", NULL); + iupAttribSetStr(ih, "BORDER", NULL); + + /* Ignore VISIBLE before mapping */ + iupAttribSetStr(ih, "VISIBLE", NULL); + + /* Set the default CmdShow for ShowWindow */ + ih->data->cmd_show = SW_SHOWNORMAL; + + return IUP_NOERROR; +} + +static void winDialogUnMapMethod(Ihandle* ih) +{ + if (ih->data->menu) + { + ih->data->menu->handle = NULL; /* the dialog will destroy the native menu */ + IupDestroy(ih->data->menu); + } + + if (iupAttribGet(ih, "_IUPDLG_HASTRAY")) + winDialogSetTrayAttrib(ih, NULL); + + /* remove the association before destroying */ + iupwinHandleRemove(ih); + + /* Destroys the window, so we can destroy the class */ + if (iupAttribGetBoolean(ih, "MDICHILD")) + { + /* for MDICHILDs must send WM_MDIDESTROY, instead of calling DestroyWindow */ + Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE"); + SendMessage(client->handle, WM_MDIDESTROY, (WPARAM)ih->handle, 0); + } + else + DestroyWindow(ih->handle); /* this will destroy the Windows children also. */ + /* but IupDestroy already destroyed the IUP children */ + /* so it is safe to call DestroyWindow */ +} + +static void winDialogLayoutUpdateMethod(Ihandle *ih) +{ + if (ih->data->ignore_resize) + return; + + ih->data->ignore_resize = 1; + + /* for dialogs the position is not updated here */ + SetWindowPos(ih->handle, 0, 0, 0, ih->currentwidth, ih->currentheight, + SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSENDCHANGING); + + ih->data->ignore_resize = 0; +} + +static void winDialogReleaseMethod(Iclass* ic) +{ + (void)ic; + if (iupwinClassExist("IupDialog")) + { + UnregisterClass("IupDialog", iupwin_hinstance); + UnregisterClass("IupDialogControl", iupwin_hinstance); + UnregisterClass("IupDialogMDIChild", iupwin_hinstance); + UnregisterClass("IupDialogMDIFrame", iupwin_hinstance); + } +} + + + +/**************************************************************************** + Attributes +****************************************************************************/ + + +static int winDialogSetBgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + if (iupStrToRGB(value, &r, &g, &b)) + { + iupAttribStoreStr(ih, "_IUPWIN_BACKGROUND_COLOR", value); + iupAttribSetStr(ih, "_IUPWIN_BACKGROUND_BITMAP", NULL); + RedrawWindow(ih->handle, NULL, NULL, RDW_ERASE|RDW_ERASENOW); /* force a WM_ERASEBKGND now */ + return 1; + } + return 0; +} + +static int winDialogSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + if (winDialogSetBgColorAttrib(ih, value)) + return 1; + else + { + HBITMAP hBitmap = iupImageGetImage(value, ih, 0); + if (hBitmap) + { + iupAttribSetStr(ih, "_IUPWIN_BACKGROUND_COLOR", NULL); + iupAttribSetStr(ih, "_IUPWIN_BACKGROUND_BITMAP", (char*)hBitmap); + RedrawWindow(ih->handle, NULL, NULL, RDW_ERASE|RDW_ERASENOW); /* force a WM_ERASEBKGND now */ + return 1; + } + } + + return 0; +} + +static HWND iupwin_mdifirst = NULL; +static HWND iupwin_mdinext = NULL; + +static char* winDialogGetMdiActiveAttrib(Ihandle *ih) +{ + Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE"); + if (client) + { + HWND hchild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0); + Ihandle* child = iupwinHandleGet(hchild); + if (child) + { + iupwin_mdinext = NULL; + iupwin_mdifirst = hchild; + return IupGetName(child); + } + } + + iupwin_mdifirst = NULL; + iupwin_mdinext = NULL; + return NULL; +} + +static char* winDialogGetMdiNextAttrib(Ihandle *ih) +{ + Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE"); + if (client) + { + Ihandle* child; + HWND hchild = iupwin_mdinext? iupwin_mdinext: iupwin_mdifirst; + + /* Skip the icon title windows */ + while (hchild && GetWindow (hchild, GW_OWNER)) + hchild = GetWindow(hchild, GW_HWNDNEXT); + + if (!hchild || hchild == iupwin_mdifirst) + { + iupwin_mdinext = NULL; + return NULL; + } + + child = iupwinHandleGet(hchild); + if (child) + { + iupwin_mdinext = hchild; + return IupGetName(child); + } + } + + iupwin_mdinext = NULL; + return NULL; +} + +/* define this here, so we do not need to define _WIN32_WINNT=0x0500 */ +#ifndef WS_EX_LAYERED +#define WS_EX_LAYERED 0x00080000 +#endif + +#ifndef LWA_ALPHA +#define LWA_ALPHA 0x00000002 +#endif + +typedef BOOL (WINAPI*winSetLayeredWindowAttributes)( + HWND hwnd, + COLORREF crKey, + BYTE bAlpha, + DWORD dwFlags); + +static int winDialogSetOpacityAttrib(Ihandle *ih, const char *value) +{ + DWORD dwExStyle = GetWindowLong(ih->handle, GWL_EXSTYLE); + if (!value) + { + if (dwExStyle & WS_EX_LAYERED) + { + dwExStyle &= ~WS_EX_LAYERED; /* remove the style */ + SetWindowLong(ih->handle, GWL_EXSTYLE, dwExStyle); + RedrawWindow(ih->handle, NULL, NULL, RDW_ERASE|RDW_INVALIDATE|RDW_FRAME|RDW_ALLCHILDREN); /* invalidate everything and all children */ + } + return 0; + } + + if (!(dwExStyle & WS_EX_LAYERED)) + { + dwExStyle |= WS_EX_LAYERED; /* add the style */ + SetWindowLong(ih->handle, GWL_EXSTYLE, dwExStyle); + } + + { + static winSetLayeredWindowAttributes mySetLayeredWindowAttributes = NULL; + + int opacity; + if (!iupStrToInt(value, &opacity)) + return 0; + + if (!mySetLayeredWindowAttributes) + { + HMODULE hinstDll = LoadLibrary("user32.dll"); + if (hinstDll) + mySetLayeredWindowAttributes = (winSetLayeredWindowAttributes)GetProcAddress(hinstDll, "SetLayeredWindowAttributes"); + } + + if (mySetLayeredWindowAttributes) + mySetLayeredWindowAttributes(ih->handle, 0, (BYTE)opacity, LWA_ALPHA); + } + + RedrawWindow(ih->handle, NULL, NULL, RDW_ERASE|RDW_INVALIDATE|RDW_FRAME|RDW_ALLCHILDREN); /* invalidate everything and all children */ + return 1; +} + +static int winDialogSetMdiArrangeAttrib(Ihandle *ih, const char *value) +{ + Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE"); + if (client) + { + UINT msg = 0; + WPARAM wp = 0; + + if (iupStrEqualNoCase(value, "TILEHORIZONTAL")) + { + msg = WM_MDITILE; + wp = MDITILE_HORIZONTAL; + } + else if (iupStrEqualNoCase(value, "TILEVERTICAL")) + { + msg = WM_MDITILE; + wp = MDITILE_VERTICAL; + } + else if (iupStrEqualNoCase(value, "CASCADE")) + msg = WM_MDICASCADE; + else if (iupStrEqualNoCase(value, "ICON")) + msg = WM_MDIICONARRANGE; + + if (msg) + SendMessage(client->handle, msg, wp, 0); + } + return 0; +} + +static int winDialogSetMdiActivateAttrib(Ihandle *ih, const char *value) +{ + Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE"); + if (client) + { + Ihandle* child = IupGetHandle(value); + if (child) + SendMessage(client->handle, WM_MDIACTIVATE, (WPARAM)child->handle, 0); + else + { + HWND hchild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0); + if (iupStrEqualNoCase(value, "NEXT")) + SendMessage(client->handle, WM_MDINEXT, (WPARAM)hchild, TRUE); + else if (iupStrEqualNoCase(value, "PREVIOUS")) + SendMessage(client->handle, WM_MDINEXT, (WPARAM)hchild, FALSE); + } + } + return 0; +} + +static int winDialogSetMdiCloseAllAttrib(Ihandle *ih, const char *value) +{ + (void)value; + winDialogMDICloseChildren(ih); + return 0; +} + +static void winDialogTrayMessage(HWND hWnd, DWORD dwMessage, HICON hIcon, PSTR pszTip) +{ + NOTIFYICONDATA tnd; + memset(&tnd, 0, sizeof(NOTIFYICONDATA)); + + tnd.cbSize = sizeof(NOTIFYICONDATA); + tnd.hWnd = hWnd; + tnd.uID = 1000; + + if (dwMessage == NIM_ADD) + { + tnd.uFlags = NIF_MESSAGE; + tnd.uCallbackMessage = WM_USER+IWIN_TRAY_NOTIFICATION; + } + else if (dwMessage == NIM_MODIFY) + { + if (hIcon) + { + tnd.uFlags |= NIF_ICON; + tnd.hIcon = hIcon; + } + + if (pszTip) + { + tnd.uFlags |= NIF_TIP; + lstrcpyn(tnd.szTip, pszTip, sizeof(tnd.szTip)); + } + } + + Shell_NotifyIcon(dwMessage, &tnd); +} + +static int winDialogCheckTray(Ihandle *ih) +{ + if (iupAttribGet(ih, "_IUPDLG_HASTRAY")) + return 1; + + if (iupAttribGetBoolean(ih, "TRAY")) + { + winDialogTrayMessage(ih->handle, NIM_ADD, NULL, NULL); + iupAttribSetStr(ih, "_IUPDLG_HASTRAY", "YES"); + return 1; + } + + return 0; +} + +static int winDialogSetTrayAttrib(Ihandle *ih, const char *value) +{ + int tray = iupStrBoolean(value); + if (iupAttribGet(ih, "_IUPDLG_HASTRAY")) + { + if (!tray) + { + winDialogTrayMessage(ih->handle, NIM_DELETE, NULL, NULL); + iupAttribSetStr(ih, "_IUPDLG_HASTRAY", NULL); + } + } + else + { + if (tray) + { + winDialogTrayMessage(ih->handle, NIM_ADD, NULL, NULL); + iupAttribSetStr(ih, "_IUPDLG_HASTRAY", "YES"); + } + } + return 1; +} + +static int winDialogSetTrayTipAttrib(Ihandle *ih, const char *value) +{ + if (winDialogCheckTray(ih)) + winDialogTrayMessage(ih->handle, NIM_MODIFY, NULL, (PSTR)value); + return 1; +} + +static int winDialogSetTrayImageAttrib(Ihandle *ih, const char *value) +{ + if (winDialogCheckTray(ih)) + { + HICON hIcon = (HICON)iupImageGetIcon(value); + if (hIcon) + winDialogTrayMessage(ih->handle, NIM_MODIFY, hIcon, NULL); + } + return 1; +} + +static int winDialogSetBringFrontAttrib(Ihandle *ih, const char *value) +{ + if (iupStrBoolean(value)) + SetForegroundWindow(ih->handle); + return 0; +} + +static int winDialogSetTopMostAttrib(Ihandle *ih, const char *value) +{ + if (iupStrBoolean(value)) + SetWindowPos(ih->handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + else + SetWindowPos(ih->handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + return 1; +} + +static int winDialogSetIconAttrib(Ihandle* ih, const char *value) +{ + if (!value) + SendMessage(ih->handle, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)NULL); + else + { + HICON icon = iupImageGetIcon(value); + if (icon) + SendMessage(ih->handle, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM)icon); + } + + if (IsIconic(ih->handle)) + RedrawWindow(ih->handle, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW); /* redraw the icon */ + else + RedrawWindow(ih->handle, NULL, NULL, RDW_FRAME|RDW_UPDATENOW); /* only the frame needs to be redrawn */ + + return 1; +} + +static int winDialogSetFullScreenAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + { + if (!iupAttribGet(ih, "_IUPWIN_FS_STYLE")) + { + int width, height; + LONG off_style, new_style; + + BOOL visible = ShowWindow (ih->handle, SW_HIDE); + + /* remove the decorations */ + off_style = WS_BORDER | WS_THICKFRAME | WS_CAPTION | + WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU; + new_style = GetWindowLong(ih->handle, GWL_STYLE); + iupAttribSetStr(ih, "_IUPWIN_FS_STYLE", (char*)new_style); + new_style &= (~off_style); + SetWindowLong(ih->handle, GWL_STYLE, new_style); + + /* save the previous decoration attributes */ + iupAttribStoreStr(ih, "_IUPWIN_FS_MAXBOX", iupAttribGet(ih, "MAXBOX")); + iupAttribStoreStr(ih, "_IUPWIN_FS_MINBOX", iupAttribGet(ih, "MINBOX")); + iupAttribStoreStr(ih, "_IUPWIN_FS_MENUBOX",iupAttribGet(ih, "MENUBOX")); + iupAttribStoreStr(ih, "_IUPWIN_FS_RESIZE", iupAttribGet(ih, "RESIZE")); + iupAttribStoreStr(ih, "_IUPWIN_FS_BORDER", iupAttribGet(ih, "BORDER")); + iupAttribStoreStr(ih, "_IUPWIN_FS_TITLE", IupGetAttribute(ih, "TITLE")); /* must use IupGetAttribute to check from the native implementation */ + + /* save the previous position and size */ + iupAttribStoreStr(ih, "_IUPWIN_FS_X", IupGetAttribute(ih, "X")); /* must use IupGetAttribute to check from the native implementation */ + iupAttribStoreStr(ih, "_IUPWIN_FS_Y", IupGetAttribute(ih, "Y")); + iupAttribStoreStr(ih, "_IUPWIN_FS_SIZE", IupGetAttribute(ih, "RASTERSIZE")); + + /* remove the decorations attributes */ + iupAttribSetStr(ih, "MAXBOX", "NO"); + iupAttribSetStr(ih, "MINBOX", "NO"); + iupAttribSetStr(ih, "MENUBOX", "NO"); + IupSetAttribute(ih, "TITLE", NULL); + iupAttribSetStr(ih, "RESIZE", "NO"); + iupAttribSetStr(ih, "BORDER", "NO"); + + /* full screen size */ + iupdrvGetFullSize(&width, &height); + + SetWindowPos(ih->handle, HWND_TOP, 0, 0, width, height, SWP_FRAMECHANGED); + + /* layout will be updated in WM_SIZE */ + if (visible) + ShowWindow(ih->handle, SW_SHOW); + } + } + else + { + LONG style = (LONG)iupAttribGet(ih, "_IUPWIN_FS_STYLE"); + if (style) + { + BOOL visible = ShowWindow(ih->handle, SW_HIDE); + + /* restore the decorations attributes */ + iupAttribStoreStr(ih, "MAXBOX", iupAttribGet(ih, "_IUPWIN_FS_MAXBOX")); + iupAttribStoreStr(ih, "MINBOX", iupAttribGet(ih, "_IUPWIN_FS_MINBOX")); + iupAttribStoreStr(ih, "MENUBOX",iupAttribGet(ih, "_IUPWIN_FS_MENUBOX")); + IupSetAttribute(ih, "TITLE", iupAttribGet(ih, "_IUPWIN_FS_TITLE")); /* TITLE is not stored in the HashTable */ + iupAttribStoreStr(ih, "RESIZE", iupAttribGet(ih, "_IUPWIN_FS_RESIZE")); + iupAttribStoreStr(ih, "BORDER", iupAttribGet(ih, "_IUPWIN_FS_BORDER")); + + /* restore the decorations */ + SetWindowLong(ih->handle, GWL_STYLE, style); + + /* restore position and size */ + SetWindowPos(ih->handle, HWND_TOP, + iupAttribGetInt(ih, "_IUPWIN_FS_X"), + iupAttribGetInt(ih, "_IUPWIN_FS_Y"), + IupGetInt(ih, "_IUPWIN_FS_SIZE"), + IupGetInt2(ih, "_IUPWIN_FS_SIZE"), 0); + + /* layout will be updated in WM_SIZE */ + if (visible) + ShowWindow(ih->handle, SW_SHOW); + + /* remove auxiliar attributes */ + iupAttribSetStr(ih, "_IUPWIN_FS_MAXBOX", NULL); + iupAttribSetStr(ih, "_IUPWIN_FS_MINBOX", NULL); + iupAttribSetStr(ih, "_IUPWIN_FS_MENUBOX",NULL); + iupAttribSetStr(ih, "_IUPWIN_FS_TITLE", NULL); + iupAttribSetStr(ih, "_IUPWIN_FS_RESIZE", NULL); + iupAttribSetStr(ih, "_IUPWIN_FS_BORDER", NULL); + + iupAttribSetStr(ih, "_IUPWIN_FS_X", NULL); + iupAttribSetStr(ih, "_IUPWIN_FS_Y", NULL); + iupAttribSetStr(ih, "_IUPWIN_FS_SIZE", NULL); + + iupAttribSetStr(ih, "_IUPWIN_FS_STYLE", NULL); + } + } + return 1; +} + + +void iupdrvDialogInitClass(Iclass* ic) +{ + if (!iupwinClassExist("IupDialog")) + { + winDialogRegisterClass(0); + winDialogRegisterClass(1); + winDialogRegisterClass(2); + winDialogRegisterClass(-1); + + WM_HELPMSG = RegisterWindowMessage(HELPMSGSTRING); + } + + /* Driver Dependent Class functions */ + ic->Map = winDialogMapMethod; + ic->UnMap = winDialogUnMapMethod; + ic->LayoutUpdate = winDialogLayoutUpdateMethod; + ic->Release = winDialogReleaseMethod; + + /* Callback Windows Only*/ + iupClassRegisterCallback(ic, "MDIACTIVATE_CB", ""); + + /* Callback Windows and GTK Only */ + iupClassRegisterCallback(ic, "TRAYCLICK_CB", "iii"); + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winDialogSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, iupdrvBaseSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* Base Container */ + iupClassRegisterAttribute(ic, "CLIENTSIZE", iupdrvBaseGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + + /* IupDialog only */ + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, winDialogSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ICON", NULL, winDialogSetIconAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FULLSCREEN", NULL, winDialogSetFullScreenAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SAVEUNDER", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MINSIZE", NULL, NULL, IUPAF_SAMEASSYSTEM, "1x1", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MAXSIZE", NULL, NULL, IUPAF_SAMEASSYSTEM, "65535x65535", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* IupDialog Windows Only */ + iupClassRegisterAttribute(ic, "HWND", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MDIARRANGE", NULL, winDialogSetMdiArrangeAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MDIACTIVATE", NULL, winDialogSetMdiActivateAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MDICLOSEALL", NULL, winDialogSetMdiCloseAllAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MDIACTIVE", winDialogGetMdiActiveAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MDINEXT", winDialogGetMdiNextAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "OPACITY", NULL, winDialogSetOpacityAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "LAYERALPHA", NULL, winDialogSetOpacityAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "BRINGFRONT", NULL, winDialogSetBringFrontAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "COMPOSITED", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED); + + iupClassRegisterAttribute(ic, "CONTROL", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "HELPBUTTON", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TOOLBOX", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MDIFRAME", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MDICLIENT", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MDIMENU", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MDICHILD", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + + /* IupDialog Windows and GTK Only */ + iupClassRegisterAttribute(ic, "TOPMOST", NULL, winDialogSetTopMostAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TRAY", NULL, winDialogSetTrayAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TRAYIMAGE", NULL, winDialogSetTrayImageAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TRAYTIP", NULL, winDialogSetTrayTipAttrib, NULL, NULL, IUPAF_NO_INHERIT); +} diff --git a/iup/src/win/iupwin_draw.c b/iup/src/win/iupwin_draw.c new file mode 100755 index 0000000..4a810e6 --- /dev/null +++ b/iup/src/win/iupwin_draw.c @@ -0,0 +1,328 @@ +/** \file + * \brief Draw Functions + * + * See Copyright Notice in "iup.h" + */ + +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#include <windows.h> +#include <uxtheme.h> +#include <tmschema.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> + +#include "iup.h" + +#include "iup_attrib.h" +#include "iup_class.h" +#include "iup_str.h" + +#include "iupwin_drv.h" +#include "iupwin_info.h" +#include "iupwin_draw.h" + + +#ifndef TABP_AEROWIZARDBODY +#define TABP_AEROWIZARDBODY 11 /* manually added definition */ +#endif + +#ifndef TMT_FILLCOLORHINT +#define TMT_FILLCOLORHINT 3821 +#endif +#ifndef TMT_TEXTCOLOR +#define TMT_TEXTCOLOR 3823 +#endif + + +typedef HTHEME (STDAPICALLTYPE *_winThemeOpenData)(HWND hwnd, LPCWSTR pszClassList); +typedef HRESULT (STDAPICALLTYPE *_winThemeCloseData)(HTHEME hTheme); +typedef HRESULT (STDAPICALLTYPE *_winThemeDrawBackground)(HTHEME hTheme, HDC hDC, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect); +typedef HRESULT (STDAPICALLTYPE *_winThemeGetColor)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, COLORREF *pColor); + +static _winThemeOpenData winThemeOpenData = NULL; +static _winThemeCloseData winThemeCloseData = NULL; +static _winThemeDrawBackground winThemeDrawBackground = NULL; +static _winThemeGetColor winThemeGetColor = NULL; + +typedef BOOL (CALLBACK* _winAlphaBlendFunc)( HDC hdcDest, + int xoriginDest, int yoriginDest, + int wDest, int hDest, HDC hdcSrc, + int xoriginSrc, int yoriginSrc, + int wSrc, int hSrc, + BLENDFUNCTION ftn); +static _winAlphaBlendFunc winAlphaBlend = NULL; + +static int winDrawThemeEnabled(void) +{ + return winThemeOpenData? 1: 0; +} + +void iupwinDrawText(HDC hDC, const char* text, int x, int y, int width, int height, HFONT hFont, COLORREF fgcolor, int style) +{ + COLORREF oldcolor; + RECT rect; + HFONT hOldFont = SelectObject(hDC, hFont); + + rect.left = x; + rect.top = y; + rect.right = x+width; + rect.bottom = y+height; + + SetTextAlign(hDC, TA_TOP|TA_LEFT); + SetBkMode(hDC, TRANSPARENT); + oldcolor = SetTextColor(hDC, fgcolor); + + DrawText(hDC, text, -1, &rect, style|DT_NOCLIP); + + SelectObject(hDC, hOldFont); + SetTextColor(hDC, oldcolor); + SetBkMode(hDC, OPAQUE); +} + +void iupwinDrawBitmap(HDC hDC, HBITMAP hBitmap, HBITMAP hMask, int x, int y, int width, int height, int bpp) +{ + HDC hMemDC = CreateCompatibleDC(hDC); + SelectObject(hMemDC, hBitmap); + + if (bpp == 32 && winAlphaBlend) + { + BLENDFUNCTION blendfunc; + blendfunc.BlendOp = AC_SRC_OVER; + blendfunc.BlendFlags = 0; + blendfunc.SourceConstantAlpha = 0xFF; + blendfunc.AlphaFormat = AC_SRC_ALPHA; + + winAlphaBlend(hDC, x, y, width, height, + hMemDC, 0, 0, width, height, + blendfunc); + } + else if (bpp == 8 && hMask) + MaskBlt(hDC, x, y, width, height, + hMemDC, 0, 0, + hMask, 0, 0, MAKEROP4(SRCCOPY, 0xAA0000)); + else + BitBlt(hDC, x, y, width, height, + hMemDC, 0, 0, + SRCCOPY); + + + DeleteDC(hMemDC); +} + +void iupwinDrawInit(void) +{ + if (!winAlphaBlend) + { + HINSTANCE lib = LoadLibrary("Msimg32"); + if (lib) + winAlphaBlend = (_winAlphaBlendFunc)GetProcAddress(lib, "AlphaBlend"); + } + + if (!winThemeOpenData && iupwin_comctl32ver6) + { + HMODULE hinstDll = LoadLibrary("uxtheme.dll"); + if (hinstDll) + { + winThemeOpenData = (_winThemeOpenData)GetProcAddress(hinstDll, "OpenThemeData"); + winThemeCloseData = (_winThemeCloseData)GetProcAddress(hinstDll, "CloseThemeData"); + winThemeDrawBackground = (_winThemeDrawBackground)GetProcAddress(hinstDll, "DrawThemeBackground"); + winThemeGetColor = (_winThemeGetColor)GetProcAddress(hinstDll, "GetThemeColor"); + } + } +} + +static int winDrawGetThemeStateId(int itemState) +{ + if (itemState & ODS_DISABLED) + return PBS_DISABLED; + else if (itemState & ODS_SELECTED) + return PBS_PRESSED; + else if (itemState & ODS_HOTLIGHT) + return PBS_HOT; + else if (itemState & ODS_DEFAULT) + return PBS_DEFAULTED; + else + return PBS_NORMAL; +} + +static int winDrawThemeButtonBorder(HWND hWnd, HDC hDC, RECT *rect, UINT itemState) +{ + int iStateId; + HTHEME hTheme; + + if (!winDrawThemeEnabled()) + return 0; + + hTheme = winThemeOpenData(hWnd, L"BUTTON"); + if (!hTheme) + return 0; + + iStateId = winDrawGetThemeStateId(itemState); + + winThemeDrawBackground(hTheme, hDC, BP_PUSHBUTTON, iStateId, rect, NULL); + + winThemeCloseData(hTheme); + return 1; +} + +void iupwinDrawThemeFrameBorder(HWND hWnd, HDC hDC, RECT *rect, UINT itemState) +{ + int iStateId = GBS_NORMAL; + HTHEME hTheme; + + if (!winDrawThemeEnabled()) + return; + + hTheme = winThemeOpenData(hWnd, L"BUTTON"); + if (!hTheme) + return; + + if (itemState & ODS_DISABLED) + iStateId = GBS_DISABLED; + + winThemeDrawBackground(hTheme, hDC, BP_GROUPBOX, iStateId, rect, NULL); + + winThemeCloseData(hTheme); +} + +int iupwinDrawGetThemeTabsBgColor(HWND hWnd, COLORREF *color) +{ + HTHEME hTheme; + HRESULT ret; + + if (!winDrawThemeEnabled()) + return 0; + + hTheme = winThemeOpenData(hWnd, L"TAB"); + if (!hTheme) + return 0; + + if (iupwinIsVista()) + ret = winThemeGetColor(hTheme, TABP_AEROWIZARDBODY, TIS_NORMAL, TMT_FILLCOLORHINT, color); + else + ret = winThemeGetColor(hTheme, TABP_BODY, TIS_NORMAL, TMT_FILLCOLORHINT, color); + + winThemeCloseData(hTheme); + return (ret == S_OK)? 1: 0; +} + +int iupwinDrawGetThemeButtonBgColor(HWND hWnd, COLORREF *color) +{ + HTHEME hTheme; + HRESULT ret; + + if (!winDrawThemeEnabled()) + return 0; + + hTheme = winThemeOpenData(hWnd, L"BUTTON"); + if (!hTheme) + return 0; + + ret = winThemeGetColor(hTheme, BP_PUSHBUTTON, PBS_NORMAL, TMT_FILLCOLORHINT, color); + + winThemeCloseData(hTheme); + return (ret == S_OK)? 1: 0; +} + +int iupwinDrawGetThemeFrameFgColor(HWND hWnd, COLORREF *color) +{ + HTHEME hTheme; + HRESULT ret; + + if (!winDrawThemeEnabled()) + return 0; + + hTheme = winThemeOpenData(hWnd, L"BUTTON"); + if (!hTheme) + return 0; + + ret = winThemeGetColor(hTheme, BP_GROUPBOX, GBS_NORMAL, TMT_TEXTCOLOR, color); + + winThemeCloseData(hTheme); + return (ret == S_OK)? 1: 0; +} + +static int winDrawGetStateId(int itemState) +{ + if (itemState & ODS_DISABLED) + return DFCS_INACTIVE; + else if (itemState & ODS_SELECTED) + return DFCS_PUSHED; + else if (itemState & ODS_HOTLIGHT) + return DFCS_HOT; + else + return 0; +} + +void iupwinDrawButtonBorder(HWND hWnd, HDC hDC, RECT *rect, UINT itemState) +{ + if (!winDrawThemeButtonBorder(hWnd, hDC, rect, itemState)) + { + DrawFrameControl(hDC, rect, DFC_BUTTON, DFCS_BUTTONPUSH | winDrawGetStateId(itemState)); + if (itemState & ODS_DEFAULT) /* if a button has the focus, must draw the default button frame */ + FrameRect(hDC, rect, (HBRUSH)GetStockObject(BLACK_BRUSH)); + } +} + +void iupdrvDrawFocusRect(Ihandle* ih, void* gc, int x, int y, int w, int h) +{ + HDC hDC = (HDC)gc; + RECT rect; + (void)ih; + + rect.left = x; + rect.top = y; + rect.right = x+w; + rect.bottom = y+h; + + DrawFocusRect(hDC, &rect); +} + +void iupwinDrawRemoveTheme(HWND hwnd) +{ + typedef HRESULT (STDAPICALLTYPE *winSetWindowTheme)(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList); + static winSetWindowTheme mySetWindowTheme = NULL; + if (!mySetWindowTheme) + { + HMODULE hinstDll = LoadLibrary("uxtheme.dll"); + if (hinstDll) + mySetWindowTheme = (winSetWindowTheme)GetProcAddress(hinstDll, "SetWindowTheme"); + } + + if (mySetWindowTheme) + mySetWindowTheme(hwnd, L"", L""); +} + +void iupwinDrawParentBackground(Ihandle* ih, HDC hDC, RECT* rect) +{ + unsigned char r=0, g=0, b=0; + char* color = iupBaseNativeParentGetBgColorAttrib(ih); + iupStrToRGB(color, &r, &g, &b); + SetDCBrushColor(hDC, RGB(r,g,b)); + FillRect(hDC, rect, (HBRUSH)GetStockObject(DC_BRUSH)); +} + +HDC iupwinDrawCreateBitmapDC(iupwinBitmapDC *bmpDC, HDC hDC, int w, int h) +{ + bmpDC->w = w; + bmpDC->h = h; + bmpDC->hDC = hDC; + + bmpDC->hBitmap = CreateCompatibleBitmap(bmpDC->hDC, w, h); + bmpDC->hBitmapDC = CreateCompatibleDC(bmpDC->hDC); + bmpDC->hOldBitmap = SelectObject(bmpDC->hBitmapDC, bmpDC->hBitmap); + return bmpDC->hBitmapDC; +} + +void iupwinDrawDestroyBitmapDC(iupwinBitmapDC *bmpDC) +{ + BitBlt(bmpDC->hDC, 0, 0, bmpDC->w, bmpDC->h, bmpDC->hBitmapDC, 0, 0, SRCCOPY); + SelectObject(bmpDC->hBitmapDC, bmpDC->hOldBitmap); + DeleteObject(bmpDC->hBitmap); + DeleteDC(bmpDC->hBitmapDC); +} + diff --git a/iup/src/win/iupwin_draw.h b/iup/src/win/iupwin_draw.h new file mode 100755 index 0000000..c9a57e6 --- /dev/null +++ b/iup/src/win/iupwin_draw.h @@ -0,0 +1,47 @@ +/** \file + * \brief Draw Functions + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPWIN_DRAW_H +#define __IUPWIN_DRAW_H + +#ifdef __cplusplus +extern "C" { +#endif + + +void iupwinDrawInit(void); + +void iupwinDrawBitmap(HDC hDC, HBITMAP hBitmap, HBITMAP hMask, int x, int y, int width, int height, int bpp); +void iupwinDrawText(HDC hDC, const char* text, int x, int y, int width, int height, HFONT hFont, COLORREF fgcolor, int style); + +void iupwinDrawParentBackground(Ihandle* ih, HDC hDC, RECT* rect); +void iupwinDrawButtonBorder(HWND hWnd, HDC hDC, RECT *rect, UINT itemState); + +void iupwinDrawThemeFrameBorder(HWND hWnd, HDC hDC, RECT *rect, UINT itemState); +int iupwinDrawGetThemeTabsBgColor(HWND hWnd, COLORREF *color); +int iupwinDrawGetThemeButtonBgColor(HWND hWnd, COLORREF *color); +int iupwinDrawGetThemeFrameFgColor(HWND hWnd, COLORREF *color); +void iupwinDrawRemoveTheme(HWND hWnd); + +typedef struct _iupwinBitmapDC +{ + HBITMAP hBitmap, hOldBitmap; + HDC hBitmapDC, hDC; + int w, h; +} iupwinBitmapDC; + +HDC iupwinDrawCreateBitmapDC(iupwinBitmapDC *bmpDC, HDC hDC, int w, int h); +void iupwinDrawDestroyBitmapDC(iupwinBitmapDC *bmpDC); + +#ifndef ODS_HOTLIGHT /* Only defined if WINVER >= 0x0500 */ +#define ODS_HOTLIGHT 0x0040 +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/win/iupwin_drv.h b/iup/src/win/iupwin_drv.h new file mode 100755 index 0000000..3372c1a --- /dev/null +++ b/iup/src/win/iupwin_drv.h @@ -0,0 +1,113 @@ +/** \file + * \brief Windows Driver + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPWIN_DRV_H +#define __IUPWIN_DRV_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifndef WS_EX_COMPOSITED +#define WS_EX_COMPOSITED 0x02000000L /* it is defined only when _WIN32_WINNT >= 0x0501 */ +#endif + + +/* global variables */ +/* declared where they are initialized */ +extern HINSTANCE iupwin_hinstance; /* winopen.c */ +extern HINSTANCE iupwin_dll_hinstance; /* winmain.c */ +extern int iupwin_comctl32ver6; /* winopen.c */ + +void iupwinShowLastError(void); + +/* focus */ +void iupwinWmSetFocus(Ihandle *ih); + +/* key */ +int iupwinKeyEvent(Ihandle* ih, int wincode, int press); +void iupwinButtonKeySetStatus(WORD keys, char* status, int doubleclick); +void iupwinKeyEncode(int key, unsigned int *keyval, unsigned int *state); + +/* tips */ +void iupwinTipsGetDispInfo(LPARAM lp); + +/* font */ +char* iupwinGetHFontAttrib(Ihandle *ih); +HFONT iupwinGetHFont(const char* value); +char* iupwinFindHFont(HFONT hFont); + +/* menu */ +void iupwinMenuDialogProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp); + +/* common */ + +/* Definition of a callback used to return the background brush of controls called "_IUPWIN_CTLCOLOR_CB". */ +typedef int (*IFctlColor)(Ihandle* ih, HDC hdc, LRESULT *result); + +/* Definition of a callback used to draw custom controls called "_IUPWIN_DRAWITEM_CB". + drawitem is a pointer to a DRAWITEMSTRUCT struct. */ +typedef void (*IFdrawItem)(Ihandle* ih, void* drawitem); + +/* Definition of a callback used to notify custom controls called "_IUPWIN_NOTIFY_CB". + msg_info is a pointer to a NMHDR struct. */ +typedef int (*IFnotify)(Ihandle* ih, void* msg_info, HRESULT *result); + +/* Definition of callback used for custom WinProc. Can return 0 or 1. + 0 = do default processing. + 1 = ABORT default processing and the result value should be returned. +*/ +typedef int (*IwinProc)(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result); + +/* Base WinProc used by all native elements. Configure base message handling + and custom IwinProc using "_IUPWIN_CTRLPROC_CB" callback. */ +LRESULT CALLBACK iupwinBaseWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); + +/* Base IwinProc callback used by native controls. */ +int iupwinBaseProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result); + +/* Base IwinProc callback used by native containers. + Handle messages that are sent to the parent Window. */ +int iupwinBaseContainerProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result); + +/* Creates the Window with native parent and child ID, associate HWND with Ihandle*, + and replace the WinProc by iupwinBaseWinProc */ +int iupwinCreateWindowEx(Ihandle* ih, LPCSTR lpClassName, DWORD dwExStyle, DWORD dwStyle); + +int iupwinClassExist(const char* name); +int iupwinGetColorRef(Ihandle *ih, char *name, COLORREF *color); +int iupwinGetParentBgColor(Ihandle* ih, COLORREF* cr); +void iupwinDropFiles(HDROP hDrop, Ihandle *ih); +Ihandle* iupwinMenuGetItemHandle(HMENU hmenu, int menuId); +Ihandle* iupwinMenuGetHandle(HMENU hMenu); +int iupwinSetDragDropAttrib(Ihandle* ih, const char* value); +void iupwinChangeProc(Ihandle *ih, WNDPROC new_proc); +void iupwinMergeStyle(Ihandle* ih, DWORD old_mask, DWORD value); +void iupwinSetStyle(Ihandle* ih, DWORD value, int set); +WCHAR* iupwinStrChar2Wide(const char* str); +int iupwinButtonUp(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp); +int iupwinButtonDown(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp); +int iupwinMouseMove(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp); +char* iupwinGetClipboardText(Ihandle* ih); + +int iupwinGetScreenRes(void); +/* 1 point = 1/72 inch */ +/* pixel = (point/72)*(pixel/inch) */ +#define IUPWIN_PT2PIXEL(_pt, _res) MulDiv(_pt, _res, 72) /* (((_pt)*(_res))/72) */ +#define IUPWIN_PIXEL2PT(_pixel, _res) MulDiv(_pixel, 72, _res) /* (((_pixel)*72)/(_res)) */ + + +/* child window identifier of the first MDI child window created, + should not conflict with any other command identifiers. */ +#define IUP_MDICHILD_START 100000000 + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/win/iupwin_filedlg.c b/iup/src/win/iupwin_filedlg.c new file mode 100755 index 0000000..da66b4b --- /dev/null +++ b/iup/src/win/iupwin_filedlg.c @@ -0,0 +1,580 @@ +/** \file + * \brief IupFileDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> +#include <commdlg.h> +#include <shlobj.h> + +#include <stdio.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_dialog.h" +#include "iup_drvinfo.h" + +#include "iupwin_drv.h" + + +#ifndef OFN_FORCESHOWHIDDEN +#define OFN_FORCESHOWHIDDEN 0x10000000 /* Show All files including System and hidden files */ +#endif + +#define MAX_FILENAME_SIZE 65000 +#define IUP_PREVIEWCANVAS 3000 + +enum {IUP_DIALOGOPEN, IUP_DIALOGSAVE, IUP_DIALOGDIR}; + + +static void winFileDlgStrReplacePathSlash(char* name) +{ + /* check for "/" */ + int i, len = strlen(name); + for (i = 0; i < len; i++) + { + if (name[i] == '/') + name[i] = '\\'; + } +} + +static INT CALLBACK winFileDlgBrowseCallback(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData) +{ + (void)lParam; + if (uMsg == BFFM_INITIALIZED) + { + char* value; + Ihandle* ih = (Ihandle*)lpData; + ih->handle = hWnd; + iupDialogUpdatePosition(ih); + ih->handle = NULL; /* reset handle */ + value = iupStrDup(iupAttribGet(ih, "DIRECTORY")); + if (value) + { + winFileDlgStrReplacePathSlash(value); + SendMessage(hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)value); + free(value); + } + } + else if (uMsg == BFFM_SELCHANGED) + { + char* buffer = iupStrGetMemory(MAX_FILENAME_SIZE); + ITEMIDLIST* selecteditem = (ITEMIDLIST*)lParam; + buffer[0] = 0; + SHGetPathFromIDList(selecteditem, buffer); + if (buffer[0] == 0) + SendMessage(hWnd, BFFM_ENABLEOK, 0, (LPARAM)FALSE); + else + SendMessage(hWnd, BFFM_ENABLEOK, 0, (LPARAM)TRUE); + } + return 0; +} + +static void winFileDlgGetFolder(Ihandle *ih) +{ + InativeHandle* parent = iupDialogGetNativeParent(ih); + BROWSEINFO browseinfo; + char buffer[MAX_PATH]; + ITEMIDLIST *selecteditem; + + if (!parent) + parent = GetActiveWindow(); + + ZeroMemory(&browseinfo, sizeof(BROWSEINFO)); + browseinfo.lpszTitle = iupAttribGet(ih, "TITLE"); + browseinfo.pszDisplayName = buffer; + browseinfo.lpfn = winFileDlgBrowseCallback; + browseinfo.lParam = (LPARAM)ih; + browseinfo.ulFlags = BIF_NEWDIALOGSTYLE; + browseinfo.hwndOwner = parent; + + selecteditem = SHBrowseForFolder(&browseinfo); + if (!selecteditem) + { + iupAttribSetStr(ih, "VALUE", NULL); + iupAttribSetStr(ih, "STATUS", "-1"); + } + else + { + SHGetPathFromIDList(selecteditem, buffer); + iupAttribStoreStr(ih, "VALUE", buffer); + iupAttribSetStr(ih, "STATUS", "0"); + } + + iupAttribSetStr(ih, "FILEEXIST", NULL); + iupAttribSetStr(ih, "FILTERUSED", NULL); +} + +/************************************************************************************************/ + +static UINT_PTR CALLBACK winFileDlgSimpleHook(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) +{ + (void)wParam; + switch(uiMsg) + { + case WM_INITDIALOG: + { + OPENFILENAME* openfilename = (OPENFILENAME*)lParam; + Ihandle* ih = (Ihandle*)openfilename->lCustData; + ih->handle = GetParent(hWnd); + iupDialogUpdatePosition(ih); + ih->handle = NULL; /* reset handle */ + SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)ih); + break; + } + case WM_DESTROY: + { + Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER); + IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + if (cb) cb(ih, NULL, "FINISH"); + break; + } + case WM_NOTIFY: + { + LPOFNOTIFY pofn = (LPOFNOTIFY)lParam; + Ihandle* ih = (Ihandle*)pofn->lpOFN->lCustData; + switch (pofn->hdr.code) + { + case CDN_INITDONE: + { + IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + if (cb) cb(ih, NULL, "INIT"); + break; + } + case CDN_FILEOK: + case CDN_SELCHANGE: + { + IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + if (cb) + { + char* filename = iupStrGetMemory(MAX_FILENAME_SIZE); + if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE) + { + int ret; + char* file_msg; + + if (!iupdrvIsFile(filename)) + break; + + if (pofn->hdr.code == CDN_FILEOK) + file_msg = "OK"; + else + file_msg = "SELECT"; + + ret = cb(ih, filename, file_msg); + if (pofn->hdr.code == CDN_FILEOK && ret == IUP_IGNORE) + { + SetWindowLongPtr(hWnd, DWLP_MSGRESULT, 1L); + return 1; /* will refuse the file */ + } + } + } + break; + } + case CDN_HELP: + { + Icallback cb = (Icallback) IupGetCallback(ih, "HELP_CB"); + if (cb && cb(ih) == IUP_CLOSE) + EndDialog(GetParent(hWnd), IDCANCEL); + break; + } + } + break; + } + } + return 0; +} + +static void winFileDlgSetPreviewCanvasPos(HWND hWnd, HWND hWndPreview) +{ + int height, width, ypos, xpos; + RECT rect, dlgrect; + HWND hWndFileList = GetDlgItem(GetParent(hWnd), 0x0471); + HWND hWndFileCombo = GetDlgItem(GetParent(hWnd), 0x047C); + + /* GetWindowRect return screen coordinates, must convert to parent's client coordinates */ + GetWindowRect(hWnd, &dlgrect); + + GetWindowRect(hWndPreview, &rect); + ypos = rect.top - dlgrect.top; /* keep the same vertical position, at first time this is 0 */ + height = rect.bottom-rect.top; /* keep the same height */ + + GetWindowRect(hWndFileList, &rect); + xpos = rect.left - dlgrect.left; /* horizontally align with file list at left */ + + GetWindowRect(hWndFileCombo, &rect); + width = (rect.right - dlgrect.left) - xpos; /* set size to align with file combo at right */ + + /* also position the child window that contains the template, must have room for the preview canvas */ + if (ypos) /* first time does nothing */ + SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, (rect.right - dlgrect.left), (dlgrect.bottom - dlgrect.top), SWP_NOMOVE|SWP_NOZORDER); + + SetWindowPos(hWndPreview, HWND_TOP, xpos, ypos, width, height, SWP_NOZORDER); +} + +static void winFileDlgUpdatePreviewGLCanvas(Ihandle* ih) +{ + Ihandle* glcanvas = IupGetAttributeHandle(ih, "PREVIEWGLCANVAS"); + if (glcanvas) + { + iupAttribSetStr(glcanvas, "HWND", iupAttribGet(ih, "HWND")); + glcanvas->iclass->Map(glcanvas); + } +} + +static UINT_PTR CALLBACK winFileDlgPreviewHook(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) +{ + /* hWnd here is a handle to the child window that contains the template, + NOT the file dialog. Only the preview canvas is a child of this window. */ + + switch(uiMsg) + { + case WM_INITDIALOG: + { + OPENFILENAME* openfilename = (OPENFILENAME*)lParam; + Ihandle* ih = (Ihandle*)openfilename->lCustData; + HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS); + + ih->handle = GetParent(hWnd); + iupDialogUpdatePosition(ih); + ih->handle = NULL; /* reset handle */ + + if (hWndPreview) + { + RECT rect; + + winFileDlgSetPreviewCanvasPos(hWnd, hWndPreview); + + GetClientRect(hWndPreview, &rect); + iupAttribSetInt(ih, "PREVIEWWIDTH", rect.right - rect.left); + iupAttribSetInt(ih, "PREVIEWHEIGHT", rect.bottom - rect.top); + } + SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)ih); + iupAttribSetStr(ih, "WID", (char*)hWndPreview); + iupAttribSetStr(ih, "HWND", (char*)hWndPreview); + winFileDlgUpdatePreviewGLCanvas(ih); + break; + } + case WM_DRAWITEM: + { + if (wParam == IUP_PREVIEWCANVAS) + { + LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT)lParam; + Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER); + IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + char* filename = iupStrGetMemory(MAX_FILENAME_SIZE); + iupAttribSetStr(ih, "PREVIEWDC", (char*)lpDrawItem->hDC); + if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE) + { + if (iupdrvIsFile(filename)) + cb(ih, filename, "PAINT"); + else + cb(ih, NULL, "PAINT"); + } + else + cb(ih, NULL, "PAINT"); + iupAttribSetStr(ih, "PREVIEWDC", NULL); + } + break; + } + case WM_SIZE: + { + HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS); + if (hWndPreview) + { + Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER); + RECT rect; + + winFileDlgSetPreviewCanvasPos(hWnd, hWndPreview); + + GetClientRect(hWndPreview, &rect); + iupAttribSetInt(ih, "PREVIEWWIDTH", rect.right-rect.left); + + RedrawWindow(hWndPreview, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW); + } + break; + } + case WM_DESTROY: + { + Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER); + IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + cb(ih, NULL, "FINISH"); + break; + } + case WM_NOTIFY: + { + LPOFNOTIFY pofn = (LPOFNOTIFY)lParam; + Ihandle* ih = (Ihandle*)pofn->lpOFN->lCustData; + IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + switch (pofn->hdr.code) + { + case CDN_INITDONE: + { + HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS); + cb(ih, NULL, "INIT"); + if (hWndPreview) RedrawWindow(hWndPreview, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW); + break; + } + case CDN_FILEOK: + case CDN_SELCHANGE: + { + HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS); + char* filename = iupStrGetMemory(MAX_FILENAME_SIZE); + if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE) + { + int ret; + char* file_msg; + + if (!iupdrvIsFile(filename)) + break; + + if (pofn->hdr.code == CDN_FILEOK) + file_msg = "OK"; + else + file_msg = "SELECT"; + + ret = cb(ih, filename, file_msg); + if (pofn->hdr.code == CDN_FILEOK && ret == IUP_IGNORE) + { + SetWindowLongPtr(hWnd, DWLP_MSGRESULT, 1L); + return 1; /* will refuse the file */ + } + } + if (pofn->hdr.code == CDN_SELCHANGE && hWndPreview) + RedrawWindow(hWndPreview, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW); + break; + } + case CDN_HELP: + { + Icallback cb = (Icallback) IupGetCallback(ih, "HELP_CB"); + if (cb && cb(ih) == IUP_CLOSE) + EndDialog(GetParent(hWnd), IDCANCEL); + break; + } + } + break; + } + } + return 0; +} + +static char* winFileDlgStrReplaceSeparator(const char* name) +{ + int i=0; + char* buffer = (char*)malloc(strlen(name)+2); + + /* replace symbols "|" by terminator "\0" */ + + while (*name) + { + buffer[i] = *name; + + if (buffer[i] == '|') + buffer[i] = 0; + + i++; + name++; + } + + buffer[i] = 0; + buffer[i+1] = 0; /* additional 0 at the end */ + return buffer; +} + +static int winFileDlgPopup(Ihandle *ih, int x, int y) +{ + InativeHandle* parent = iupDialogGetNativeParent(ih); + OPENFILENAME openfilename; + int result, dialogtype; + char *value; + + iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */ + iupAttribSetInt(ih, "_IUPDLG_Y", y); + + value = iupAttribGetStr(ih, "DIALOGTYPE"); + if (iupStrEqualNoCase(value, "SAVE")) + dialogtype = IUP_DIALOGSAVE; + else if (iupStrEqualNoCase(value, "DIR")) + dialogtype = IUP_DIALOGDIR; + else + dialogtype = IUP_DIALOGOPEN; + + if (dialogtype == IUP_DIALOGDIR) + { + winFileDlgGetFolder(ih); + return IUP_NOERROR; + } + + if (!parent) + parent = GetActiveWindow(); + + ZeroMemory(&openfilename, sizeof(OPENFILENAME)); + openfilename.lStructSize = sizeof(OPENFILENAME); + openfilename.hwndOwner = parent; + + value = iupAttribGet(ih, "EXTFILTER"); + if (value) + { + int index; + openfilename.lpstrFilter = winFileDlgStrReplaceSeparator(value); + + value = iupAttribGet(ih, "FILTERUSED"); + if (iupStrToInt(value, &index)) + openfilename.nFilterIndex = index; + else + openfilename.nFilterIndex = 1; + } + else + { + value = iupAttribGet(ih, "FILTER"); + if (value) + { + int sz1, sz2; + char* info = iupAttribGet(ih, "FILTERINFO"); + if (!info) + info = value; + + /* concat FILTERINFO+FILTER */ + sz1 = strlen(info)+1; + sz2 = strlen(value)+1; + openfilename.lpstrFilter = (char*)malloc(sz1+sz2+1); + + memcpy((char*)openfilename.lpstrFilter, info, sz1); + memcpy((char*)openfilename.lpstrFilter+sz1, value, sz2); + ((char*)openfilename.lpstrFilter)[sz1+sz2] = 0; /* additional 0 at the end */ + openfilename.nFilterIndex = 1; + } + } + + openfilename.lpstrFile = (char*)malloc(MAX_FILENAME_SIZE+1); + value = iupAttribGet(ih, "FILE"); + if (value) + { + strncpy(openfilename.lpstrFile, value, MAX_FILENAME_SIZE); + winFileDlgStrReplacePathSlash(openfilename.lpstrFile); + } + else + openfilename.lpstrFile[0] = 0; + + openfilename.nMaxFile = MAX_FILENAME_SIZE; + + openfilename.lpstrInitialDir = iupStrDup(iupAttribGet(ih, "DIRECTORY")); + if (openfilename.lpstrInitialDir) + winFileDlgStrReplacePathSlash((char*)openfilename.lpstrInitialDir); + + openfilename.lpstrTitle = iupAttribGet(ih, "TITLE"); + openfilename.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; + + if (!iupAttribGetBoolean(ih, "NOOVERWRITEPROMPT")) + openfilename.Flags |= OFN_OVERWRITEPROMPT; + + if (iupAttribGetBoolean(ih, "SHOWHIDDEN")) + openfilename.Flags |= OFN_FORCESHOWHIDDEN; + + value = iupAttribGet(ih, "ALLOWNEW"); + if (!value) + { + if (dialogtype == IUP_DIALOGSAVE) + value = "YES"; + else + value = "NO"; + } + if (iupStrBoolean(value)) + openfilename.Flags |= OFN_CREATEPROMPT; + else + openfilename.Flags |= OFN_FILEMUSTEXIST; + + if (iupAttribGetBoolean(ih, "NOCHANGEDIR")) + openfilename.Flags |= OFN_NOCHANGEDIR; + + if (iupAttribGetBoolean(ih, "MULTIPLEFILES")) + openfilename.Flags |= OFN_ALLOWMULTISELECT; + + openfilename.lpfnHook = winFileDlgSimpleHook; + openfilename.Flags |= OFN_ENABLEHOOK | OFN_EXPLORER | OFN_ENABLESIZING; + openfilename.lCustData = (LPARAM)ih; + + if (iupAttribGetBoolean(ih, "SHOWPREVIEW") && IupGetCallback(ih, "FILE_CB")) + { + openfilename.Flags |= OFN_ENABLETEMPLATE; + openfilename.hInstance = iupwin_dll_hinstance? iupwin_dll_hinstance: iupwin_hinstance; + openfilename.lpTemplateName = "iupPreviewDlg"; + openfilename.lpfnHook = winFileDlgPreviewHook; + } + + if (IupGetCallback(ih, "HELP_CB")) + openfilename.Flags |= OFN_SHOWHELP; + + if (dialogtype == IUP_DIALOGOPEN) + result = GetOpenFileName(&openfilename); + else + result = GetSaveFileName(&openfilename); + + if (result) + { + if (iupAttribGetBoolean(ih, "MULTIPLEFILES")) + { + int i = 0; + + /* If there is more than one file, replace terminator by the separator */ + if (openfilename.lpstrFile && openfilename.lpstrFile[openfilename.nFileOffset-1] == 0 && openfilename.nFileOffset>0) + { + while (openfilename.lpstrFile[i] != 0 || openfilename.lpstrFile[i+1] != 0) + { + if (openfilename.lpstrFile[i]==0) + openfilename.lpstrFile[i] = '|'; + i++; + } + openfilename.lpstrFile[i] = '|'; + } + + iupAttribSetStr(ih, "STATUS", "0"); + iupAttribSetStr(ih, "FILEEXIST", NULL); + } + else + { + if (iupdrvIsFile(openfilename.lpstrFile)) /* check if file exists */ + { + iupAttribSetStr(ih, "FILEEXIST", "YES"); + iupAttribSetStr(ih, "STATUS", "0"); + } + else + { + iupAttribSetStr(ih, "FILEEXIST", "NO"); + iupAttribSetStr(ih, "STATUS", "1"); + } + } + + iupAttribStoreStr(ih, "VALUE", openfilename.lpstrFile); + iupAttribSetInt(ih, "FILTERUSED", (int)openfilename.nFilterIndex); + } + else + { + iupAttribSetStr(ih, "FILTERUSED", NULL); + iupAttribSetStr(ih, "VALUE", NULL); + iupAttribSetStr(ih, "FILEEXIST", NULL); + iupAttribSetStr(ih, "STATUS", "-1"); + } + + if (openfilename.lpstrFilter) free((char*)openfilename.lpstrFilter); + if (openfilename.lpstrInitialDir) free((char*)openfilename.lpstrInitialDir); + if (openfilename.lpstrFile) free(openfilename.lpstrFile); + + return IUP_NOERROR; +} + +void iupdrvFileDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = winFileDlgPopup; + + /* IupFileDialog Windows and GTK Only */ + iupClassRegisterAttribute(ic, "EXTFILTER", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FILTERINFO", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FILTERUSED", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MULTIPLEFILES", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); +} diff --git a/iup/src/win/iupwin_focus.c b/iup/src/win/iupwin_focus.c new file mode 100755 index 0000000..63da02d --- /dev/null +++ b/iup/src/win/iupwin_focus.c @@ -0,0 +1,62 @@ +/** \file + * \brief Windows Focus + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> + +#include <windows.h> + +#include "iup.h" +#include "iup_object.h" +#include "iup_focus.h" +#include "iup_assert.h" +#include "iup_drv.h" +#include "iup_attrib.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" + +/* not defined for gcc */ +#ifndef WM_CHANGEUISTATE +#define WM_CHANGEUISTATE 0x0127 +#endif +#ifndef UIS_CLEAR +#define UIS_CLEAR 2 +#endif +#ifndef UISF_HIDEFOCUS +#define UISF_HIDEFOCUS 0x1 +#endif + +/* Since Windows XP, the focus feedback only appears after the user press a key. + Except for the IupText where the feedback is the caret. + Before that if you click in a control the focus feedback will be hidden. + + We manually send WM_CHANGEUISTATE because we do not use IsDialogMessage anymore, + and the focus feedback was not shown even after the used press a key. + + TODO: I would like a form to always show the feedback, but could not understand how WM_CHANGEUISTATE works. + Neither SystemParametersInfo(SPI_SETKEYBOARDCUES, TRUE) or SystemParametersInfo(SPI_SETKEYBOARDPREF, TRUE) worked. +*/ +void iupdrvSetFocus(Ihandle *ih) +{ + SetFocus(ih->handle); + SendMessage(ih->handle, WM_CHANGEUISTATE, UIS_CLEAR|UISF_HIDEFOCUS, 0); +} + +void iupwinWmSetFocus(Ihandle *ih) +{ + Ihandle* dialog = IupGetDialog(ih); + if (ih != dialog) + iupAttribSetStr(dialog, "_IUPWIN_LASTFOCUS", (char*)ih); /* used by IupMenu */ + else + { + /* if a control inside that dialog had the focus, then reset to it when the dialog gets the focus */ + Ihandle* lastfocus = (Ihandle*)iupAttribGet(dialog, "_IUPWIN_LASTFOCUS"); + if (lastfocus) IupSetFocus(lastfocus); + } + + iupCallGetFocusCb(ih); +} diff --git a/iup/src/win/iupwin_font.c b/iup/src/win/iupwin_font.c new file mode 100755 index 0000000..659e2d9 --- /dev/null +++ b/iup/src/win/iupwin_font.c @@ -0,0 +1,342 @@ +/** \file + * \brief Windows Font mapping + * + * See Copyright Notice in "iup.h" + */ + + +#include <stdlib.h> +#include <stdio.h> + +#include <windows.h> + +#include "iup.h" + +#include "iup_str.h" +#include "iup_array.h" +#include "iup_attrib.h" +#include "iup_object.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_assert.h" + +#include "iupwin_drv.h" +#include "iupwin_info.h" + + +typedef struct IwinFont_ +{ + char standardfont[200]; + HFONT hFont; + int charwidth, charheight; +} IwinFont; + +static Iarray* win_fonts = NULL; + +static IwinFont* winFindFont(const char *standardfont) +{ + HFONT hFont; + int height_pixels; + char typeface[50] = ""; + int height = 8; + int is_bold = 0, + is_italic = 0, + is_underline = 0, + is_strikeout = 0; + int res = iupwinGetScreenRes(); + int i, count = iupArrayCount(win_fonts); + const char* mapped_name; + + /* Check if the standardfont already exists in cache */ + IwinFont* fonts = (IwinFont*)iupArrayGetData(win_fonts); + for (i = 0; i < count; i++) + { + if (iupStrEqualNoCase(standardfont, fonts[i].standardfont)) + return &fonts[i]; + } + + /* parse the old format first */ + if (!iupFontParseWin(standardfont, typeface, &height, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParsePango(standardfont, typeface, &height, &is_bold, &is_italic, &is_underline, &is_strikeout)) + return NULL; + } + + mapped_name = iupFontGetWinName(typeface); + if (mapped_name) + strcpy(typeface, mapped_name); + + /* get in pixels */ + if (height < 0) + height_pixels = height; /* already in pixels */ + else + height_pixels = -IUPWIN_PT2PIXEL(height, res); + + if (height_pixels == 0) + return NULL; + + hFont = CreateFont(height_pixels, + 0,0,0, + (is_bold) ? FW_BOLD : FW_NORMAL, + is_italic, + is_underline, + is_strikeout, + DEFAULT_CHARSET,OUT_TT_PRECIS, + CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY, + FF_DONTCARE|DEFAULT_PITCH, + typeface); + if (!hFont) + return NULL; + + /* create room in the array */ + fonts = (IwinFont*)iupArrayInc(win_fonts); + + strcpy(fonts[i].standardfont, standardfont); + fonts[i].hFont = hFont; + + { + TEXTMETRIC tm; + HDC hdc = GetDC(NULL); + HFONT oldfont = SelectObject(hdc, hFont); + + GetTextMetrics(hdc, &tm); + + SelectObject(hdc, oldfont); + ReleaseDC(NULL, hdc); + + fonts[i].charwidth = tm.tmAveCharWidth; + fonts[i].charheight = tm.tmHeight; + } + + return &fonts[i]; +} + +static void winFontFromLogFont(LOGFONT* logfont, char * font) +{ + int is_bold = (logfont->lfWeight == FW_NORMAL)? 0: 1; + int is_italic = logfont->lfItalic; + int is_underline = logfont->lfUnderline; + int is_strikeout = logfont->lfStrikeOut; + int height_pixels = logfont->lfHeight; /* negative value */ + int res = iupwinGetScreenRes(); + int height = IUPWIN_PIXEL2PT(-height_pixels, res); /* return in points */ + + sprintf(font, "%s, %s%s%s%s %d", logfont->lfFaceName, + is_bold?"Bold ":"", + is_italic?"Italic ":"", + is_underline?"Underline ":"", + is_strikeout?"Strikeout ":"", + height); +} + +char* iupdrvGetSystemFont(void) +{ + static char systemfont[200] = ""; + NONCLIENTMETRICS ncm; + ncm.cbSize = sizeof(NONCLIENTMETRICS); + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, FALSE)) + winFontFromLogFont(&ncm.lfMessageFont, systemfont); + else + strcpy(systemfont, "Tahoma, 10"); + return systemfont; +} + +char* iupwinFindHFont(HFONT hFont) +{ + int i, count = iupArrayCount(win_fonts); + + /* Check if the standardfont already exists in cache */ + IwinFont* fonts = (IwinFont*)iupArrayGetData(win_fonts); + for (i = 0; i < count; i++) + { + if (hFont == fonts[i].hFont) + return fonts[i].standardfont; + } + + return NULL; +} + +HFONT iupwinGetHFont(const char* value) +{ + IwinFont* winfont = winFindFont(value); + if (!winfont) + return NULL; + else + return winfont->hFont; +} + +static IwinFont* winFontCreateNativeFont(Ihandle *ih, const char* value) +{ + IwinFont* winfont = winFindFont(value); + if (!winfont) + { + iupERROR1("Failed to create Font: %s", value); + return NULL; + } + + iupAttribSetStr(ih, "_IUP_WINFONT", (char*)winfont); + return winfont; +} + +static IwinFont* winFontGet(Ihandle *ih) +{ + IwinFont* winfont = (IwinFont*)iupAttribGet(ih, "_IUP_WINFONT"); + if (!winfont) + winfont = winFontCreateNativeFont(ih, iupGetFontAttrib(ih)); + return winfont; +} + +char* iupwinGetHFontAttrib(Ihandle *ih) +{ + IwinFont* winfont = winFontGet(ih); + if (!winfont) + return NULL; + else + return (char*)winfont->hFont; +} + +int iupdrvSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + IwinFont* winfont = winFontCreateNativeFont(ih, value); + if (!winfont) + return 1; + + /* If FONT is changed, must update the SIZE attribute */ + iupBaseUpdateSizeFromFont(ih); + + /* FONT attribute must be able to be set before mapping, + so the font is enable for size calculation. */ + if (ih->handle && (ih->iclass->nativetype != IUP_TYPEVOID)) + SendMessage(ih->handle, WM_SETFONT, (WPARAM)winfont->hFont, MAKELPARAM(TRUE,0)); + + return 1; +} + +static HDC winFontGetDC(Ihandle* ih) +{ + if (ih->iclass->nativetype == IUP_TYPEVOID) + return GetDC(NULL); + else + return GetDC(ih->handle); /* handle can be NULL here */ +} + +static void winFontReleaseDC(Ihandle* ih, HDC hdc) +{ + if (ih->iclass->nativetype == IUP_TYPEVOID) + ReleaseDC(NULL, hdc); + else + ReleaseDC(ih->handle, hdc); /* handle can be NULL here */ +} + +void iupdrvFontGetMultiLineStringSize(Ihandle* ih, const char* str, int *w, int *h) +{ + int num_lin, max_w; + + IwinFont* winfont = winFontGet(ih); + if (!winfont) + { + if (w) *w = 0; + if (h) *h = 0; + return; + } + + if (!str) + { + if (w) *w = 0; + if (h) *h = winfont->charheight * 1; + return; + } + + max_w = 0; + num_lin = 1; + if (str[0]) + { + SIZE size; + int len; + const char *nextstr; + const char *curstr = str; + + HDC hdc = winFontGetDC(ih); + HFONT oldhfont = SelectObject(hdc, winfont->hFont); + + do + { + nextstr = iupStrNextLine(curstr, &len); + GetTextExtentPoint32(hdc, curstr, len, &size); + max_w = iupMAX(max_w, size.cx); + + curstr = nextstr; + if (*nextstr) + num_lin++; + } while(*nextstr); + + SelectObject(hdc, oldhfont); + winFontReleaseDC(ih, hdc); + } + + if (w) *w = max_w; + if (h) *h = winfont->charheight*num_lin; +} + +int iupdrvFontGetStringWidth(Ihandle* ih, const char* str) +{ + HDC hdc; + HFONT oldhfont, hFont; + SIZE size; + int len; + char* line_end; + + if (!str || str[0]==0) + return 0; + + hFont = (HFONT)iupwinGetHFontAttrib(ih); + if (!hFont) + return 0; + + hdc = winFontGetDC(ih); + oldhfont = SelectObject(hdc, hFont); + + line_end = strchr(str, '\n'); + if (line_end) + len = line_end-str; + else + len = strlen(str); + + GetTextExtentPoint32(hdc, str, len, &size); + + SelectObject(hdc, oldhfont); + winFontReleaseDC(ih, hdc); + + return size.cx; +} + +void iupdrvFontGetCharSize(Ihandle* ih, int *charwidth, int *charheight) +{ + IwinFont* winfont = winFontGet(ih); + if (!winfont) + { + if (charwidth) *charwidth = 0; + if (charheight) *charheight = 0; + return; + } + + if (charwidth) *charwidth = winfont->charwidth; + if (charheight) *charheight = winfont->charheight; +} + +void iupdrvFontInit(void) +{ + win_fonts = iupArrayCreate(50, sizeof(IwinFont)); +} + +void iupdrvFontFinish(void) +{ + int i, count = iupArrayCount(win_fonts); + IwinFont* fonts = (IwinFont*)iupArrayGetData(win_fonts); + for (i = 0; i < count; i++) + { + DeleteObject(fonts[i].hFont); + fonts[i].hFont = NULL; + } + iupArrayDestroy(win_fonts); +} diff --git a/iup/src/win/iupwin_fontdlg.c b/iup/src/win/iupwin_fontdlg.c new file mode 100755 index 0000000..0602441 --- /dev/null +++ b/iup/src/win/iupwin_fontdlg.c @@ -0,0 +1,160 @@ +/** \file + * \brief IupFontDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> +#include <stdio.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_dialog.h" +#include "iup_drvfont.h" + +#include "iupwin_drv.h" + + +#define IUP_FONTFAMILYCOMBOBOX 0x0470 + +static UINT_PTR winFontDlgHookProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) +{ + (void)wParam; + if (uiMsg == WM_INITDIALOG) + { + HWND hWndItem; + CHOOSEFONT* choosefont = (CHOOSEFONT*)lParam; + Ihandle* ih = (Ihandle*)choosefont->lCustData; + + char* value = iupAttribGet(ih, "TITLE"); + if (value) + SetWindowText(hWnd, value); + + ih->handle = hWnd; + iupDialogUpdatePosition(ih); + ih->handle = NULL; /* reset handle */ + iupAttribSetStr(ih, "HWND", (char*)hWnd); /* used by HELP_CB in winDialogBaseProc */ + + hWndItem = GetDlgItem(hWnd, IUP_FONTFAMILYCOMBOBOX); + SetFocus(hWndItem); + } + return 0; +} + +static int winFontDlgPopup(Ihandle* ih, int x, int y) +{ + InativeHandle* parent = iupDialogGetNativeParent(ih); + unsigned char r, g, b; + CHOOSEFONT choosefont; + LOGFONT logfont; + char* standardfont; + int height_pixels; + char typeface[50] = ""; + int height = 8; + int is_bold = 0, + is_italic = 0, + is_underline = 0, + is_strikeout = 0; + int res = iupwinGetScreenRes(); + + iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */ + iupAttribSetInt(ih, "_IUPDLG_Y", y); + + if (!parent) + parent = GetActiveWindow(); + + standardfont = iupAttribGet(ih, "VALUE"); + if (!standardfont) + return IUP_ERROR; + + /* parse the old format first */ + if (!iupFontParseWin(standardfont, typeface, &height, &is_bold, &is_italic, &is_underline, &is_strikeout)) + { + if (!iupFontParsePango(standardfont, typeface, &height, &is_bold, &is_italic, &is_underline, &is_strikeout)) + return IUP_ERROR; + } + + /* get size in pixels */ + if (height < 0) + height_pixels = height; /* already in pixels */ + else + height_pixels = -IUPWIN_PT2PIXEL(height, res); + + if (height_pixels == 0) + return IUP_ERROR; + + ZeroMemory(&choosefont, sizeof(CHOOSEFONT)); + choosefont.lStructSize = sizeof(CHOOSEFONT); + + if (iupStrToRGB(iupAttribGet(ih, "COLOR"), &r, &g, &b)) + choosefont.rgbColors = RGB(r, g, b); + + choosefont.hwndOwner = parent; + choosefont.lpLogFont = &logfont; + choosefont.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT | CF_ENABLEHOOK; + choosefont.lCustData = (LPARAM)ih; + choosefont.lpfnHook = (LPCFHOOKPROC)winFontDlgHookProc; + + if (IupGetCallback(ih, "HELP_CB")) + choosefont.Flags |= CF_SHOWHELP; + + strcpy(logfont.lfFaceName, typeface); + logfont.lfHeight = height_pixels; + logfont.lfWeight = (is_bold)? FW_BOLD: FW_NORMAL; + logfont.lfItalic = (BYTE)is_italic; + logfont.lfUnderline = (BYTE)is_underline; + logfont.lfStrikeOut = (BYTE)is_strikeout; + + logfont.lfCharSet = DEFAULT_CHARSET; + logfont.lfEscapement = 0; + logfont.lfOrientation = 0; + logfont.lfWidth = 0; + logfont.lfOutPrecision = OUT_TT_PRECIS; + logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + logfont.lfQuality = DEFAULT_QUALITY; + logfont.lfPitchAndFamily = FF_DONTCARE|DEFAULT_PITCH; + + if (!ChooseFont(&choosefont)) + { + iupAttribSetStr(ih, "VALUE", NULL); + iupAttribSetStr(ih, "COLOR", NULL); + iupAttribSetStr(ih, "STATUS", NULL); + return IUP_NOERROR; + } + + is_bold = (logfont.lfWeight == FW_NORMAL)? 0: 1; + is_italic = logfont.lfItalic; + is_underline = logfont.lfUnderline; + is_strikeout = logfont.lfStrikeOut; + height_pixels = logfont.lfHeight; + + if (height < 0) /* not an error, use old value as a reference for the units */ + height = height_pixels; /* return in pixels */ + else + height = IUPWIN_PIXEL2PT(-height_pixels, res); /* return in points */ + + iupAttribSetStrf(ih, "VALUE", "%s, %s%s%s%s %d", logfont.lfFaceName, + is_bold?"Bold ":"", + is_italic?"Italic ":"", + is_underline?"Underline ":"", + is_strikeout?"Strikeout ":"", + height); + + iupAttribSetStrf(ih, "COLOR", "%d %d %d", GetRValue(choosefont.rgbColors), + GetGValue(choosefont.rgbColors), + GetBValue(choosefont.rgbColors)); + iupAttribSetStr(ih, "STATUS", "1"); + + return IUP_NOERROR; +} + +void iupdrvFontDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = winFontDlgPopup; + + /* IupFontDialog Windows Only */ + iupClassRegisterAttribute(ic, "COLOR", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); +} diff --git a/iup/src/win/iupwin_frame.c b/iup/src/win/iupwin_frame.c new file mode 100755 index 0000000..0949b5d --- /dev/null +++ b/iup/src/win/iupwin_frame.c @@ -0,0 +1,203 @@ +/** \file + * \brief Frame Control + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> +#include <commctrl.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_stdcontrols.h" +#include "iup_frame.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" +#include "iupwin_draw.h" +#include "iupwin_info.h" + + +void iupdrvFrameGetDecorOffset(Ihandle* ih, int *x, int *y) +{ + if (iupwin_comctl32ver6) + { + *x = 3; + *y = 3; + } + else + { + *x = 2; + *y = 2; + } + + if (iupAttribGet(ih, "_IUPFRAME_HAS_TITLE") || iupAttribGet(ih, "TITLE")) + { + (*y) += iupFrameGetTitleHeight(ih); + } +} + +static void winFrameDrawText(HDC hDC, const char* text, int x, int y, COLORREF fgcolor) +{ + COLORREF oldcolor; + + SetTextAlign(hDC, TA_TOP|TA_LEFT); + SetBkMode(hDC, TRANSPARENT); + oldcolor = SetTextColor(hDC, fgcolor); + + TextOut(hDC, x, y, text, strlen(text)); + + SetTextColor(hDC, oldcolor); + SetBkMode(hDC, OPAQUE); +} + +static void winFrameDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem) +{ + iupwinBitmapDC bmpDC; + HDC hDC = iupwinDrawCreateBitmapDC(&bmpDC, drawitem->hDC, drawitem->rcItem.right-drawitem->rcItem.left, + drawitem->rcItem.bottom-drawitem->rcItem.top); + + iupwinDrawParentBackground(ih, hDC, &drawitem->rcItem); + + if (iupAttribGet(ih, "_IUPFRAME_HAS_TITLE")) + { + int x, y; + HFONT hOldFont, hFont = (HFONT)iupwinGetHFontAttrib(ih); + int txt_height = iupFrameGetTitleHeight(ih); + COLORREF fgcolor; + SIZE size; + + char* title = iupdrvBaseGetTitleAttrib(ih); + if (!title) title = ""; + + x = drawitem->rcItem.left+7; + y = drawitem->rcItem.top; + + hOldFont = SelectObject(hDC, hFont); + GetTextExtentPoint32(hDC, title, strlen(title), &size); + ExcludeClipRect(hDC, x-2, y, x+size.cx+2, y+size.cy); + + drawitem->rcItem.top += txt_height/2; + if (iupwin_comctl32ver6) + iupwinDrawThemeFrameBorder(ih->handle, hDC, &drawitem->rcItem, drawitem->itemState); + else + DrawEdge(hDC, &drawitem->rcItem, EDGE_ETCHED, BF_RECT); + + SelectClipRgn(hDC, NULL); + + if (drawitem->itemState & ODS_DISABLED) + fgcolor = GetSysColor(COLOR_GRAYTEXT); + else + { + unsigned char r, g, b; + char* color = iupAttribGetInherit(ih, "FGCOLOR"); + if (!color) + { + if (!iupwinDrawGetThemeFrameFgColor(ih->handle, &fgcolor)) + fgcolor = 0; /* black */ + } + else + { + if (iupStrToRGB(color, &r, &g, &b)) + fgcolor = RGB(r,g,b); + else + fgcolor = 0; /* black */ + } + } + + winFrameDrawText(hDC, title, x, y, fgcolor); + + SelectObject(hDC, hOldFont); + } + else + { + char* value = iupAttribGetStr(ih, "SUNKEN"); + if (iupStrBoolean(value)) + DrawEdge(hDC, &drawitem->rcItem, EDGE_SUNKEN, BF_RECT); + else + DrawEdge(hDC, &drawitem->rcItem, EDGE_ETCHED, BF_RECT); + } + + iupwinDrawDestroyBitmapDC(&bmpDC); +} + +static int winFrameProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + switch (msg) + { + case WM_GETDLGCODE: + { + *result = DLGC_STATIC; /* same return as GROUPBOX */ + return 1; + } + case WM_NCHITTEST: + { + *result = HTTRANSPARENT; /* same return as GROUPBOX */ + return 1; + } + case WM_ERASEBKGND: + { + /* just to ignore the internal processing */ + *result = 1; + return 1; + } + } + + return iupwinBaseContainerProc(ih, msg, wp, lp, result); +} + +static int winFrameMapMethod(Ihandle* ih) +{ + char *title; + DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS| + BS_OWNERDRAW, /* owner draw necessary because BS_GROUPBOX does not work ok */ + dwExStyle = 0; + + if (!ih->parent) + return IUP_ERROR; + + title = iupAttribGet(ih, "TITLE"); + if (title) + iupAttribSetStr(ih, "_IUPFRAME_HAS_TITLE", "1"); + + if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED")) + dwExStyle |= WS_EX_COMPOSITED; + else + dwStyle |= WS_CLIPCHILDREN; + + if (!iupwinCreateWindowEx(ih, "BUTTON", dwExStyle, dwStyle)) + return IUP_ERROR; + + /* replace the WinProc to handle other messages */ + IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winFrameProc); + + /* Process WM_DRAWITEM */ + IupSetCallback(ih, "_IUPWIN_DRAWITEM_CB", (Icallback)winFrameDrawItem); + + return IUP_NOERROR; +} + +void iupdrvFrameInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = winFrameMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", iupBaseNativeParentGetBgColorAttrib, NULL, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, iupdrvBaseSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +} diff --git a/iup/src/win/iupwin_globalattrib.c b/iup/src/win/iupwin_globalattrib.c new file mode 100755 index 0000000..a176925 --- /dev/null +++ b/iup/src/win/iupwin_globalattrib.c @@ -0,0 +1,243 @@ +/** \file + * \brief Windows Driver iupdrvSetGlobal + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <string.h> +#include <windows.h> + +#include "iup.h" + +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvinfo.h" +#include "iup_strmessage.h" + +#include "iupwin_drv.h" + +static int win_monitor_index = 0; + +/* Not defined in compilers older than VC9 */ +#ifndef MAPVK_VK_TO_VSC +#define MAPVK_VK_TO_VSC (0) +#endif + +static void winGlobalSendKey(int key, int press) +{ + unsigned int keyval, state; + INPUT input[2]; + LPARAM extra_info; + WORD state_scan = 0, key_scan; + ZeroMemory(input, 2*sizeof(INPUT)); + + iupwinKeyEncode(key, &keyval, &state); + if (!keyval) + return; + + extra_info = GetMessageExtraInfo(); + if (state) + state_scan = (WORD)MapVirtualKey(state, MAPVK_VK_TO_VSC); + key_scan = (WORD)MapVirtualKey(keyval, MAPVK_VK_TO_VSC); + + if (press & 0x01) + { + if (state) + { + /* modifier first */ + input[0].type = INPUT_KEYBOARD; + input[0].ki.wVk = (WORD)state; + input[0].ki.wScan = state_scan; + input[0].ki.dwExtraInfo = extra_info; + + /* key second */ + input[1].type = INPUT_KEYBOARD; + input[1].ki.wVk = (WORD)keyval; + input[1].ki.wScan = key_scan; + input[1].ki.dwExtraInfo = extra_info; + + SendInput(2, input, sizeof(INPUT)); + } + else + { + input[0].type = INPUT_KEYBOARD; + input[0].ki.wVk = (WORD)keyval; + input[0].ki.wScan = key_scan; + input[0].ki.dwExtraInfo = extra_info; + + SendInput(1, input, sizeof(INPUT)); + } + } + + if (press & 0x02) + { + if (state) + { + /* key first */ + input[0].type = INPUT_KEYBOARD; + input[0].ki.dwFlags = KEYEVENTF_KEYUP; + input[0].ki.wVk = (WORD)keyval; + input[0].ki.wScan = key_scan; + input[0].ki.dwExtraInfo = extra_info; + + /* modifier second */ + input[1].type = INPUT_KEYBOARD; + input[1].ki.dwFlags = KEYEVENTF_KEYUP; + input[1].ki.wVk = (WORD)state; + input[1].ki.wScan = state_scan; + input[1].ki.dwExtraInfo = extra_info; + + SendInput(2, input, sizeof(INPUT)); + } + else + { + input[0].type = INPUT_KEYBOARD; + input[0].ki.dwFlags = KEYEVENTF_KEYUP; + input[0].ki.wVk = (WORD)keyval; + input[0].ki.wScan = key_scan; + input[0].ki.dwExtraInfo = extra_info; + + SendInput(1, input, sizeof(INPUT)); + } + } +} + +static BOOL CALLBACK winMonitorInfoEnum(HMONITOR handle, HDC handle_dc, LPRECT rect, LPARAM data) +{ + RECT* monitors_rect = (RECT*)data; + monitors_rect[win_monitor_index] = *rect; + win_monitor_index++; + (void)handle_dc; + (void)handle; + return TRUE; +} + +int iupdrvSetGlobal(const char *name, const char *value) +{ + if (iupStrEqual(name, "LANGUAGE")) + { + iupStrMessageUpdateLanguage(value); + return 1; + } + if (iupStrEqual(name, "CURSORPOS")) + { + int x, y; + if (iupStrToIntInt(value, &x, &y, 'x') == 2) + SetCursorPos(x, y); + return 0; + } + if (iupStrEqual(name, "KEYPRESS")) + { + int key; + if (iupStrToInt(value, &key)) + winGlobalSendKey(key, 0x01); + return 0; + } + if (iupStrEqual(name, "KEYRELEASE")) + { + int key; + if (iupStrToInt(value, &key)) + winGlobalSendKey(key, 0x02); + return 0; + } + if (iupStrEqual(name, "KEY")) + { + int key; + if (iupStrToInt(value, &key)) + winGlobalSendKey(key, 0x03); + return 0; + } + return 1; +} + +char *iupdrvGetGlobal(const char *name) +{ + if (iupStrEqual(name, "CURSORPOS")) + { + int x, y; + char* str = iupStrGetMemory(50); + iupdrvGetCursorPos(&x, &y); + sprintf(str, "%dx%d", x, y); + return str; + } + if (iupStrEqual(name, "SHIFTKEY")) + { + char key[5]; + iupdrvGetKeyState(key); + if (key[0] == 'S') + return "ON"; + return "OFF"; + } + if (iupStrEqual(name, "CONTROLKEY")) + { + char key[5]; + iupdrvGetKeyState(key); + if (key[1] == 'C') + return "ON"; + return "OFF"; + } + if (iupStrEqual(name, "MODKEYSTATE")) + { + char *str = iupStrGetMemory(5); + iupdrvGetKeyState(str); + return str; + } + if (iupStrEqual(name, "SCREENSIZE")) + { + char *str = iupStrGetMemory(50); + int w, h; + iupdrvGetScreenSize(&w, &h); + sprintf(str, "%dx%d", w, h); + return str; + } + if (iupStrEqual(name, "FULLSIZE")) + { + char *str = iupStrGetMemory(50); + int w, h; + iupdrvGetFullSize(&w, &h); + sprintf(str, "%dx%d", w, h); + return str; + } + if (iupStrEqual(name, "SCREENDEPTH")) + { + char *str = iupStrGetMemory(50); + int bpp = iupdrvGetScreenDepth(); + sprintf(str, "%d", bpp); + return str; + } + if (iupStrEqual(name, "VIRTUALSCREEN")) + { + char *str = iupStrGetMemory(50); + int x = GetSystemMetrics(SM_XVIRTUALSCREEN); + int y = GetSystemMetrics(SM_YVIRTUALSCREEN); + int w = GetSystemMetrics(SM_CXVIRTUALSCREEN); + int h = GetSystemMetrics(SM_CYVIRTUALSCREEN); + sprintf(str, "%d %d %d %d", x, y, w, h); + return str; + } + if (iupStrEqual(name, "MONITORSINFO")) + { + int i; + int monitors_count = GetSystemMetrics(SM_CMONITORS); + RECT* monitors_rect = malloc(monitors_count*sizeof(RECT)); + char *str = iupStrGetMemory(monitors_count*50); + char* pstr = str; + + win_monitor_index = 0; + EnumDisplayMonitors(NULL, NULL, winMonitorInfoEnum, (LPARAM)monitors_rect); + + for (i=0; i < monitors_count; i++) + pstr += sprintf(pstr, "%d %d %d %d\n", (int)monitors_rect[i].left, (int)monitors_rect[i].top, (int)(monitors_rect[i].right-monitors_rect[i].left), (int)(monitors_rect[i].bottom-monitors_rect[i].top)); + + free(monitors_rect); + return str; + } + if (iupStrEqual(name, "TRUECOLORCANVAS")) + { + if (iupdrvGetScreenDepth() > 8) + return "YES"; + return "NO"; + } + return NULL; +} diff --git a/iup/src/win/iupwin_handle.c b/iup/src/win/iupwin_handle.c new file mode 100755 index 0000000..d5a7f77 --- /dev/null +++ b/iup/src/win/iupwin_handle.c @@ -0,0 +1,56 @@ +/** \file + * \brief HWND to ihandle table + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_table.h" + +#include "iupwin_handle.h" + + +static Itable* winhandle_table; /* table indexed by HWND containing Ihandle* address */ + +Ihandle* iupwinHandleGet(void* handle) +{ + Ihandle* ih; + if (!handle) + return NULL; + ih = (Ihandle*)iupTableGet(winhandle_table, (char*)handle); + if (ih && !iupObjectCheck(ih)) + return NULL; + return ih; +} + +void iupwinHandleSet(Ihandle *ih) +{ + iupTableSet(winhandle_table, (char*)ih->handle, ih, IUPTABLE_POINTER); +} + +void iupwinHandleAdd(Ihandle *ih, InativeHandle* hWnd) +{ + iupTableSet(winhandle_table, (char*)hWnd, ih, IUPTABLE_POINTER); +} + +void iupwinHandleRemove(Ihandle *ih) +{ + iupTableRemove(winhandle_table, (char*)ih->handle); +} + +void iupwinHandleInit(void) +{ + winhandle_table = iupTableCreate(IUPTABLE_POINTERINDEXED); +} + +void iupwinHandleFinish(void) +{ + iupTableDestroy(winhandle_table); + winhandle_table = NULL; +} diff --git a/iup/src/win/iupwin_handle.h b/iup/src/win/iupwin_handle.h new file mode 100755 index 0000000..4a8643d --- /dev/null +++ b/iup/src/win/iupwin_handle.h @@ -0,0 +1,28 @@ +/** \file + * \brief HWND to ihandle table + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPWIN_HANDLE_H +#define __IUPWIN_HANDLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Returns the IUP handle given the Windows handle. */ + +Ihandle* iupwinHandleGet(void* handle); +void iupwinHandleSet(Ihandle *ih); +void iupwinHandleAdd(Ihandle *ih, InativeHandle* hWnd); +void iupwinHandleRemove(Ihandle *ih); +void iupwinHandleInit(void); +void iupwinHandleFinish(void); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/win/iupwin_image.c b/iup/src/win/iupwin_image.c new file mode 100755 index 0000000..2db9800 --- /dev/null +++ b/iup/src/win/iupwin_image.c @@ -0,0 +1,668 @@ +/** \file + * \brief Image Resource. + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> + +#include <stdio.h> +#include <stdlib.h> +#include <memory.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_image.h" + +#include "iupwin_drv.h" + +/* RGB in RGBA DIBs are pre-multiplied by alpha to AlphaBlend usage. */ +#define iupALPHAPRE(_src, _alpha) (((_src)*(_alpha))/255) + +static int winDibNumColors(BITMAPINFOHEADER* bmih) +{ + if (bmih->biBitCount > 8) + { + if (bmih->biCompression == BI_BITFIELDS) + return 3; + else + return 0; + } + else + { + if (bmih->biClrUsed != 0) + return bmih->biClrUsed; + else + return 1 << bmih->biBitCount; + } +} + +void iupdrvImageGetRawData(void* handle, unsigned char* imgdata) +{ + int x, y, w, h, bpp, bmp_line_size, bits_size; + BYTE* bits; + HANDLE hHandle = (HANDLE)handle; + void* dib = GlobalLock(hHandle); + BITMAPINFOHEADER* bmih = (BITMAPINFOHEADER*)dib; + + w = bmih->biWidth; + h = abs(bmih->biHeight); + bpp = iupImageNormBpp(bmih->biBitCount); + bmp_line_size = ((w * bmih->biBitCount + 31) / 32) * 4; /* DWORD aligned, 4 bytes boundary in a N bpp image */ + bits_size = bmp_line_size*h; + + bits = ((BYTE*)dib) + sizeof(BITMAPINFOHEADER) + winDibNumColors(bmih)*sizeof(RGBQUAD); + + /* windows bitmaps are bottom up */ + /* imgdata is bottom up */ + + if (bmih->biHeight < 0) + bits = bits + (bits_size - bmp_line_size); /* start of last line */ + + if (bpp == 8) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + switch (bmih->biBitCount) + { + case 1: + *imgdata++ = (unsigned char)((bits[x / 8] >> (7 - x % 8)) & 0x01); + break; + case 4: + *imgdata++ = (unsigned char)((bits[x / 2] >> ((1 - x % 2) * 4)) & 0x0F); + break; + case 8: + *imgdata++ = bits[x]; + break; + } + } + + if (bmih->biHeight < 0) + bits -= bmp_line_size; + else + bits += bmp_line_size; + } + } + else + { + int offset, planesize; + unsigned short color; + unsigned int rmask = 0, gmask = 0, bmask = 0, + roff = 0, goff = 0, boff = 0; /* pixel bit mask control when reading 16 and 32 bpp images */ + unsigned char *red, *green, *blue, *alpha; + + planesize = w*h; + red = imgdata; + green = imgdata+planesize; + blue = imgdata+2*planesize; + alpha = imgdata+3*planesize; + + if (bmih->biBitCount == 16) + offset = bmp_line_size; /* do not increment for each pixel, jump line */ + else + offset = bmp_line_size - (w*bmih->biBitCount)/8; /* increment for each pixel, jump pad */ + + if (bmih->biCompression == BI_BITFIELDS) + { + unsigned int Mask; + unsigned int* palette = (unsigned int*)(((BYTE*)bmih) + sizeof(BITMAPINFOHEADER)); + + rmask = Mask = palette[0]; + while (!(Mask & 0x01)) + {Mask >>= 1; roff++;} + + gmask = Mask = palette[1]; + while (!(Mask & 0x01)) + {Mask >>= 1; goff++;} + + bmask = Mask = palette[2]; + while (!(Mask & 0x01)) + {Mask >>= 1; boff++;} + } + else if (bmih->biBitCount == 16) + { + bmask = 0x001F; + gmask = 0x03E0; + rmask = 0x7C00; + boff = 0; + goff = 5; + roff = 10; + } + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + if (bmih->biBitCount == 16) + { + color = ((unsigned short*)bits)[x]; + *red++ = (unsigned char)((((rmask & color) >> roff) * 255) / (rmask >> roff)); + *green++ = (unsigned char)((((gmask & color) >> goff) * 255) / (gmask >> goff)); + *blue++ = (unsigned char)((((bmask & color) >> boff) * 255) / (bmask >> boff)); + } + else + { + *blue++ = *bits++; + *green++ = *bits++; + *red++ = *bits++; + + if (bmih->biBitCount == 32) + { + if (alpha) + *alpha++ = *bits++; + else + bits++; + } + } + } + + bits += offset; + + if (bmih->biHeight < 0) + bits -= 2*bmp_line_size; + } + } + + GlobalUnlock(hHandle); +} + +void* iupdrvImageCreateImageRaw(int width, int height, int bpp, iupColor* colors, int colors_count, unsigned char *imgdata) +{ + int y,x,bmp_line_size,channels,bits_size,header_size; + HANDLE hHandle; + BYTE* bits; /* DIB bitmap bits, created in CreateDIBSection and filled here */ + void* dib; + BITMAPINFOHEADER* bmih; + + bmp_line_size = ((width * bpp + 31) / 32) * 4; /* DWORD aligned, 4 bytes boundary in a N bpp image */ + bits_size = bmp_line_size*height; + header_size = sizeof(BITMAPINFOHEADER) + colors_count*sizeof(RGBQUAD); + + hHandle = GlobalAlloc(GMEM_MOVEABLE, header_size+bits_size); + if (!hHandle) + return NULL; + + dib = GlobalLock(hHandle); + bits = ((BYTE*)dib) + header_size; + + bmih = (BITMAPINFOHEADER*)dib; + + memset(bmih, 0, sizeof(BITMAPINFOHEADER)); + bmih->biSize = sizeof(BITMAPINFOHEADER); + bmih->biWidth = width; + bmih->biHeight = height; + bmih->biPlanes = 1; /* not the same as PLANES */ + bmih->biBitCount = (WORD)bpp; + bmih->biCompression = BI_RGB; + bmih->biClrUsed = colors_count; + + if (colors_count) + { + RGBQUAD* bitmap_colors = (RGBQUAD*)(((BYTE*)dib) + sizeof(BITMAPINFOHEADER)); + int i; + for (i=0;i<colors_count;i++) + { + bitmap_colors[i].rgbRed = colors[i].r; + bitmap_colors[i].rgbGreen = colors[i].g; + bitmap_colors[i].rgbBlue = colors[i].b; + bitmap_colors[i].rgbReserved = 0; + } + } + + channels = 1; + if (bpp == 24) + channels = 3; + else if (bpp == 32) + channels = 4; + + /* windows bitmaps are bottom up */ + /* imgdata is bottom up */ + + if (bpp != 8) /* (bpp == 32 || bpp == 24) */ + { + unsigned char *r, *g, *b, *a; + + int planesize = width*height; + r = imgdata; + g = imgdata+planesize; + b = imgdata+2*planesize; + a = imgdata+3*planesize; + + for (y=0; y<height; y++) + { + int lineoffset = y*width; + for (x=0; x<width; x++) + { + int offset = channels*x; + /* Windows Bitmap order is BGRA */ + BYTE *bmp_b = &bits[offset], + *bmp_g = bmp_b+1, + *bmp_r = bmp_g+1, + *bmp_a = bmp_r+1; + + *bmp_r = r[lineoffset+x]; + *bmp_g = g[lineoffset+x]; + *bmp_b = b[lineoffset+x]; + + if (channels == 4) /* bpp==32 */ + { + *bmp_a = a[lineoffset+x]; + + /* RGB in RGBA DIBs are pre-multiplied by alpha to AlphaBlend usage. */ + *bmp_r = iupALPHAPRE(*bmp_r,*bmp_a); + *bmp_g = iupALPHAPRE(*bmp_g,*bmp_a); + *bmp_b = iupALPHAPRE(*bmp_b,*bmp_a); + } + } + + bits += bmp_line_size; + } + } + else + { + for (y=0; y<height; y++) + { + int lineoffset = y*width; + for (x=0; x<width; x++) + { + bits[x] = imgdata[lineoffset+x]; + } + + bits += bmp_line_size; + } + } + + GlobalUnlock(hHandle); + return hHandle; +} + +int iupdrvImageGetRawInfo(void* handle, int *w, int *h, int *bpp, iupColor* colors, int *colors_count) +{ + HANDLE hHandle = (HANDLE)handle; + void* dib = GlobalLock(hHandle); + BITMAPINFOHEADER* bmih = (BITMAPINFOHEADER*)dib; + + if (w) *w = bmih->biWidth; + if (h) *h = abs(bmih->biHeight); + if (bpp) *bpp = iupImageNormBpp(bmih->biBitCount); + + if (bmih->biBitCount <= 8) + { + RGBQUAD* bitmap_colors = (RGBQUAD*)(((BYTE*)bmih) + sizeof(BITMAPINFOHEADER)); + int i; + + if (bmih->biClrUsed != 0) + *colors_count = bmih->biClrUsed; + else + *colors_count = 1 << bmih->biBitCount; + + for (i=0;i<*colors_count;i++) + { + colors[i].r = bitmap_colors[i].rgbRed; + colors[i].g = bitmap_colors[i].rgbGreen; + colors[i].b = bitmap_colors[i].rgbBlue; + } + } + + GlobalUnlock(hHandle); + return 1; +} + +static int winImageInitDibColors(iupColor* colors, RGBQUAD* bmpcolors, int colors_count, + unsigned char bg_r, unsigned char bg_g, unsigned char bg_b, int make_inactive) +{ + int i, ret = 0; + for (i=0;i<colors_count;i++) + { + bmpcolors[i].rgbRed = colors[i].r; + bmpcolors[i].rgbGreen = colors[i].g; + bmpcolors[i].rgbBlue = colors[i].b; + bmpcolors[i].rgbReserved = colors[i].a; + + if (bmpcolors[i].rgbReserved == 0) /* full transparent alpha */ + { + bmpcolors[i].rgbBlue = bg_b; + bmpcolors[i].rgbGreen = bg_g; + bmpcolors[i].rgbRed = bg_r; + ret = 1; + } + else + bmpcolors[i].rgbReserved = 0; /* clear non transparent mark */ + + if (make_inactive) + iupImageColorMakeInactive(&(bmpcolors[i].rgbRed), &(bmpcolors[i].rgbGreen), &(bmpcolors[i].rgbBlue), + bg_r, bg_g, bg_b); + } + + return ret; +} + +static HBITMAP winImageCreateBitmap(Ihandle *ih, int width, int height, int bpp, BYTE** bits, + unsigned char bg_r, unsigned char bg_g, unsigned char bg_b, int make_inactive) +{ + HDC hDC; + int colors_count; + HBITMAP hBitmap; + BITMAPINFOHEADER* bmih; /* bitmap info header */ + iupColor colors[256]; + + if (bpp == 32 || bpp == 24) + colors_count = 0; + else /* bpp == 8 */ + iupImageInitColorTable(ih, colors, &colors_count); + + bmih = malloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*colors_count); + if (!bmih) + return NULL; + + memset(bmih, 0, sizeof(BITMAPINFOHEADER)); + bmih->biSize = sizeof(BITMAPINFOHEADER); + bmih->biWidth = width; + bmih->biHeight = height; + bmih->biPlanes = 1; /* not the same as PLANES */ + bmih->biBitCount = (WORD)bpp; + bmih->biCompression = BI_RGB; + bmih->biClrUsed = colors_count; + + if (colors_count) + { + /* since colors are only passed to the CreateDIBSection here, must update BGCOLOR and inactive here */ + RGBQUAD* bitmap_colors = (RGBQUAD*)(((BYTE*)bmih) + sizeof(BITMAPINFOHEADER)); + if (winImageInitDibColors(colors, bitmap_colors, colors_count, bg_r, bg_g, bg_b, make_inactive)) + iupAttribSetStr(ih, "_IUP_BGCOLOR_DEPEND", "1"); + } + + hDC = GetDC(NULL); + hBitmap = CreateDIBSection(hDC, (BITMAPINFO*)bmih, DIB_RGB_COLORS, (void**)bits, NULL, 0x0); + ReleaseDC(NULL, hDC); + free(bmih); + + return hBitmap; +} + +void* iupdrvImageCreateImage(Ihandle *ih, const char* bgcolor, int make_inactive) +{ + unsigned char bg_r = 0, bg_g = 0, bg_b = 0; + int y,x,bmp_line_size,data_line_size, + width = ih->currentwidth, + height = ih->currentheight, + channels = iupAttribGetInt(ih, "CHANNELS"), + flat_alpha = iupAttribGetBoolean(ih, "FLAT_ALPHA"), + bpp = iupAttribGetInt(ih, "BPP"); + unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID"); + HBITMAP hBitmap; + BYTE* bits; /* DIB bitmap bits, created in CreateDIBSection and filled here */ + + iupStrToRGB(bgcolor, &bg_r, &bg_g, &bg_b); + + hBitmap = winImageCreateBitmap(ih, width, height, bpp, &bits, bg_r, bg_g, bg_b, make_inactive); + if (!hBitmap) + return NULL; + + bmp_line_size = ((width * bpp + 31) / 32) * 4; /* DWORD aligned, 4 bytes boundary in a N bpp image */ + data_line_size = width*channels; + + /* windows bitmaps are bottom up */ + imgdata += (height-1)*data_line_size; /* iupimage is top down */ + + for (y=0; y<height; y++) + { + for (x=0; x<width; x++) + { + if (bpp != 8) /* (bpp == 32 || bpp == 24) */ + { + int offset = channels*x; + /* Windows Bitmap order is BGRA */ + BYTE *b = &bits[offset], + *g = b+1, + *r = g+1, + *a = r+1, + *dat = &imgdata[offset]; + + *r = *(dat); + *g = *(dat+1); + *b = *(dat+2); + + if (channels == 4) /* bpp==32 */ + { + if (flat_alpha) + { + *a = *(dat+3); + *r = iupALPHABLEND(*r, bg_r, *a); + *g = iupALPHABLEND(*g, bg_g, *a); + *b = iupALPHABLEND(*b, bg_b, *a); + *a = 255; + } + + if (make_inactive) + iupImageColorMakeInactive(r, g, b, bg_r, bg_g, bg_b); + + if (!flat_alpha) + { + *a = *(dat+3); + + /* RGB in RGBA DIBs are pre-multiplied by alpha to AlphaBlend usage. */ + *r = iupALPHAPRE(*r,*a); + *g = iupALPHAPRE(*g,*a); + *b = iupALPHAPRE(*b,*a); + } + } + } + else /* bpp == 8 */ + { + bits[x] = imgdata[x]; + } + } + + bits += bmp_line_size; + imgdata -= data_line_size; /* iupimage is top down */ + } + + if (make_inactive || (channels == 4 && flat_alpha)) + iupAttribSetStr(ih, "_IUP_BGCOLOR_DEPEND", "1"); + + return hBitmap; +} + +static HBITMAP winImageCreateBitmask(Ihandle *ih, int invert) +{ + int y, x, mask_line_size,data_line_size, colors_count, set, + width = ih->currentwidth, + height = ih->currentheight, + channels = iupAttribGetInt(ih, "CHANNELS"), + bpp = iupAttribGetInt(ih, "BPP"); + unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID"); + HBITMAP hBitmap; + BYTE* bitmask, *bitmask_ptr; + iupColor colors[256]; + + if (bpp == 8) + iupImageInitColorTable(ih, colors, &colors_count); + + mask_line_size = ((width + 15) / 16) * 2; /* WORD aligned, 2 bytes boundary in a 1 bpp image */ + data_line_size = width*channels; + + bitmask = malloc(height * mask_line_size); + memset(bitmask, 0, height * mask_line_size); /* opaque */ + + /* mask and iupimage are top down */ + + bitmask_ptr = bitmask; + for (y=0; y<height; y++) + { + for (x=0; x<width; x++) + { + set = 0; + + if (bpp == 32) + { + BYTE* dat = &imgdata[channels*x]; + if (*(dat+3) == 0) /* full transparent alpha */ + set = 1; + } + else if (bpp == 8) + { + unsigned char index = imgdata[x]; + if (colors[index].a == 0) /* full transparent alpha */ + set = 1; + } + + if (set) + bitmask_ptr[x/8] |= 1 << (7 - (x % 8)); /* set transparent mask bit */ + } + + bitmask_ptr += mask_line_size; + imgdata += data_line_size; + } + + if (invert) + { + int k, size = height * mask_line_size; + for (k = 0; k < size; k++) + bitmask[k] = ~bitmask[k]; + } + + hBitmap = CreateBitmap(width, height, 1, 1, bitmask); + free(bitmask); + return hBitmap; +} + +static HICON winImageCreateIcon(Ihandle *ih, int is_cursor) +{ + HBITMAP hBitmap, hBitmapMask; + ICONINFO iconinfo; + HICON icon; + char* color0 = NULL; + + /* If cursor and no transparency defined, assume 0 if transparent. + We do this only in Windows and because of backward compatibility. */ + if (is_cursor) + { + int bpp = iupAttribGetInt(ih, "BPP"); + if (bpp == 8) + { + if (!iupStrEqual(iupAttribGet(ih, "0"), "BGCOLOR") && + !iupStrEqual(iupAttribGet(ih, "1"), "BGCOLOR") && + !iupStrEqual(iupAttribGet(ih, "2"), "BGCOLOR")) + { + color0 = iupStrDup(iupAttribGet(ih, "0")); + iupAttribSetStr(ih, "0", "BGCOLOR"); + } + } + } + + hBitmap = iupdrvImageCreateImage(ih, NULL, 0); + if (!hBitmap) + { + if (color0) free(color0); + return NULL; + } + + /* Transparency mask */ + hBitmapMask = winImageCreateBitmask(ih, 0); + if (!hBitmapMask) + { + DeleteObject(hBitmap); + if (color0) free(color0); + return NULL; + } + + /* destination = (destination AND bitmask) XOR bitmap */ + iconinfo.hbmMask = hBitmapMask; /* AND */ + iconinfo.hbmColor = hBitmap; /* XOR */ + + if (is_cursor) + { + int x=0,y=0; + iupStrToIntInt(iupAttribGet(ih, "HOTSPOT"), &x, &y, ':'); + + iconinfo.xHotspot = x; + iconinfo.yHotspot = y; + iconinfo.fIcon = FALSE; + } + else + iconinfo.fIcon = TRUE; + + icon = CreateIconIndirect(&iconinfo); + + DeleteObject(hBitmap); + DeleteObject(hBitmapMask); + + if (color0) + { + iupAttribStoreStr(ih, "0", color0); + free(color0); + } + + return icon; +} + +void* iupdrvImageCreateIcon(Ihandle *ih) +{ + return winImageCreateIcon(ih, 0); +} + +void* iupdrvImageCreateCursor(Ihandle *ih) +{ + return winImageCreateIcon(ih, 1); +} + +void* iupdrvImageCreateMask(Ihandle *ih) +{ + int invert = 1; + if (!ih) return NULL; + if (iupAttribGet(ih, "_IUPIMG_NO_INVERT")) invert = 0; + return (void*)winImageCreateBitmask(ih, invert); +} + +void* iupdrvImageLoad(const char* name, int type) +{ + int iup2win[3] = {IMAGE_BITMAP, IMAGE_ICON, IMAGE_CURSOR}; + HANDLE hImage = LoadImage(iupwin_hinstance, (LPCTSTR)name, iup2win[type], 0, 0, type==0?LR_CREATEDIBSECTION:0); + if (!hImage && iupwin_dll_hinstance) + hImage = LoadImage(iupwin_dll_hinstance, (LPCTSTR)name, iup2win[type], 0, 0, type==0?LR_CREATEDIBSECTION:0); + if (!hImage) + hImage = LoadImage(NULL, (LPCTSTR)name, iup2win[type], 0, 0, LR_LOADFROMFILE|(type==0?LR_CREATEDIBSECTION:0)); + return hImage; +} + +int iupdrvImageGetInfo(void* handle, int *w, int *h, int *bpp) +{ + BITMAP bm; + if (!GetObject((HBITMAP)handle, sizeof(BITMAP), (LPSTR)&bm)) + { + if (w) *w = 0; + if (h) *h = 0; + if (bpp) *bpp = 0; + return 0; + } + if (w) *w = bm.bmWidth; + if (h) *h = abs(bm.bmHeight); + if (bpp) *bpp = iupImageNormBpp(bm.bmBitsPixel*bm.bmPlanes); + return 1; +} + +void iupdrvImageDestroy(void* handle, int type) +{ + switch (type) + { + case IUPIMAGE_IMAGE: + if (GetObjectType((HBITMAP)handle)==OBJ_BITMAP) + DeleteObject((HBITMAP)handle); + else + GlobalFree((HANDLE)handle); + break; + case IUPIMAGE_ICON: + DestroyIcon((HICON)handle); + break; + case IUPIMAGE_CURSOR: + DestroyCursor((HCURSOR)handle); + break; + } +} + diff --git a/iup/src/win/iupwin_info.c b/iup/src/win/iupwin_info.c new file mode 100755 index 0000000..8ea7dd4 --- /dev/null +++ b/iup/src/win/iupwin_info.c @@ -0,0 +1,277 @@ +/** \file + * \brief Windows System Information + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <windows.h> +#include <uxtheme.h> + +#include "iup.h" + +#include "iup_str.h" +#include "iup_drv.h" + +#include "iupwin_info.h" + + +int iupwinIsVista(void) +{ + OSVERSIONINFO osvi; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + + if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion >= 6) + return 1; + + return 0; +} + +int iupwinGetSystemMajorVersion(void) +{ + OSVERSIONINFO osvi; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + return osvi.dwMajorVersion; +} + +char *iupwinGetSystemLanguage(void) +{ + LANGID id = GetSystemDefaultUILanguage(); + char *lang = NULL; + switch(id) + { + case 0x0000: lang = "Language Neutral"; break; + case 0x007f: lang = "Locale Invariant"; break; + case 0x0400: lang = "User Default Language"; break; + case 0x0800: lang = "System Default Language"; break; + case 0x0436: lang = "Afrikaans"; break; + case 0x041c: lang = "Albanian"; break; + case 0x0401: lang = "Arabic (Saudi Arabia)"; break; + case 0x0801: lang = "Arabic (Iraq)"; break; + case 0x0c01: lang = "Arabic (Egypt)"; break; + case 0x1001: lang = "Arabic (Libya)"; break; + case 0x1401: lang = "Arabic (Algeria)"; break; + case 0x1801: lang = "Arabic (Morocco)"; break; + case 0x1c01: lang = "Arabic (Tunisia)"; break; + case 0x2001: lang = "Arabic (Oman)"; break; + case 0x2401: lang = "Arabic (Yemen)"; break; + case 0x2801: lang = "Arabic (Syria)"; break; + case 0x2c01: lang = "Arabic (Jordan)"; break; + case 0x3001: lang = "Arabic (Lebanon)"; break; + case 0x3401: lang = "Arabic (Kuwait)"; break; + case 0x3801: lang = "Arabic (U.A.E.)"; break; + case 0x3c01: lang = "Arabic (Bahrain)"; break; + case 0x4001: lang = "Arabic (Qatar)"; break; + case 0x042b: lang = "Armenian"; break; + case 0x042c: lang = "Azeri (Latin)"; break; + case 0x082c: lang = "Azeri (Cyrillic)"; break; + case 0x042d: lang = "Basque"; break; + case 0x0423: lang = "Belarusian"; break; + case 0x0402: lang = "Bulgarian"; break; + case 0x0455: lang = "Burmese"; break; + case 0x0403: lang = "Catalan"; break; + case 0x0404: lang = "Chinese (Taiwan)"; break; + case 0x0804: lang = "Chinese"; break; + case 0x0c04: lang = "Chinese (Hong Kong)"; break; + case 0x1004: lang = "Chinese (Singapore)"; break; + case 0x1404: lang = "Chinese (Macau)"; break; + case 0x041a: lang = "Croatian"; break; + case 0x0405: lang = "Czech"; break; + case 0x0406: lang = "Danish"; break; + case 0x0465: lang = "Divehi"; break; + case 0x0413: lang = "Dutch (Netherlands)"; break; + case 0x0813: lang = "Dutch (Belgium)"; break; + case 0x0409: lang = "English (United States)"; break; + case 0x0809: lang = "English (United Kingdom)"; break; + case 0x0c09: lang = "English (Australian)"; break; + case 0x1009: lang = "English (Canadian)"; break; + case 0x1409: lang = "English (New Zealand)"; break; + case 0x1809: lang = "English (Ireland)"; break; + case 0x1c09: lang = "English (South Africa)"; break; + case 0x2009: lang = "English (Jamaica)"; break; + case 0x2409: lang = "English (Caribbean)"; break; + case 0x2809: lang = "English (Belize)"; break; + case 0x2c09: lang = "English (Trinidad)"; break; + case 0x3009: lang = "English (Zimbabwe)"; break; + case 0x3409: lang = "English (Philippines)"; break; + case 0x0425: lang = "Estonian"; break; + case 0x0438: lang = "Faeroese"; break; + case 0x0429: lang = "Farsi"; break; + case 0x040b: lang = "Finnish"; break; + case 0x040c: lang = "French (Standard)"; break; + case 0x080c: lang = "French (Belgian)"; break; + case 0x0c0c: lang = "French (Canadian)"; break; + case 0x100c: lang = "French (Switzerland)"; break; + case 0x140c: lang = "French (Luxembourg)"; break; + case 0x180c: lang = "French (Monaco)"; break; + case 0x0456: lang = "Galician"; break; + case 0x0437: lang = "Georgian"; break; + case 0x0407: lang = "German (Standard)"; break; + case 0x0807: lang = "German (Switzerland)"; break; + case 0x0c07: lang = "German (Austria)"; break; + case 0x1007: lang = "German (Luxembourg)"; break; + case 0x1407: lang = "German (Liechtenstein)"; break; + case 0x0408: lang = "Greek"; break; + case 0x0447: lang = "Gujarati"; break; + case 0x040d: lang = "Hebrew"; break; + case 0x0439: lang = "Hindi"; break; + case 0x040e: lang = "Hungarian"; break; + case 0x040f: lang = "Icelandic"; break; + case 0x0421: lang = "Indonesian"; break; + case 0x0410: lang = "Italian (Standard)"; break; + case 0x0810: lang = "Italian (Switzerland)"; break; + case 0x0411: lang = "Japanese"; break; + case 0x044b: lang = "Kannada"; break; + case 0x0457: lang = "Konkani"; break; + case 0x0412: lang = "Korean"; break; + case 0x0812: lang = "Korean (Johab)"; break; + case 0x0440: lang = "Kyrgyz"; break; + case 0x0426: lang = "Latvian"; break; + case 0x0427: lang = "Lithuanian"; break; + case 0x0827: lang = "Lithuanian (Classic)"; break; + case 0x042f: lang = "Macedonian"; break; + case 0x043e: lang = "Malay (Malaysian)"; break; + case 0x083e: lang = "Malay (Brunei Darussalam)"; break; + case 0x044e: lang = "Marathi"; break; + case 0x0450: lang = "Mongolian"; break; + case 0x0414: lang = "Norwegian (Bokmal)"; break; + case 0x0814: lang = "Norwegian (Nynorsk)"; break; + case 0x0415: lang = "Polish"; break; + case 0x0416: lang = "Portuguese (Brazil)"; break; + case 0x0816: lang = "Portuguese (Portugal)"; break; + case 0x0446: lang = "Punjabi"; break; + case 0x0418: lang = "Romanian"; break; + case 0x0419: lang = "Russian"; break; + case 0x044f: lang = "Sanskrit"; break; + case 0x0c1a: lang = "Serbian (Cyrillic)"; break; + case 0x081a: lang = "Serbian (Latin)"; break; + case 0x041b: lang = "Slovak"; break; + case 0x0424: lang = "Slovenian"; break; + case 0x040a: lang = "Spanish (Spain, Traditional Sort)"; break; + case 0x080a: lang = "Spanish (Mexican)"; break; + case 0x0c0a: lang = "Spanish (Spain, International Sort)"; break; + case 0x100a: lang = "Spanish (Guatemala)"; break; + case 0x140a: lang = "Spanish (Costa Rica)"; break; + case 0x180a: lang = "Spanish (Panama)"; break; + case 0x1c0a: lang = "Spanish (Dominican Republic)"; break; + case 0x200a: lang = "Spanish (Venezuela)"; break; + case 0x240a: lang = "Spanish (Colombia)"; break; + case 0x280a: lang = "Spanish (Peru)"; break; + case 0x2c0a: lang = "Spanish (Argentina)"; break; + case 0x300a: lang = "Spanish (Ecuador)"; break; + case 0x340a: lang = "Spanish (Chile)"; break; + case 0x380a: lang = "Spanish (Uruguay)"; break; + case 0x3c0a: lang = "Spanish (Paraguay)"; break; + case 0x400a: lang = "Spanish (Bolivia)"; break; + case 0x440a: lang = "Spanish (El Salvador)"; break; + case 0x480a: lang = "Spanish (Honduras)"; break; + case 0x4c0a: lang = "Spanish (Nicaragua)"; break; + case 0x500a: lang = "Spanish (Puerto Rico)"; break; + case 0x0430: lang = "Sutu"; break; + case 0x0441: lang = "Swahili (Kenya)"; break; + case 0x041d: lang = "Swedish"; break; + case 0x081d: lang = "Swedish (Finland)"; break; + case 0x045a: lang = "Syriac"; break; + case 0x0449: lang = "Tamil"; break; + case 0x0444: lang = "Tatar (Tatarstan)"; break; + case 0x044a: lang = "Telugu"; break; + case 0x041e: lang = "Thai"; break; + case 0x041f: lang = "Turkish"; break; + case 0x0422: lang = "Ukrainian"; break; + case 0x0420: lang = "Urdu (Pakistan)"; break; + case 0x0820: lang = "Urdu (India)"; break; + case 0x0443: lang = "Uzbek (Latin)"; break; + case 0x0843: lang = "Uzbek (Cyrillic)"; break; + case 0x042a: lang = "Vietnamese"; break; + } + return lang; +} + +#define PACKVERSION(major,minor) MAKELONG(minor,major) +typedef struct _DLLVERSIONINFO +{ + DWORD cbSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformID; +} DLLVERSIONINFO; +typedef HRESULT (CALLBACK* DLLGETVERSIONPROC)(DLLVERSIONINFO *); + +static DWORD winGetDllVersion(LPCTSTR lpszDllName) +{ + HINSTANCE hinstDll; + DWORD dwVersion = 0; + + /* For security purposes, LoadLibrary should be provided with a + fully-qualified path to the DLL. The lpszDllName variable should be + tested to ensure that it is a fully qualified path before it is used. */ + hinstDll = LoadLibrary(lpszDllName); + + if (hinstDll) + { + DLLGETVERSIONPROC pDllGetVersion; + pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinstDll, "DllGetVersion"); + + /* Because some DLLs might not implement this function, you + must test for it explicitly. Depending on the particular + DLL, the lack of a DllGetVersion function can be a useful + indicator of the version. */ + + if (pDllGetVersion) + { + DLLVERSIONINFO dvi; + HRESULT hr; + + ZeroMemory(&dvi, sizeof(dvi)); + dvi.cbSize = sizeof(dvi); + + hr = pDllGetVersion(&dvi); + if (SUCCEEDED(hr)) + dwVersion = PACKVERSION(dvi.dwMajorVersion, dvi.dwMinorVersion); + } + + FreeLibrary(hinstDll); + } + + return dwVersion; +} + +int iupwinGetComCtl32Version(void) +{ + return winGetDllVersion(TEXT("comctl32.dll")); +} + +void iupwinGetSysColor(char* color, int wincolor) +{ + COLORREF syscolor = GetSysColor(wincolor); + sprintf(color, "%d %d %d", (int)GetRValue(syscolor), (int)GetGValue(syscolor), (int)GetBValue(syscolor)); +} + +char* iupwinGetSystemFgColor(void) +{ + static char def_fgcolor[50]; + iupwinGetSysColor(def_fgcolor, COLOR_WINDOWTEXT); + return def_fgcolor; +} + +int iupwinIsAppThemed(void) +{ + typedef BOOL (STDAPICALLTYPE *winIsAppThemed)(void); + static winIsAppThemed myIsAppThemed = NULL; + if (!myIsAppThemed) + { + HMODULE hinstDll = LoadLibrary("uxtheme.dll"); + if (hinstDll) + myIsAppThemed = (winIsAppThemed)GetProcAddress(hinstDll, "IsAppThemed"); + } + + if (myIsAppThemed) + return myIsAppThemed(); + else + return 0; +} diff --git a/iup/src/win/iupwin_info.h b/iup/src/win/iupwin_info.h new file mode 100755 index 0000000..d39bae0 --- /dev/null +++ b/iup/src/win/iupwin_info.h @@ -0,0 +1,29 @@ +/** \file + * \brief Windows System Information + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPWIN_INFO_H +#define __IUPWIN_INFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* system */ +int iupwinGetSystemMajorVersion(void); +int iupwinGetComCtl32Version(void); +char* iupwinGetSystemLanguage(void); +int iupwinIsAppThemed(void); +int iupwinIsVista(void); + +/* color */ +void iupwinGetSysColor(char* color, int wincolor); +char* iupwinGetSystemFgColor(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/win/iupwin_key.c b/iup/src/win/iupwin_key.c new file mode 100755 index 0000000..921ed94 --- /dev/null +++ b/iup/src/win/iupwin_key.c @@ -0,0 +1,348 @@ +/** \file + * \brief Windows Driver keyboard mapping + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> + +#include <windows.h> + +#include "iup.h" +#include "iupkey.h" + +#include "iup_object.h" +#include "iup_key.h" + +#include "iupwin_drv.h" + + +#ifndef VK_OEM_PLUS +#define VK_OEM_PLUS 0xBB /* '+' any country */ +#define VK_OEM_COMMA 0xBC /* ',' any country */ +#define VK_OEM_MINUS 0xBD /* '-' any country */ +#define VK_OEM_PERIOD 0xBE /* '.' any country */ +#define VK_OEM_102 0xE2 /* "<>" or "\|" on RT 102-key kbd. */ +#endif + +typedef struct _Iwin2iupkey +{ + int wincode; + int iupcode; + int s_iupcode; + int c_iupcode; + int m_iupcode; + int y_iupcode; +} Iwin2iupkey; + +static Iwin2iupkey winkey_map[] = { + +{ VK_ESCAPE, K_ESC, K_sESC, K_cESC, K_mESC, K_yESC }, +{ VK_PAUSE, K_PAUSE, K_sPAUSE, K_cPAUSE, K_mPAUSE, K_yPAUSE }, +{ VK_SNAPSHOT, K_Print, K_sPrint, K_cPrint, K_mPrint, K_yPrint }, +{ VK_APPS, K_Menu, K_sMenu, K_cMenu, K_mMenu, K_yMenu }, + +{ VK_HOME, K_HOME, K_sHOME, K_cHOME, K_mHOME, K_yHOME }, +{ VK_UP, K_UP, K_sUP, K_cUP, K_mUP, K_yUP }, +{ VK_PRIOR, K_PGUP, K_sPGUP, K_cPGUP, K_mPGUP, K_yPGUP }, +{ VK_LEFT, K_LEFT, K_sLEFT, K_cLEFT, K_mLEFT, K_yLEFT }, +{ VK_CLEAR, K_MIDDLE,K_sMIDDLE, K_cMIDDLE,K_mMIDDLE,K_yMIDDLE}, +{ VK_RIGHT, K_RIGHT, K_sRIGHT, K_cRIGHT, K_mRIGHT, K_yRIGHT }, +{ VK_END, K_END, K_sEND, K_cEND, K_mEND, K_yEND }, +{ VK_DOWN, K_DOWN, K_sDOWN, K_cDOWN, K_mDOWN, K_yDOWN }, +{ VK_NEXT, K_PGDN, K_sPGDN, K_cPGDN, K_mPGDN, K_yPGDN }, +{ VK_INSERT, K_INS, K_sINS, K_cINS, K_mINS, K_yINS }, +{ VK_DELETE, K_DEL, K_sDEL, K_cDEL, K_mDEL, K_yDEL }, +{ VK_SPACE, K_SP, K_sSP, K_cSP, K_mSP, K_ySP }, +{ VK_TAB, K_TAB, K_sTAB, K_cTAB, K_mTAB, K_yTAB }, +{ VK_RETURN, K_CR, K_sCR, K_cCR, K_mCR, K_yCR }, +{ VK_BACK, K_BS, K_sBS, K_cBS, K_mBS, K_yBS }, + +/* VK_0 - VK_9 are the same as ASCII '0' - '9' (0x30 - 0x39) */ +{ '1', K_1, K_exclam, K_c1, K_m1, K_y1 }, +{ '2', K_2, K_at, K_c2, K_m2, K_y2 }, +{ '3', K_3, K_numbersign, K_c3, K_m3, K_y3 }, +{ '4', K_4, K_dollar, K_c4, K_m4, K_y4 }, +{ '5', K_5, K_percent, K_c5, K_m5, K_y5 }, +{ '6', K_6, K_circum, K_c6, K_m6, K_y6 }, +{ '7', K_7, K_ampersand, K_c7, K_m7, K_y7 }, +{ '8', K_8, K_asterisk, K_c8, K_m8, K_y8 }, +{ '9', K_9, K_parentleft, K_c9, K_m9, K_y9 }, +{ '0', K_0, K_parentright, K_c0, K_m0, K_y0 }, + +/* VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A) */ +{ 'A', K_a, K_A, K_cA, K_mA, K_yA}, +{ 'B', K_b, K_B, K_cB, K_mB, K_yB}, +{ 'C', K_c, K_C, K_cC, K_mC, K_yC}, +{ 'D', K_d, K_D, K_cD, K_mD, K_yD}, +{ 'E', K_e, K_E, K_cE, K_mE, K_yE}, +{ 'F', K_f, K_F, K_cF, K_mF, K_yF}, +{ 'G', K_g, K_G, K_cG, K_mG, K_yG}, +{ 'H', K_h, K_H, K_cH, K_mH, K_yH}, +{ 'I', K_i, K_I, K_cI, K_mI, K_yI}, +{ 'J', K_j, K_J, K_cJ, K_mJ, K_yJ}, +{ 'K', K_k, K_K, K_cK, K_mK, K_yK}, +{ 'L', K_l, K_L, K_cL, K_mL, K_yL}, +{ 'M', K_m, K_M, K_cM, K_mM, K_yM}, +{ 'N', K_n, K_N, K_cN, K_mN, K_yN}, +{ 'O', K_o, K_O, K_cO, K_mO, K_yO}, +{ 'P', K_p, K_P, K_cP, K_mP, K_yP}, +{ 'Q', K_q, K_Q, K_cQ, K_mQ, K_yQ}, +{ 'R', K_r, K_R, K_cR, K_mR, K_yR}, +{ 'S', K_s, K_S, K_cS, K_mS, K_yS}, +{ 'T', K_t, K_T, K_cT, K_mT, K_yT}, +{ 'U', K_u, K_U, K_cU, K_mU, K_yU}, +{ 'V', K_v, K_V, K_cV, K_mV, K_yV}, +{ 'W', K_w, K_W, K_cW, K_mW, K_yW}, +{ 'X', K_x, K_X, K_cX, K_mX, K_yX}, +{ 'Y', K_y, K_Y, K_cY, K_mY, K_yY}, +{ 'Z', K_z, K_Z, K_cZ, K_mZ, K_yZ}, + +{ VK_F1, K_F1, K_sF1, K_cF1, K_mF1, K_yF1 }, +{ VK_F2, K_F2, K_sF2, K_cF2, K_mF2, K_yF2 }, +{ VK_F3, K_F3, K_sF3, K_cF3, K_mF3, K_yF3 }, +{ VK_F4, K_F4, K_sF4, K_cF4, K_mF4, K_yF4 }, +{ VK_F5, K_F5, K_sF5, K_cF5, K_mF5, K_yF5 }, +{ VK_F6, K_F6, K_sF6, K_cF6, K_mF6, K_yF6 }, +{ VK_F7, K_F7, K_sF7, K_cF7, K_mF7, K_yF7 }, +{ VK_F8, K_F8, K_sF8, K_cF8, K_mF8, K_yF8 }, +{ VK_F9, K_F9, K_sF9, K_cF9, K_mF9, K_yF9 }, +{ VK_F10, K_F10, K_sF10, K_cF10, K_mF10, K_yF10 }, +{ VK_F11, K_F11, K_sF11, K_cF11, K_mF11, K_yF11 }, +{ VK_F12, K_F12, K_sF12, K_cF12, K_mF12, K_yF12 }, + +{ VK_OEM_1, K_semicolon, K_colon, K_cSemicolon, K_mSemicolon, K_ySemicolon }, +{ VK_OEM_PLUS, K_equal, K_plus, K_cEqual, K_mEqual, K_yEqual }, +{ VK_OEM_COMMA, K_comma, K_less, K_cComma, K_mComma, K_yComma }, +{ VK_OEM_MINUS, K_minus, K_underscore, K_cMinus, K_mMinus, K_yMinus }, +{ VK_OEM_PERIOD, K_period, K_greater, K_cPeriod, K_mPeriod, K_yPeriod }, +{ VK_OEM_2, K_slash, K_question, K_cSlash, K_mSlash, K_ySlash }, +{ VK_OEM_3, K_grave, K_tilde, 0, 0, 0 }, +{ VK_OEM_4, K_bracketleft, K_braceleft, K_cBracketleft, K_mBracketleft, K_yBracketleft }, +{ VK_OEM_5, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash }, +{ VK_OEM_6, K_bracketright, K_braceright, K_cBracketright,K_mBracketright,K_yBracketright }, +{ VK_OEM_7, K_apostrophe, K_quotedbl, 0, 0, 0 }, +{ VK_OEM_102, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash }, + +{ VK_NUMPAD0, K_0, K_0, K_c0, K_m0, K_y0 }, +{ VK_NUMPAD1, K_1, K_1, K_c1, K_m1, K_y1 }, +{ VK_NUMPAD2, K_2, K_2, K_c2, K_m2, K_y2 }, +{ VK_NUMPAD3, K_3, K_3, K_c3, K_m3, K_y3 }, +{ VK_NUMPAD4, K_4, K_4, K_c4, K_m4, K_y4 }, +{ VK_NUMPAD5, K_5, K_5, K_c5, K_m5, K_y5 }, +{ VK_NUMPAD6, K_6, K_6, K_c6, K_m6, K_y6 }, +{ VK_NUMPAD7, K_7, K_7, K_c7, K_m7, K_y7 }, +{ VK_NUMPAD8, K_8, K_8, K_c8, K_m8, K_y8 }, +{ VK_NUMPAD9, K_9, K_9, K_c9, K_m9, K_y9 }, +{ VK_MULTIPLY, K_asterisk, K_sAsterisk, K_cAsterisk, K_mAsterisk, K_yAsterisk }, +{ VK_ADD, K_plus, K_sPlus, K_cPlus, K_mPlus, K_yPlus }, +{ VK_SUBTRACT, K_minus, K_sMinus, K_cMinus, K_mMinus, K_yMinus }, +{ VK_DECIMAL, K_period, K_sPeriod, K_cPeriod, K_mPeriod, K_yPeriod }, +{ VK_DIVIDE, K_slash, K_sSlash, K_cSlash, K_mSlash, K_ySlash }, +{ VK_SEPARATOR, K_comma, K_sComma, K_cComma, K_mComma, K_yComma } +}; + +static Iwin2iupkey keytable_abnt[] = { +{ '1', K_1, K_exclam, K_c1, K_m1, K_y1 }, +{ '2', K_2, K_at, K_c2, K_m2, K_y2 }, +{ '3', K_3, K_numbersign, K_c3, K_m3, K_y3 }, +{ '4', K_4, K_dollar, K_c4, K_m4, K_y4 }, +{ '5', K_5, K_percent, K_c5, K_m5, K_y5 }, +{ '6', K_6, K_circum, K_c6, K_m6, K_y6 }, + +{ VK_OEM_1, K_ccedilla, K_Ccedilla, K_cCcedilla, K_mCcedilla, K_yCcedilla }, +{ VK_OEM_2, K_semicolon, K_colon, K_cSemicolon, K_mSemicolon, K_ySemicolon }, +{ VK_OEM_3, K_apostrophe, K_quotedbl, 0, 0, 0 }, +{ VK_OEM_4, K_acute, K_grave, 0, 0, 0 }, +{ VK_OEM_5, K_bracketright, K_braceright, K_cBracketleft, K_mBracketleft, K_yBracketleft }, +{ VK_OEM_6, K_bracketleft, K_braceleft, K_cBracketright, K_mBracketright, K_yBracketright }, +{ VK_OEM_7, K_tilde, K_circum, 0, 0, 0 }, +{ VK_OEM_102, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash }, +{ VK_OEM_PLUS, K_equal, K_plus, K_cEqual, K_mEqual, K_yEqual }, +{ 0xC1, K_slash, K_question, K_cSlash, K_mSlash, K_ySlash }, +{ 0xC2, K_period, K_sPeriod, K_cPeriod, K_mPeriod, K_yPeriod }, +{ VK_SEPARATOR,K_period, K_sPeriod, K_cPeriod, K_mPeriod, K_yPeriod }, +{ VK_DECIMAL, K_comma, K_sComma, K_cComma, K_mComma, K_yComma } +}; + + +void iupwinKeyEncode(int key, unsigned int *keyval, unsigned int *state) +{ + int i, iupcode = key & 0xFF; /* 0-255 interval */ + int count = sizeof(winkey_map)/sizeof(winkey_map[0]); + for (i = 0; i < count; i++) + { + Iwin2iupkey* key_map = &(winkey_map[i]); + if (key_map->iupcode == iupcode) + { + *keyval = key_map->wincode; + *state = 0; + + if (iupcode != key) + { + if (key_map->c_iupcode == key) + *state = VK_CONTROL; + else if (key_map->m_iupcode == key) + *state = VK_MENU; + else if (key_map->y_iupcode == key) + *state = VK_LWIN; + else if (key_map->s_iupcode == key) + *state = VK_SHIFT; + } + return; + } + else if (key_map->s_iupcode == key) /* There are Shift keys bellow 256 */ + { + *keyval = key_map->wincode; + *state = VK_SHIFT; + return; + } + } +} + +static int winKeyMap2Iup(Iwin2iupkey* table, int i) +{ + int code = 0; + if (GetKeyState(VK_CONTROL) & 0x8000) + code = table[i].c_iupcode; + else if (GetKeyState(VK_MENU) & 0x8000) + code = table[i].m_iupcode; + else if ((GetKeyState(VK_LWIN) & 0x8000) || (GetKeyState(VK_RWIN) & 0x8000)) + code = table[i].y_iupcode; + else if (GetKeyState(VK_CAPITAL) & 0x01) /* if it's on */ + { + if ((GetKeyState(VK_SHIFT) & 0x8000) || !iupKeyCanCaps(table[i].iupcode)) + return table[i].iupcode; + else + code = table[i].s_iupcode; + } + else if (GetKeyState(VK_SHIFT) & 0x8000) + code = table[i].s_iupcode; + else + return table[i].iupcode; + + if (!code) + code = table[i].iupcode; + + return code; +} + +static int winKeyDecode(int wincode) +{ + HKL k; + int i, count; + + k = GetKeyboardLayout(0); + if ((int)HIWORD(k) == 0x0416) /* ABNT */ + { + int abnt_count = sizeof(keytable_abnt)/sizeof(keytable_abnt[0]); + for (i = 0; i < abnt_count; i++) + { + if (keytable_abnt[i].wincode == wincode) + return winKeyMap2Iup(keytable_abnt, i); + } + } + + count = sizeof(winkey_map)/sizeof(winkey_map[0]); + for (i = 0; i < count; i++) + { + if (winkey_map[i].wincode == wincode) + return winKeyMap2Iup(winkey_map, i); + } + + return 0; +} + +int iupwinKeyEvent(Ihandle* ih, int wincode, int press) +{ + int result, code; + + if (!ih->iclass->is_interactive) + return 1; + + code = winKeyDecode(wincode); + if (code == 0) + return 1; + + if (press) + { + result = iupKeyCallKeyCb(ih, code); + if (result == IUP_CLOSE) + { + IupExitLoop(); + return 1; + } + else if (result == IUP_IGNORE) + return 0; + + /* in the previous callback the dialog could be destroyed */ + if (iupObjectCheck(ih)) + { + /* this is called only for canvas */ + if (ih->iclass->nativetype == IUP_TYPECANVAS) + { + result = iupKeyCallKeyPressCb(ih, code, 1); + if (result == IUP_CLOSE) + { + IupExitLoop(); + return 1; + } + else if (result == IUP_IGNORE) + return 0; + } + } + + if (!iupKeyProcessNavigation(ih, code, (GetKeyState(VK_SHIFT) & 0x8000))) + return 0; + } + else + { + /* this is called only for canvas */ + if (ih->iclass->nativetype == IUP_TYPECANVAS) + { + result = iupKeyCallKeyPressCb(ih, code, 0); + if (result == IUP_CLOSE) + { + IupExitLoop(); + return 1; + } + else if (result == IUP_IGNORE) + return 0; + } + } + + return 1; +} + +void iupwinButtonKeySetStatus(WORD keys, char* status, int doubleclick) +{ + if (keys & MK_SHIFT) + iupKEYSETSHIFT(status); + + if (keys & MK_CONTROL) + iupKEYSETCONTROL(status); + + if (keys & MK_LBUTTON) + iupKEYSETBUTTON1(status); + + if (keys & MK_MBUTTON) + iupKEYSETBUTTON2(status); + + if (keys & MK_RBUTTON) + iupKEYSETBUTTON3(status); + + if (doubleclick) + iupKEYSETDOUBLE(status); + + if (GetKeyState(VK_MENU) & 0x8000) + iupKEYSETALT(status); + + if ((GetKeyState(VK_LWIN) & 0x8000) || (GetKeyState(VK_RWIN) & 0x8000)) + iupKEYSETSYS(status); + + if (keys & MK_XBUTTON1) + iupKEYSETBUTTON4(status); + + if (keys & MK_XBUTTON2) + iupKEYSETBUTTON5(status); +} diff --git a/iup/src/win/iupwin_label.c b/iup/src/win/iupwin_label.c new file mode 100755 index 0000000..d5a1f53 --- /dev/null +++ b/iup/src/win/iupwin_label.c @@ -0,0 +1,339 @@ +/** \file + * \brief Label Control + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_label.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_image.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" +#include "iupwin_draw.h" + + +static void winLabelDrawImage(Ihandle* ih, HDC hDC, int rect_width, int rect_height) +{ + int xpad = ih->data->horiz_padding, + ypad = ih->data->vert_padding; + int x, y, width, height, bpp; + HBITMAP hBitmap, hMask = NULL; + char *name; + int make_inactive = 0; + + if (iupdrvIsActive(ih)) + name = iupAttribGet(ih, "IMAGE"); + else + { + name = iupAttribGet(ih, "IMINACTIVE"); + if (!name) + { + name = iupAttribGet(ih, "IMAGE"); + make_inactive = 1; + } + } + + hBitmap = iupImageGetImage(name, ih, make_inactive); + if (!hBitmap) + return; + + /* must use this info, since image can be a driver image loaded from resources */ + iupdrvImageGetInfo(hBitmap, &width, &height, &bpp); + + if (ih->data->horiz_alignment == IUP_ALIGN_ARIGHT) + x = rect_width - (width + 2*xpad); + else if (ih->data->horiz_alignment == IUP_ALIGN_ACENTER) + x = (rect_width - (width + 2*xpad))/2; + else /* ALEFT */ + x = 0; + + if (ih->data->vert_alignment == IUP_ALIGN_ABOTTOM) + y = rect_height - (height + 2*ypad); + else if (ih->data->vert_alignment == IUP_ALIGN_ATOP) + y = 0; + else /* ACENTER */ + y = (rect_height - (height + 2*ypad))/2; + + x += xpad; + y += ypad; + + if (bpp == 8) + hMask = iupdrvImageCreateMask(IupGetHandle(name)); + + iupwinDrawBitmap(hDC, hBitmap, hMask, x, y, width, height, bpp); + + if (hMask) + DeleteObject(hMask); +} + +static void winLabelDrawText(Ihandle* ih, HDC hDC, int rect_width, int rect_height) +{ + int xpad = ih->data->horiz_padding, + ypad = ih->data->vert_padding; + int x, y, width, height, style; + HFONT hFont = (HFONT)iupwinGetHFontAttrib(ih); + COLORREF fgcolor; + + char* title = iupdrvBaseGetTitleAttrib(ih); + char* str = iupStrProcessMnemonic(title, NULL, 0); /* remove & */ + iupdrvFontGetMultiLineStringSize(ih, str, &width, &height); + if (str && str!=title) free(str); + + if (ih->data->horiz_alignment == IUP_ALIGN_ARIGHT) + style = DT_RIGHT; + else if (ih->data->horiz_alignment == IUP_ALIGN_ACENTER) + style = DT_CENTER; + else /* ALEFT */ + style = DT_LEFT; + + if (ih->data->vert_alignment == IUP_ALIGN_ABOTTOM) + y = rect_height - (height + 2*ypad); + else if (ih->data->vert_alignment == IUP_ALIGN_ATOP) + y = 0; + else /* ACENTER */ + y = (rect_height - (height + 2*ypad))/2; + + /* let DrawText do the horizontal alignment */ + x = xpad; + width = rect_width - 2*xpad; + y += ypad; + + if (iupdrvIsActive(ih)) + fgcolor = ih->data->fgcolor; + else + fgcolor = GetSysColor(COLOR_GRAYTEXT); + + /* WORDWRAP and ELLIPSIS */ + style |= ih->data->text_style; + + iupwinDrawText(hDC, title, x, y, width, height, hFont, fgcolor, style); +} + +static void winLabelDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem) +{ + HDC hDC; + iupwinBitmapDC bmpDC; + int width, height; + + if (!(drawitem->itemAction & ODA_DRAWENTIRE)) + return; + + width = drawitem->rcItem.right - drawitem->rcItem.left; + height = drawitem->rcItem.bottom - drawitem->rcItem.top; + + hDC = iupwinDrawCreateBitmapDC(&bmpDC, drawitem->hDC, width, height); + + iupwinDrawParentBackground(ih, hDC, &drawitem->rcItem); + + if (ih->data->type == IUP_LABEL_IMAGE) + winLabelDrawImage(ih, hDC, width, height); + else + winLabelDrawText(ih, hDC, width, height); + + iupwinDrawDestroyBitmapDC(&bmpDC); +} + +/************************************************************************************************/ + +static int winLabelSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT) + { + char value1[30] = "", value2[30] = ""; + + iupStrToStrStr(value, value1, value2, ':'); + + if (iupStrEqualNoCase(value1, "ARIGHT")) + ih->data->horiz_alignment = IUP_ALIGN_ARIGHT; + else if (iupStrEqualNoCase(value1, "ACENTER")) + ih->data->horiz_alignment = IUP_ALIGN_ACENTER; + else /* "ALEFT" */ + ih->data->horiz_alignment = IUP_ALIGN_ALEFT; + + if (iupStrEqualNoCase(value2, "ABOTTOM")) + ih->data->vert_alignment = IUP_ALIGN_ABOTTOM; + else if (iupStrEqualNoCase(value2, "ACENTER")) + ih->data->vert_alignment = IUP_ALIGN_ACENTER; + else /* "ATOP" */ + ih->data->vert_alignment = IUP_ALIGN_ATOP; + + iupdrvDisplayRedraw(ih); + } + return 0; +} + +static char* winLabelGetAlignmentAttrib(Ihandle *ih) +{ + if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT) + { + char* horiz_align2str[3] = {"ALEFT", "ACENTER", "ARIGHT"}; + char* vert_align2str[3] = {"ATOP", "ACENTER", "ABOTTOM"}; + char *str = iupStrGetMemory(50); + sprintf(str, "%s:%s", horiz_align2str[ih->data->horiz_alignment], vert_align2str[ih->data->vert_alignment]); + return str; + } + else + return NULL; +} + +static int winLabelSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + + if (ih->handle && ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT) + iupdrvDisplayRedraw(ih); + + return 0; +} + +static int winLabelSetWordWrapAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_LABEL_TEXT) + { + if (iupStrBoolean(value)) + ih->data->text_style |= DT_WORDBREAK; + else + ih->data->text_style &= ~DT_WORDBREAK; + + iupdrvDisplayRedraw(ih); + } + + return 1; +} + +static int winLabelSetEllipsisAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_LABEL_TEXT) + { + if (iupStrBoolean(value)) + ih->data->text_style |= DT_END_ELLIPSIS; + else + ih->data->text_style &= ~DT_END_ELLIPSIS; + + iupdrvDisplayRedraw(ih); + } + + return 1; +} + +static int winLabelSetFgColorAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT) + { + unsigned char r, g, b; + if (iupStrToRGB(value, &r, &g, &b)) + { + ih->data->fgcolor = RGB(r,g,b); + iupdrvDisplayRedraw(ih); + } + } + return 1; +} + +static int winLabelProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + switch (msg) + { + case WM_NCCALCSIZE: + { + if (wp == TRUE) + { + *result = WVR_HREDRAW|WVR_VREDRAW; + return 1; + } + } + } + + return iupwinBaseProc(ih, msg, wp, lp, result); +} + +static int winLabelMapMethod(Ihandle* ih) +{ + char* value; + DWORD dwStyle = WS_CHILD | + SS_NOTIFY; /* SS_NOTIFY is necessary because of the base messages */ + + if (!ih->parent) + return IUP_ERROR; + + value = iupAttribGet(ih, "SEPARATOR"); + if (value) + { + if (iupStrEqualNoCase(value, "HORIZONTAL")) + { + ih->data->type = IUP_LABEL_SEP_HORIZ; + dwStyle |= SS_ETCHEDHORZ; + } + else /* "VERTICAL" */ + { + ih->data->type = IUP_LABEL_SEP_VERT; + dwStyle |= SS_ETCHEDVERT; + } + } + else + { + /* The lack for good alignment support in STATIC control forces IUP to draw its own label, + but uses the Windows functions to draw text and images in native format. */ + dwStyle |= SS_OWNERDRAW; + + value = iupAttribGet(ih, "IMAGE"); + if (value) + ih->data->type = IUP_LABEL_IMAGE; + else + ih->data->type = IUP_LABEL_TEXT; + } + + if (!iupwinCreateWindowEx(ih, "STATIC", 0, dwStyle)) + return IUP_ERROR; + + if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT) + { + /* replace the WinProc to handle other messages */ + IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winLabelProc); + + IupSetCallback(ih, "_IUPWIN_DRAWITEM_CB", (Icallback)winLabelDrawItem); + } + + return IUP_NOERROR; +} + +void iupdrvLabelInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = winLabelMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + /* the most important use of this is to provide the correct background for images */ + iupClassRegisterAttribute(ic, "BGCOLOR", iupBaseNativeParentGetBgColorAttrib, NULL, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, winLabelSetFgColorAttrib, "DLGFGCOLOR", NULL, IUPAF_NOT_MAPPED); /* force new default value */ + iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, iupdrvBaseSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupLabel only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", winLabelGetAlignmentAttrib, winLabelSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ALEFT:ACENTER", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE", NULL, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PADDING", iupLabelGetPaddingAttrib, winLabelSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + + /* IupLabel Windows and GTK only */ + iupClassRegisterAttribute(ic, "WORDWRAP", NULL, winLabelSetWordWrapAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "ELLIPSIS", NULL, winLabelSetEllipsisAttrib, NULL, NULL, IUPAF_DEFAULT); +} diff --git a/iup/src/win/iupwin_list.c b/iup/src/win/iupwin_list.c new file mode 100755 index 0000000..8fdadb6 --- /dev/null +++ b/iup/src/win/iupwin_list.c @@ -0,0 +1,1460 @@ +/** \file + * \brief List Control + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> +#include <commctrl.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_mask.h" +#include "iup_focus.h" +#include "iup_list.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" +#include "iupwin_draw.h" + + +#ifndef EM_SETCUEBANNER /* defined only if _WIN32_WINNT >= 0x501 */ +#define ECM_FIRST 0x1500 /* Edit control messages */ +#define EM_SETCUEBANNER (ECM_FIRST + 1) +#endif + +#define WM_CARET WM_APP+1 /* Custom IUP message */ + +#define WIN_GETCOUNT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETCOUNT: LB_GETCOUNT) +#define WIN_GETTEXTLEN(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETLBTEXTLEN: LB_GETTEXTLEN) +#define WIN_GETTEXT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETLBTEXT: LB_GETTEXT) +#define WIN_ADDSTRING(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_ADDSTRING: LB_ADDSTRING) +#define WIN_DELETESTRING(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_DELETESTRING: LB_DELETESTRING) +#define WIN_INSERTSTRING(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_INSERTSTRING: LB_INSERTSTRING) +#define WIN_RESETCONTENT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_RESETCONTENT: LB_RESETCONTENT) +#define WIN_SETCURSEL(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETCURSEL: LB_SETCURSEL) +#define WIN_GETCURSEL(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETCURSEL: LB_GETCURSEL) +#define WIN_SETHORIZONTALEXTENT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETHORIZONTALEXTENT: LB_SETHORIZONTALEXTENT) +#define WIN_SETITEMDATA(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETITEMDATA: LB_SETITEMDATA) +#define WIN_GETITEMDATA(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETITEMDATA: LB_GETITEMDATA) +#define WIN_SETTOPINDEX(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETTOPINDEX: LB_SETTOPINDEX) +#define WIN_SETITEMHEIGHT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETITEMHEIGHT: LB_SETITEMHEIGHT) + + +void iupdrvListAddItemSpace(Ihandle* ih, int *h) +{ + (void)ih; + (void)h; +} + +void iupdrvListAddBorders(Ihandle* ih, int *x, int *y) +{ + int border_size = 2*4; + (*x) += border_size; + (*y) += border_size; + + if (ih->data->is_dropdown) + { + (*x) += 3; /* extra space for the dropdown button */ + + if (ih->data->has_editbox) + { + /* extra border for the editbox */ + int internal_border_size = 2*6; + (*x) += internal_border_size; + (*y) += internal_border_size; + } + } + else + { + if (ih->data->has_editbox) + (*y) += 2*3; /* internal border between editbox and list */ + } +} + +int iupdrvListGetCount(Ihandle* ih) +{ + return SendMessage(ih->handle, WIN_GETCOUNT(ih), 0, 0); +} + +static int winListConvertXYToPos(Ihandle* ih, int x, int y) +{ + int pos; + + if (ih->data->has_editbox) + { + HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + + pos = SendMessage(cbedit, EM_CHARFROMPOS, 0, MAKELPARAM(x, y)); + pos = LOWORD(pos); + } + + if (ih->data->has_editbox) + { + HWND cblist = (HWND)iupAttribGet(ih, "_IUPWIN_LISTBOX"); + pos = SendMessage(cblist, LB_ITEMFROMPOINT, 0, MAKELPARAM(x, y))+1; /* IUP Starts at 1 */ + pos = LOWORD(pos); + } + else + { + pos = SendMessage(ih->handle, LB_ITEMFROMPOINT, 0, MAKELPARAM(x, y))+1; + pos = LOWORD(pos); + } + + return pos; +} + +static int winListGetMaxWidth(Ihandle* ih) +{ + int i, item_w, max_w = 0, + count = SendMessage(ih->handle, WIN_GETCOUNT(ih), 0, 0); + + for (i=0; i<count; i++) + { + item_w = SendMessage(ih->handle, WIN_GETITEMDATA(ih), i, 0); + if (item_w > max_w) + max_w = item_w; + } + + return max_w; +} + +static void winListUpdateScrollWidth(Ihandle* ih) +{ + if (ih->data->is_dropdown && iupAttribGetBoolean(ih, "DROPEXPAND")) + { + int w = 3+winListGetMaxWidth(ih)+iupdrvGetScrollbarSize()+3; + SendMessage(ih->handle, CB_SETDROPPEDWIDTH, w, 0); + } + else + SendMessage(ih->handle, WIN_SETHORIZONTALEXTENT(ih), winListGetMaxWidth(ih), 0); +} + +void iupdrvListAppendItem(Ihandle* ih, const char* value) +{ + int pos = SendMessage(ih->handle, WIN_ADDSTRING(ih), 0, (LPARAM)value); + SendMessage(ih->handle, WIN_SETITEMDATA(ih), pos, (LPARAM)iupdrvFontGetStringWidth(ih, value)); + winListUpdateScrollWidth(ih); +} + +void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value) +{ + SendMessage(ih->handle, WIN_INSERTSTRING(ih), pos, (LPARAM)value); + SendMessage(ih->handle, WIN_SETITEMDATA(ih), pos, (LPARAM)iupdrvFontGetStringWidth(ih, value)); + winListUpdateScrollWidth(ih); +} + +void iupdrvListRemoveItem(Ihandle* ih, int pos) +{ + if (ih->data->is_dropdown && !ih->data->has_editbox) + { + /* must check if removing the current item */ + int curpos = SendMessage(ih->handle, WIN_GETCURSEL(ih), 0, 0); + if (pos == curpos) + { + if (curpos > 0) curpos--; + else curpos++; + + SendMessage(ih->handle, WIN_SETCURSEL(ih), curpos, 0); + } + } + + SendMessage(ih->handle, WIN_DELETESTRING(ih), pos, 0L); + winListUpdateScrollWidth(ih); +} + +void iupdrvListRemoveAllItems(Ihandle* ih) +{ + SendMessage(ih->handle, WIN_RESETCONTENT(ih), 0, 0L); + if (ih->data->is_dropdown && iupAttribGetBoolean(ih, "DROPEXPAND")) + SendMessage(ih->handle, CB_SETDROPPEDWIDTH, 0, 0); + else + SendMessage(ih->handle, WIN_SETHORIZONTALEXTENT(ih), 0, 0); +} + +static int winListGetCaretPos(HWND cbedit) +{ + int pos = 0; + POINT point; + + if (GetFocus() != cbedit || !GetCaretPos(&point)) + { + /* if does not have the focus, or could not get caret position, + then use the selection start position */ + SendMessage(cbedit, EM_GETSEL, (WPARAM)&pos, 0); + } + else + { + pos = SendMessage(cbedit, EM_CHARFROMPOS, 0, MAKELPARAM(point.x, point.y)); + pos = LOWORD(pos); + } + + return pos; +} + + +/*********************************************************************************/ + + +static void winListUpdateItemWidth(Ihandle* ih) +{ + int i, count = SendMessage(ih->handle, WIN_GETCOUNT(ih), 0, 0); + for (i=0; i<count; i++) + { + int len = SendMessage(ih->handle, WIN_GETTEXTLEN(ih), (WPARAM)i, 0); + char* str = iupStrGetMemory(len+1); + SendMessage(ih->handle, WIN_GETTEXT(ih), (WPARAM)i, (LPARAM)str); + SendMessage(ih->handle, WIN_SETITEMDATA(ih), i, (LPARAM)iupdrvFontGetStringWidth(ih, str)); + } +} + +static int winListSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + iupdrvSetStandardFontAttrib(ih, value); + winListUpdateItemWidth(ih); + winListUpdateScrollWidth(ih); + return 1; +} + +static char* winListGetIdValueAttrib(Ihandle* ih, const char* name_id) +{ + int pos = iupListGetPos(ih, name_id); + if (pos != -1) + { + int len = SendMessage(ih->handle, WIN_GETTEXTLEN(ih), (WPARAM)pos, 0); + char* str = iupStrGetMemory(len+1); + SendMessage(ih->handle, WIN_GETTEXT(ih), (WPARAM)pos, (LPARAM)str); + return str; + } + return NULL; +} + +static char* winListGetValueAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + int nc = GetWindowTextLength(ih->handle); + if (nc) + { + char* str = iupStrGetMemory(nc+1); + GetWindowText(ih->handle, str, nc+1); + return str; + } + } + else + { + if (ih->data->is_dropdown || !ih->data->is_multiple) + { + int pos = SendMessage(ih->handle, WIN_GETCURSEL(ih), 0, 0); + char* str = iupStrGetMemory(50); + sprintf(str, "%d", pos+1); /* IUP starts at 1 */ + return str; + } + else + { + int i, count = SendMessage(ih->handle, LB_GETCOUNT, 0, 0); + int* pos = malloc(sizeof(int)*count); + int sel_count = SendMessage(ih->handle, LB_GETSELITEMS, count, (LPARAM)pos); + char* str = iupStrGetMemory(count+1); + memset(str, '-', count); + str[count]=0; + for (i=0; i<sel_count; i++) + str[pos[i]] = '+'; + str[count]=0; + return str; + } + } + + return NULL; +} + +static int winListSetValueAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->has_editbox) + { + if (!value) value = ""; + SetWindowText(ih->handle, value); + } + else + { + if (ih->data->is_dropdown || !ih->data->is_multiple) + { + int pos; + if (iupStrToInt(value, &pos)==1) + { + SendMessage(ih->handle, WIN_SETCURSEL(ih), pos-1, 0); /* IUP starts at 1 */ + iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos); + } + else + { + SendMessage(ih->handle, WIN_SETCURSEL(ih), (WPARAM)-1, 0); /* no selection */ + iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); + } + } + else + { + /* User has changed a multiple selection on a simple list. */ + int i, len, count; + + /* Clear all selections */ + SendMessage(ih->handle, LB_SETSEL, FALSE, -1); + + if (!value) + { + iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); + return 0; + } + + count = SendMessage(ih->handle, LB_GETCOUNT, 0, 0L); + len = strlen(value); + if (len < count) + count = len; + + /* update selection list */ + for (i = 0; i<count; i++) + { + if (value[i]=='+') + SendMessage(ih->handle, LB_SETSEL, TRUE, i); + } + + iupAttribStoreStr(ih, "_IUPLIST_OLDVALUE", value); + } + } + + return 0; +} + +static int winListSetShowDropdownAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->is_dropdown) + SendMessage(ih->handle, CB_SHOWDROPDOWN, iupStrBoolean(value), 0); + return 0; +} + +static int winListSetTopItemAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->is_dropdown) + { + int pos = 1; + if (iupStrToInt(value, &pos)) + SendMessage(ih->handle, WIN_SETTOPINDEX(ih), pos-1, 0); /* IUP starts at 1 */ + } + return 0; +} + +static int winListSetSpacingAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->is_dropdown) + return 0; + + if (!iupStrToInt(value, &ih->data->spacing)) + ih->data->spacing = 0; + + if (ih->handle) + { + int height; + iupdrvFontGetCharSize(ih, NULL, &height); + height += 2*ih->data->spacing; + SendMessage(ih->handle, WIN_SETITEMHEIGHT(ih), 0, height); + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ +} + +static int winListSetPaddingAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->has_editbox) + return 0; + + iupStrToIntInt(value, &(ih->data->horiz_padding), &(ih->data->vert_padding), 'x'); + ih->data->vert_padding = 0; + if (ih->handle) + { + HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN, MAKELPARAM(ih->data->horiz_padding, ih->data->horiz_padding)); + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ +} + +static int winListSetFilterAttrib(Ihandle *ih, const char *value) +{ + int style = 0; + + if (!ih->data->has_editbox) + return 0; + + if (iupStrEqualNoCase(value, "LOWERCASE")) + style = ES_LOWERCASE; + else if (iupStrEqualNoCase(value, "NUMBER")) + style = ES_NUMBER; + else if (iupStrEqualNoCase(value, "UPPERCASE")) + style = ES_UPPERCASE; + + if (style) + { + HWND old_handle = ih->handle; + ih->handle = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + iupwinMergeStyle(ih, ES_LOWERCASE|ES_NUMBER|ES_UPPERCASE, style); + ih->handle = old_handle; + } + + return 1; +} + +static int winListSetCueBannerAttrib(Ihandle *ih, const char *value) +{ + if (ih->data->has_editbox && iupwin_comctl32ver6) + { + WCHAR* wstr = iupwinStrChar2Wide(value); + HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_SETCUEBANNER, (WPARAM)FALSE, (LPARAM)wstr); + free(wstr); + return 1; + } + return 0; +} + +static int winListSetClipboardAttrib(Ihandle *ih, const char *value) +{ + UINT msg = 0; + + if (!ih->data->has_editbox) + return 0; + + if (iupStrEqualNoCase(value, "COPY")) + msg = WM_COPY; + else if (iupStrEqualNoCase(value, "CUT")) + msg = WM_CUT; + else if (iupStrEqualNoCase(value, "PASTE")) + msg = WM_PASTE; + else if (iupStrEqualNoCase(value, "CLEAR")) + msg = WM_CLEAR; + else if (iupStrEqualNoCase(value, "UNDO")) + msg = WM_UNDO; + + if (msg) + { + HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, msg, 0, 0); + } + + return 0; +} + +static int winListSetSelectedTextAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->has_editbox) + return 0; + + if (value) + { + int start = 0, end = 0; + HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); + if (start == end) + return 0; + SendMessage(cbedit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)value); + } + return 0; +} + +static char* winListGetSelectedTextAttrib(Ihandle* ih) +{ + int nc; + HWND cbedit; + if (!ih->data->has_editbox) + return 0; + + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + nc = GetWindowTextLength(cbedit); + if (nc) + { + int start = 0, end = 0; + char* str; + + SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); + if (start == end) + return NULL; + + str = iupStrGetMemory(nc+1); + GetWindowText(cbedit, str, nc+1); + str[end] = 0; /* returns only the selected text */ + str += start; + + return str; + } + else + return NULL; +} + +static int winListSetNCAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->has_editbox) + return 0; + + if (!iupStrToInt(value, &ih->data->nc)) + ih->data->nc = 0; + + if (ih->handle) + { + HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_LIMITTEXT, ih->data->nc, 0L); + } + return 0; +} + +static int winListSetSelectionAttrib(Ihandle* ih, const char* value) +{ + HWND cbedit; + int start=1, end=1; + if (!ih->data->has_editbox) + return 0; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_SETSEL, (WPARAM)-1, (LPARAM)0); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_SETSEL, (WPARAM)0, (LPARAM)-1); + return 0; + } + + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<1 || end<1) + return 0; + + start--; /* IUP starts at 1 */ + end--; + + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_SETSEL, (WPARAM)start, (LPARAM)end); + + return 0; +} + +static char* winListGetSelectionAttrib(Ihandle* ih) +{ + int start = 0, end = 0; + char* str; + HWND cbedit; + if (!ih->data->has_editbox) + return NULL; + + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); + if (start == end) + return NULL; + + str = iupStrGetMemory(100); + + start++; /* IUP starts at 1 */ + end++; + sprintf(str, "%d:%d", start, end); + + return str; +} + +static int winListSetSelectionPosAttrib(Ihandle* ih, const char* value) +{ + int start=0, end=0; + HWND cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_SETSEL, (WPARAM)-1, (LPARAM)0); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_SETSEL, (WPARAM)0, (LPARAM)-1); + return 0; + } + + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<0 || end<0) + return 0; + + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_SETSEL, (WPARAM)start, (LPARAM)end); + + return 0; +} + +static char* winListGetSelectionPosAttrib(Ihandle* ih) +{ + int start = 0, end = 0; + char* str; + HWND cbedit; + if (!ih->data->has_editbox) + return NULL; + + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); + if (start == end) + return NULL; + + str = iupStrGetMemory(100); + sprintf(str, "%d:%d", start, end); + return str; +} + +static int winListSetInsertAttrib(Ihandle* ih, const char* value) +{ + if (value && ih->data->has_editbox) + { + HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)value); + } + return 0; +} + +static int winListSetAppendAttrib(Ihandle* ih, const char* value) +{ + int len; + HWND cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value) value = ""; + + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + len = GetWindowTextLength(cbedit)+1; + SendMessage(cbedit, EM_SETSEL, (WPARAM)len, (LPARAM)len); + SendMessage(cbedit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)value); + + return 0; +} + +static int winListSetReadOnlyAttrib(Ihandle* ih, const char* value) +{ + HWND cbedit; + if (!ih->data->has_editbox) + return 0; + + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_SETREADONLY, (WPARAM)iupStrBoolean(value), 0); + return 0; +} + +static char* winListGetReadOnlyAttrib(Ihandle* ih) +{ + DWORD style; + HWND cbedit; + if (!ih->data->has_editbox) + return NULL; + + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + style = GetWindowLong(cbedit, GWL_STYLE); + if (style & ES_READONLY) + return "YES"; + else + return "NO"; +} + +static int winListSetCaretAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + HWND cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 1) pos = 1; + pos--; /* IUP starts at 1 */ + + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_SETSEL, (WPARAM)pos, (LPARAM)pos); + SendMessage(cbedit, EM_SCROLLCARET, 0L, 0L); + + return 0; +} + +static char* winListGetCaretAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + char* str = iupStrGetMemory(100); + HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + sprintf(str, "%d", winListGetCaretPos(cbedit)+1); + return str; + } + else + return NULL; +} + +static int winListSetCaretPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + HWND cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); /* be permissive in SetCaret, do not abort if invalid */ + if (pos < 0) pos = 0; + + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_SETSEL, (WPARAM)pos, (LPARAM)pos); + SendMessage(cbedit, EM_SCROLLCARET, 0L, 0L); + + return 0; +} + +static char* winListGetCaretPosAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + char* str = iupStrGetMemory(100); + HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + sprintf(str, "%d", winListGetCaretPos(cbedit)); + return str; + } + else + return NULL; +} + +static int winListSetScrollToAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + HWND cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 1) pos = 1; + + pos--; /* return to Windows referece */ + + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_LINESCROLL, (WPARAM)pos, (LPARAM)0); + + return 0; +} + +static int winListSetScrollToPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + HWND cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + SendMessage(cbedit, EM_LINESCROLL, (WPARAM)pos, (LPARAM)0); + + return 0; +} + + +/*********************************************************************************/ + + +static int winListCtlColor(Ihandle* ih, HDC hdc, LRESULT *result) +{ + COLORREF cr; + + if (iupwinGetColorRef(ih, "FGCOLOR", &cr)) + SetTextColor(hdc, cr); + + if (iupwinGetColorRef(ih, "BGCOLOR", &cr)) + { + SetBkColor(hdc, cr); + SetDCBrushColor(hdc, cr); + *result = (LRESULT)GetStockObject(DC_BRUSH); + return 1; + } + return 0; +} + +static int winListWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp) +{ + (void)lp; + + if (ih->data->is_dropdown || ih->data->has_editbox) + { + switch (HIWORD(wp)) + { + case CBN_EDITCHANGE: + { + iupBaseCallValueChangedCb(ih); + break; + } + case CBN_SETFOCUS: + iupwinWmSetFocus(ih); + break; + case CBN_KILLFOCUS: + iupCallKillFocusCb(ih); + break; + case CBN_CLOSEUP: + case CBN_DROPDOWN: + { + IFni cb = (IFni)IupGetCallback(ih, "DROPDOWN_CB"); + if (cb) + cb(ih, HIWORD(wp)==CBN_DROPDOWN? 1: 0); + break; + } + case CBN_DBLCLK: + { + IFnis cb = (IFnis) IupGetCallback(ih, "DBLCLICK_CB"); + if (cb) + { + int pos = SendMessage(ih->handle, CB_GETCURSEL, 0, 0); + pos++; /* IUP starts at 1 */ + iupListSingleCallDblClickCallback(ih, cb, pos); + } + break; + } + case CBN_SELCHANGE: + { + IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION"); + if (cb) + { + int pos = SendMessage(ih->handle, CB_GETCURSEL, 0, 0); + pos++; /* IUP starts at 1 */ + iupListSingleCallActionCallback(ih, cb, pos); + } + + iupBaseCallValueChangedCb(ih); + break; + } + } + } + else + { + switch (HIWORD(wp)) + { + case LBN_DBLCLK: + { + IFnis cb = (IFnis) IupGetCallback(ih, "DBLCLICK_CB"); + if (cb) + { + int pos = SendMessage(ih->handle, LB_GETCURSEL, 0, 0); + pos++; /* IUP starts at 1 */ + iupListSingleCallDblClickCallback(ih, cb, pos); + } + break; + } + case LBN_SELCHANGE: + { + if (!ih->data->is_multiple) + { + IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION"); + if (cb) + { + int pos = SendMessage(ih->handle, LB_GETCURSEL, 0, 0); + pos++; /* IUP starts at 1 */ + iupListSingleCallActionCallback(ih, cb, pos); + } + } + else + { + IFns multi_cb = (IFns)IupGetCallback(ih, "MULTISELECT_CB"); + IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION"); + if (multi_cb || cb) + { + int sel_count = SendMessage(ih->handle, LB_GETSELCOUNT, 0, 0); + int* pos = malloc(sizeof(int)*sel_count); + SendMessage(ih->handle, LB_GETSELITEMS, sel_count, (LPARAM)pos); + iupListMultipleCallActionCallback(ih, cb, multi_cb, pos, sel_count); + free(pos); + } + } + + iupBaseCallValueChangedCb(ih); + break; + } + } + } + + return 0; /* not used */ +} + +static void winListCallCaretCb(Ihandle* ih, HWND cbedit) +{ + int pos; + + IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB"); + if (!cb) return; + + pos = winListGetCaretPos(cbedit); + + if (pos != ih->data->last_caret_pos) + { + ih->data->last_caret_pos = pos; + cb(ih, 1, pos+1, pos); + } +} + +static int winListCallEditCb(Ihandle* ih, HWND cbedit, const char* insert_value, int key, int dir) +{ + int start, end, ret = 1; + char *value, *new_value; + + IFnis cb = (IFnis)IupGetCallback(ih, "EDIT_CB"); + if (!cb && !ih->data->mask) + return 1; + + SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); + + value = winListGetValueAttrib(ih); + + if (!value) + new_value = iupStrDup(insert_value); + else if (insert_value) + new_value = iupStrInsert(value, insert_value, start, end); + else + { + new_value = value; + iupStrRemove(value, start, end, dir); + } + + if (!new_value) + return 0; /* abort */ + + if (ih->data->nc && (int)strlen(new_value) > ih->data->nc) + { + if (new_value != value) free(new_value); + return 0; /* abort */ + } + + if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0) + { + if (new_value != value) free(new_value); + return 0; /* abort */ + } + + if (cb) + { + int cb_ret = cb(ih, key, (char*)new_value); + if (cb_ret==IUP_IGNORE) + ret = 0; /* abort processing */ + else if (cb_ret==IUP_CLOSE) + { + IupExitLoop(); + ret = 0; /* abort processing */ + } + else if (cb_ret!=0 && key!=0 && + cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE) + { + WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_EDITOLDPROC_CB"); + CallWindowProc(oldProc, cbedit, WM_CHAR, cb_ret, 0); /* replace key */ + ret = 0; /* abort processing */ + } + } + + if (new_value != value) free(new_value); + return ret; +} + +static int winListEditProc(Ihandle* ih, HWND cbedit, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + int ret = 0; + + if (msg==WM_KEYDOWN) /* process K_ANY before text callbacks */ + { + ret = iupwinBaseProc(ih, msg, wp, lp, result); + if (ret) return 1; + } + + switch (msg) + { + case WM_CHAR: + { + if ((char)wp == '\b') + { + if (!winListCallEditCb(ih, cbedit, NULL, 0, -1)) + ret = 1; + } + else if ((char)wp == '\n' || (char)wp == '\r') + { + ret = 1; + } + else if (!(GetKeyState(VK_CONTROL) & 0x8000 || + GetKeyState(VK_MENU) & 0x8000 || + GetKeyState(VK_LWIN) & 0x8000 || + GetKeyState(VK_RWIN) & 0x8000)) + { + char insert_value[2]; + insert_value[0] = (char)wp; + insert_value[1] = 0; + + if (!winListCallEditCb(ih, cbedit, insert_value, wp, 1)) + ret = 1; + } + + PostMessage(cbedit, WM_CARET, 0, 0L); + + if (wp==VK_TAB) /* the keys have the same definitions as the chars */ + ret = 1; /* abort default processing to avoid beep */ + + break; + } + case WM_KEYDOWN: + { + if (wp == VK_DELETE) /* Del does not generates a WM_CHAR */ + { + if (!winListCallEditCb(ih, cbedit, NULL, 0, 1)) + ret = 1; + } + else if (wp == 'A' && GetKeyState(VK_CONTROL) & 0x8000) /* Ctrl+A = Select All */ + { + SendMessage(cbedit, EM_SETSEL, (WPARAM)0, (LPARAM)-1); + } + + PostMessage(cbedit, WM_CARET, 0, 0L); + break; + } + case WM_CLEAR: + { + if (!winListCallEditCb(ih, cbedit, NULL, 0, 1)) + ret = 1; + + PostMessage(cbedit, WM_CARET, 0, 0L); + break; + } + case WM_CUT: + { + if (!winListCallEditCb(ih, cbedit, NULL, 0, 1)) + ret = 1; + + PostMessage(cbedit, WM_CARET, 0, 0L); + break; + } + case WM_PASTE: + { + if (IupGetCallback(ih, "EDIT_CB") || ih->data->mask) /* test before to avoid alocate clipboard text memory */ + { + char* insert_value = iupwinGetClipboardText(ih); + if (insert_value) + { + if (!winListCallEditCb(ih, cbedit, insert_value, 0, 1)) + ret = 1; + free(insert_value); + } + } + + PostMessage(cbedit, WM_CARET, 0, 0L); + break; + } + case WM_UNDO: + { + IFnis cb = (IFnis)IupGetCallback(ih, "EDIT_CB"); + if (cb) + { + char* value; + WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_EDITOLDPROC_CB"); + CallWindowProc(oldProc, cbedit, WM_UNDO, 0, 0); + + value = winListGetValueAttrib(ih); + cb(ih, 0, (char*)value); + + ret = 1; + } + + PostMessage(cbedit, WM_CARET, 0, 0L); + break; + } + case WM_KEYUP: + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONUP: + PostMessage(cbedit, WM_CARET, 0, 0L); + break; + case WM_CARET: + winListCallCaretCb(ih, cbedit); + break; + } + + if (ret) /* if abort processing, then the result is 0 */ + { + *result = 0; + return 1; + } + else + { + if (msg==WM_KEYDOWN) + return 0; + else + return iupwinBaseProc(ih, msg, wp, lp, result); + } +} + +static LRESULT CALLBACK winListEditWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + int ret = 0; + LRESULT result = 0; + WNDPROC oldProc; + Ihandle *ih; + + ih = iupwinHandleGet(hwnd); + if (!ih) + return DefWindowProc(hwnd, msg, wp, lp); /* should never happen */ + + /* retrieve the control previous procedure for subclassing */ + oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_EDITOLDPROC_CB"); + + ret = winListEditProc(ih, hwnd, msg, wp, lp, &result); + + if (ret) + return result; + else + return CallWindowProc(oldProc, hwnd, msg, wp, lp); +} + +static int winListComboListProc(Ihandle* ih, HWND cblist, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + (void)cblist; + + switch (msg) + { + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + if (iupwinButtonDown(ih, msg, wp, lp)==-1) + { + *result = 0; + return 1; + } + break; + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONUP: + if (iupwinButtonUp(ih, msg, wp, lp)==-1) + { + *result = 0; + return 1; + } + break; + case WM_MOUSEMOVE: + iupwinMouseMove(ih, msg, wp, lp); + iupwinBaseProc(ih, msg, wp, lp, result); /* to process ENTER/LEAVE */ + break; + case WM_MOUSELEAVE: + iupwinBaseProc(ih, msg, wp, lp, result); /* to process ENTER/LEAVE */ + break; + } + + return 0; +} + +static LRESULT CALLBACK winListComboListWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + int ret = 0; + LRESULT result = 0; + WNDPROC oldProc; + Ihandle *ih; + + ih = iupwinHandleGet(hwnd); + if (!ih) + return DefWindowProc(hwnd, msg, wp, lp); /* should never happen */ + + /* retrieve the control previous procedure for subclassing */ + oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_LISTOLDPROC_CB"); + + ret = winListComboListProc(ih, hwnd, msg, wp, lp, &result); + + if (ret) + return result; + else + return CallWindowProc(oldProc, hwnd, msg, wp, lp); +} + +static int winListProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + if (!ih->data->is_dropdown && !ih->data->has_editbox) + { + switch (msg) + { + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + if (iupwinButtonDown(ih, msg, wp, lp)==-1) + { + *result = 0; + return 1; + } + break; + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONUP: + if (iupwinButtonUp(ih, msg, wp, lp)==-1) + { + *result = 0; + return 1; + } + break; + case WM_MOUSEMOVE: + iupwinMouseMove(ih, msg, wp, lp); + break; + } + } + + switch (msg) + { + case WM_CHAR: + if (GetKeyState(VK_CONTROL) & 0x8000) + { + /* avoid item search when Ctrl is pressed */ + *result = 0; + return 1; + } + case WM_SETFOCUS: + case WM_KILLFOCUS: + case WM_MOUSELEAVE: + case WM_MOUSEMOVE: + if (ih->data->has_editbox) + return 0; /* do not call base procedure to avoid duplicate messages */ + break; + } + + return iupwinBaseProc(ih, msg, wp, lp, result); +} + + +/*********************************************************************************/ + + +static void winListLayoutUpdateMethod(Ihandle *ih) +{ + if (ih->data->is_dropdown) + { + /* Must add the dropdown area, or it will not be visible */ + RECT rect; + int charheight, calc_h, win_h, win_w, voptions; + + voptions = iupAttribGetInt(ih, "VISIBLE_ITEMS"); + if (voptions <= 0) + voptions = 1; + + iupdrvFontGetCharSize(ih, NULL, &charheight); + calc_h = ih->currentheight + voptions*charheight; + + SendMessage(ih->handle, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rect); + win_h = rect.bottom-rect.top; + win_w = rect.right-rect.left; + + if (ih->currentwidth != win_w || calc_h != win_h) + SetWindowPos(ih->handle, HWND_TOP, ih->x, ih->y, ih->currentwidth, calc_h, + SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOOWNERZORDER); + else + SetWindowPos(ih->handle, HWND_TOP, ih->x, ih->y, 0, 0, + SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOOWNERZORDER); + } + else + iupdrvBaseLayoutUpdateMethod(ih); +} + +static int winListMapMethod(Ihandle* ih) +{ + char* class_name; + DWORD dwStyle = WS_CHILD, + dwExStyle = WS_EX_CLIENTEDGE; + + if (!ih->parent) + return IUP_ERROR; + + if (ih->data->is_dropdown || ih->data->has_editbox) + { + class_name = "COMBOBOX"; + + dwStyle |= CBS_NOINTEGRALHEIGHT; + + if (ih->data->is_dropdown) + dwStyle |= WS_VSCROLL|WS_HSCROLL; + else if (ih->data->sb) + { + dwStyle |= WS_VSCROLL|WS_HSCROLL; + + if (!iupAttribGetBoolean(ih, "AUTOHIDE")) + dwStyle |= CBS_DISABLENOSCROLL; + } + + if (ih->data->has_editbox) + { + dwStyle |= CBS_AUTOHSCROLL; + + if (ih->data->is_dropdown) + dwStyle |= CBS_DROPDOWN; /* hidden-list+edit */ + else + dwStyle |= CBS_SIMPLE; /* visible-list+edit */ + } + else + dwStyle |= CBS_DROPDOWNLIST; /* hidden-list */ + + if (iupAttribGetBoolean(ih, "SORT")) + dwStyle |= CBS_SORT; + } + else + { + class_name = "LISTBOX"; + + dwStyle |= LBS_NOINTEGRALHEIGHT|LBS_NOTIFY; + + if (ih->data->is_multiple) + dwStyle |= LBS_EXTENDEDSEL; + + if (ih->data->sb) + { + dwStyle |= WS_VSCROLL|WS_HSCROLL; + + if (!iupAttribGetBoolean(ih, "AUTOHIDE")) + dwStyle |= LBS_DISABLENOSCROLL; + } + + if (iupAttribGetBoolean(ih, "SORT")) + dwStyle |= LBS_SORT; + } + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + dwStyle |= WS_TABSTOP; + + if (!iupwinCreateWindowEx(ih, class_name, dwExStyle, dwStyle)) + return IUP_ERROR; + + /* Custom Procedure */ + IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winListProc); + + /* Process background color */ + IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winListCtlColor); + + /* Process WM_COMMAND */ + IupSetCallback(ih, "_IUPWIN_COMMAND_CB", (Icallback)winListWmCommand); + + if (ih->data->is_dropdown || ih->data->has_editbox) + { + COMBOBOXINFO boxinfo; + + ZeroMemory(&boxinfo, sizeof(COMBOBOXINFO)); + boxinfo.cbSize = sizeof(COMBOBOXINFO); + + GetComboBoxInfo(ih->handle, &boxinfo); + + iupwinHandleAdd(ih, boxinfo.hwndList); + iupAttribSetStr(ih, "_IUPWIN_LISTBOX", (char*)boxinfo.hwndList); + + /* subclass the list box. */ + IupSetCallback(ih, "_IUPWIN_LISTOLDPROC_CB", (Icallback)GetWindowLongPtr(boxinfo.hwndList, GWLP_WNDPROC)); + SetWindowLongPtr(boxinfo.hwndList, GWLP_WNDPROC, (LONG_PTR)winListComboListWinProc); + + if (ih->data->has_editbox) + { + iupwinHandleAdd(ih, boxinfo.hwndItem); + iupAttribSetStr(ih, "_IUPWIN_EDITBOX", (char*)boxinfo.hwndItem); + + /* subclass the edit box. */ + IupSetCallback(ih, "_IUPWIN_EDITOLDPROC_CB", (Icallback)GetWindowLongPtr(boxinfo.hwndItem, GWLP_WNDPROC)); + SetWindowLongPtr(boxinfo.hwndItem, GWLP_WNDPROC, (LONG_PTR)winListEditWinProc); + + /* set defaults */ + SendMessage(ih->handle, CB_LIMITTEXT, 0, 0L); + } + } + + /* configure for DRAG&DROP */ + if (IupGetCallback(ih, "DROPFILES_CB")) + iupAttribSetStr(ih, "DRAGDROP", "YES"); + + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)winListConvertXYToPos); + + iupListSetInitialItems(ih); + + return IUP_NOERROR; +} + +void iupdrvListInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = winListMapMethod; + ic->LayoutUpdate = winListLayoutUpdateMethod; + + /* Driver Dependent Attribute functions */ + + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, winListSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_NOT_MAPPED); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_NOT_MAPPED); + + /* IupList only */ + iupClassRegisterAttributeId(ic, "IDVALUE", winListGetIdValueAttrib, iupListSetIdValueAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE", winListGetValueAttrib, winListSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWDROPDOWN", NULL, winListSetShowDropdownAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TOPITEM", NULL, winListSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VISIBLE_ITEMS", NULL, NULL, IUPAF_SAMEASSYSTEM, "5", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "DROPEXPAND", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPACING", iupListGetSpacingAttrib, winListSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + + iupClassRegisterAttribute(ic, "PADDING", iupListGetPaddingAttrib, winListSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "SELECTEDTEXT", winListGetSelectedTextAttrib, winListSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTION", winListGetSelectionAttrib, winListSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTIONPOS", winListGetSelectionPosAttrib, winListSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARET", winListGetCaretAttrib, winListSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARETPOS", winListGetCaretPosAttrib, winListSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INSERT", NULL, winListSetInsertAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "APPEND", NULL, winListSetAppendAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "READONLY", winListGetReadOnlyAttrib, winListSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "NC", iupListGetNCAttrib, winListSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, winListSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTO", NULL, winListSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, winListSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "CUEBANNER", NULL, winListSetCueBannerAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FILTER", NULL, winListSetFilterAttrib, NULL, NULL, IUPAF_NO_INHERIT); +} diff --git a/iup/src/win/iupwin_loop.c b/iup/src/win/iupwin_loop.c new file mode 100755 index 0000000..7c5dbe7 --- /dev/null +++ b/iup/src/win/iupwin_loop.c @@ -0,0 +1,135 @@ +/** \file + * \brief Windows Message Loop + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <windows.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" + + +static IFidle win_idle_cb = NULL; +static int win_main_loop = 0; + + +void iupdrvSetIdleFunction(Icallback f) +{ + win_idle_cb = (IFidle)f; +} + +void IupExitLoop(void) +{ + PostQuitMessage(0); +} + +static int winLoopProcessMessage(MSG* msg) +{ + if (msg->message == WM_QUIT) /* IUP_CLOSE returned in a callback or IupHide in a popup dialog or all dialogs closed */ + return IUP_CLOSE; + else + { + TranslateMessage(msg); + DispatchMessage(msg); + return IUP_DEFAULT; + } +} + +int IupMainLoopLevel(void) +{ + return win_main_loop; +} + +int IupMainLoop(void) +{ + MSG msg; + int ret; + + win_main_loop++; + + do + { + if (win_idle_cb) + { + ret = 1; + if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { + if (winLoopProcessMessage(&msg) == IUP_CLOSE) + { + win_main_loop--; + return IUP_CLOSE; + } + } + else + { + int ret = win_idle_cb(); + if (ret == IUP_CLOSE) + { + win_idle_cb = NULL; + win_main_loop--; + return IUP_CLOSE; + } + if (ret == IUP_IGNORE) + win_idle_cb = NULL; + } + } + else + { + ret = GetMessage(&msg, NULL, 0, 0); + if (ret == -1) /* error */ + { + win_main_loop--; + return IUP_ERROR; + } + if (ret == 0 || /* WM_QUIT */ + winLoopProcessMessage(&msg) == IUP_CLOSE) /* ret != 0 */ + { + win_main_loop--; + return IUP_NOERROR; + } + } + } while (ret); + + win_main_loop--; + return IUP_NOERROR; +} + +int IupLoopStep(void) +{ + MSG msg; + if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + return winLoopProcessMessage(&msg); + + return IUP_DEFAULT; +} + +void IupFlush(void) +{ + int post_quit = 0; + MSG msg; + + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { + if (winLoopProcessMessage(&msg) == IUP_CLOSE) + { + post_quit = 1; + break; + } + } + + /* re post the quit message if still inside MainLoop */ + if (post_quit && win_main_loop>0) + PostQuitMessage(0); +} diff --git a/iup/src/win/iupwin_menu.c b/iup/src/win/iupwin_menu.c new file mode 100755 index 0000000..74a8b52 --- /dev/null +++ b/iup/src/win/iupwin_menu.c @@ -0,0 +1,667 @@ +/** \file + * \brief Menu Resources + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> + +#include <stdio.h> +#include <stdlib.h> +#include <memory.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_image.h" +#include "iup_dlglist.h" +#include "iup_focus.h" +#include "iup_menu.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" +#include "iupwin_brush.h" + + +Ihandle* iupwinMenuGetHandle(HMENU hMenu) +{ + MENUINFO menuinfo; + menuinfo.cbSize = sizeof(MENUINFO); + menuinfo.fMask = MIM_MENUDATA; + if (GetMenuInfo(hMenu, &menuinfo)) + return (Ihandle*)menuinfo.dwMenuData; + else + return NULL; +} + +Ihandle* iupwinMenuGetItemHandle(HMENU hMenu, int menuId) +{ + MENUITEMINFO menuiteminfo; + menuiteminfo.cbSize = sizeof(MENUITEMINFO); + menuiteminfo.fMask = MIIM_DATA; + + if (GetMenuItemInfo(hMenu, menuId, FALSE, &menuiteminfo)) + return (Ihandle*)menuiteminfo.dwItemData; + else + return NULL; +} + +int iupdrvMenuGetMenuBarSize(Ihandle* ih) +{ + (void)ih; + return GetSystemMetrics(SM_CYMENU); +} + +static void winMenuUpdateBar(Ihandle* ih) +{ + if (iupMenuIsMenuBar(ih) && ih->parent->handle) + DrawMenuBar(ih->parent->handle); + else if (ih->parent) + { + ih = ih->parent; /* check also for children of a menu bar */ + if (iupMenuIsMenuBar(ih) && ih->parent->handle) + DrawMenuBar(ih->parent->handle); + } +} + +static void winMenuGetLastPos(Ihandle* ih, int *last_pos, int *pos) +{ + Ihandle* child; + *last_pos=0; + *pos=0; + for (child=ih->parent->firstchild; child; child=child->brother) + { + if (child == ih) + *pos = *last_pos; + (*last_pos)++; + } +} + +static void winItemCheckToggle(Ihandle* ih) +{ + if (iupAttribGetBoolean(ih->parent, "RADIO")) + { + int last_pos, pos; + winMenuGetLastPos(ih, &last_pos, &pos); + CheckMenuRadioItem((HMENU)ih->handle, 0, last_pos, pos, MF_BYPOSITION); + + winMenuUpdateBar(ih); + } + else if (iupAttribGetBoolean(ih, "AUTOTOGGLE")) + { + if (GetMenuState((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND) & MF_CHECKED) + CheckMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_UNCHECKED|MF_BYCOMMAND); + else + CheckMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_CHECKED|MF_BYCOMMAND); + + winMenuUpdateBar(ih); + } +} + +typedef struct _IchildId +{ + int id, menuid; + Ihandle* child; +} IchildId; + +void iupwinMenuDialogProc(Ihandle* ih_dialog, UINT msg, WPARAM wp, LPARAM lp) +{ + /* called only from winDialogBaseProc */ + + switch (msg) + { + case WM_INITMENUPOPUP: + { + HMENU hMenu = (HMENU)wp; + Ihandle *ih = iupwinMenuGetHandle(hMenu); + if (ih) + { + Icallback cb = (Icallback)IupGetCallback(ih, "OPEN_CB"); + if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "OPEN_CB"); /* check also in the Submenu */ + if (cb) cb(ih); + } + break; + } + case WM_UNINITMENUPOPUP: + { + HMENU hMenu = (HMENU)wp; + Ihandle *ih = iupwinMenuGetHandle(hMenu); + if (ih) + { + Icallback cb = (Icallback)IupGetCallback(ih, "MENUCLOSE_CB"); + if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "MENUCLOSE_CB"); /* check also in the Submenu */ + if (cb) cb(ih); + } + break; + } + case WM_MENUSELECT: + { + HMENU hMenu = (HMENU)lp; + Ihandle *ih; + + if (!lp) + break; + + if ((HIWORD(wp) & MF_POPUP) || (HIWORD(wp) & MF_SYSMENU)) /* drop-down ih or submenu. */ + { + UINT menuindex = LOWORD(wp); + HMENU hsubmenu = GetSubMenu(hMenu, menuindex); + ih = iupwinMenuGetHandle(hsubmenu); /* returns the handle of a IupMenu */ + if (ih) ih = ih->parent; /* gets the submenu */ + } + else /* ih item */ + { + UINT menuID = LOWORD(wp); + ih = iupwinMenuGetItemHandle(hMenu, menuID); + } + + if (ih) + { + Icallback cb = IupGetCallback(ih, "HIGHLIGHT_CB"); + if (cb) cb(ih); + } + break; + } + case WM_MENUCOMMAND: + { + int menuId = GetMenuItemID((HMENU)lp, (int)wp); + Icallback cb; + Ihandle* ih; + + if (menuId >= IUP_MDICHILD_START) + break; + + ih = iupwinMenuGetItemHandle((HMENU)lp, menuId); + if (!ih) + break; + + winItemCheckToggle(ih); + + cb = IupGetCallback(ih, "ACTION"); + if (cb && cb(ih) == IUP_CLOSE) + IupExitLoop(); + + break; + } + case WM_ENTERMENULOOP: + { + /* Simulate WM_KILLFOCUS when the menu interaction is started */ + Ihandle* lastfocus = (Ihandle*)iupAttribGet(ih_dialog, "_IUPWIN_LASTFOCUS"); + if (lastfocus) iupCallKillFocusCb(lastfocus); + break; + } + case WM_EXITMENULOOP: + { + /* Simulate WM_GETFOCUS when the menu interaction is stopped */ + Ihandle* lastfocus = (Ihandle*)iupAttribGet(ih_dialog, "_IUPWIN_LASTFOCUS"); + if (lastfocus) iupCallGetFocusCb(lastfocus); + break; + } + } +} + +int iupdrvMenuPopup(Ihandle* ih, int x, int y) +{ + HWND hWndActive = GetActiveWindow(); + int tray_menu = 0; + int menuId; + + if (!hWndActive) + { + /* search for a valid handle */ + Ihandle* dlg = iupDlgListFirst(); + do + { + if (dlg->handle) + { + hWndActive = dlg->handle; /* found a valid handle */ + + /* if not a "TRAY" dialog, keep searching, because TRAY is a special case */ + if (iupAttribGetBoolean(dlg, "TRAY")) + break; + } + dlg = iupDlgListNext(); + } while (dlg); + } + + /* Necessary to avoid tray dialogs to lock popup menus (they get sticky after the 1st time) */ + if (hWndActive) + { + Ihandle* dlg = iupwinHandleGet(hWndActive); + if (dlg && iupAttribGetBoolean(dlg, "TRAY")) + { + /* To display a context menu for a notification icon, + the current window must be the foreground window. */ + SetForegroundWindow(hWndActive); + tray_menu = 1; + } + } + + /* stop processing here. messages will not go to the message loop */ + menuId = TrackPopupMenu((HMENU)ih->handle, TPM_LEFTALIGN|TPM_RIGHTBUTTON|TPM_RETURNCMD, x, y, 0, hWndActive, NULL); + + if (tray_menu) + { + /* You must force a task switch to the application that + called TrackPopupMenu at some time in the near future. + This is done by posting a benign message to the window. */ + PostMessage(hWndActive, WM_NULL, 0, 0); + } + + if (menuId) + { + Icallback cb; + Ihandle* ih_item = iupwinMenuGetItemHandle((HMENU)ih->handle, menuId); + if (!ih_item) return IUP_NOERROR; + + winItemCheckToggle(ih_item); + + cb = IupGetCallback(ih_item, "ACTION"); + if (cb && cb(ih_item) == IUP_CLOSE) + IupExitLoop(); + } + + return IUP_NOERROR; +} + + +/*******************************************************************************************/ + + +static int winMenuSetBgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + /* must use IupGetAttribute to use inheritance */ + if (iupStrToRGB(value, &r, &g, &b)) + { + MENUINFO menuinfo; + menuinfo.cbSize = sizeof(MENUINFO); + menuinfo.fMask = MIM_BACKGROUND; + menuinfo.hbrBack = iupwinBrushGet(RGB(r,g,b)); + SetMenuInfo((HMENU)ih->handle, &menuinfo); + winMenuUpdateBar(ih); + } + return 1; +} + +static void winMenuChildUnMapMethod(Ihandle* ih) +{ + RemoveMenu((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND); +} + +static int winMenuAddParentSubmenu(Ihandle* ih) +{ + int pos; + MENUITEMINFO menuiteminfo; + + pos = IupGetChildPos(ih->parent, ih); + ih->serial = iupMenuGetChildId(ih); + + menuiteminfo.cbSize = sizeof(MENUITEMINFO); + menuiteminfo.fMask = MIIM_ID|MIIM_DATA|MIIM_SUBMENU|MIIM_STRING; + menuiteminfo.dwTypeData = ""; /* must set or it will be not possible to update */ + menuiteminfo.cch = 0; + menuiteminfo.wID = (UINT)ih->serial; + menuiteminfo.dwItemData = (ULONG_PTR)ih; + menuiteminfo.hSubMenu = (HMENU)ih->firstchild->handle; + + if (!InsertMenuItem((HMENU)ih->parent->handle, pos, TRUE, &menuiteminfo)) + return IUP_ERROR; + + ih->handle = ih->parent->handle; /* gets the HMENU of the parent */ + + /* must update attributes since submenu is actually created after it is mapped */ + iupAttribUpdate(ih); + iupAttribUpdateFromParent(ih); + + winMenuUpdateBar(ih); + + return IUP_NOERROR; +} + +static int winMenuMapMethod(Ihandle* ih) +{ + MENUINFO menuinfo; + + if (iupMenuIsMenuBar(ih)) + { + /* top level menu used for MENU attribute in IupDialog (a menu bar) */ + + ih->handle = (InativeHandle*)CreateMenu(); + if (!ih->handle) + return IUP_ERROR; + + SetMenu(ih->parent->handle, (HMENU)ih->handle); + } + else + { + if (ih->parent) + { + /* parent is a submenu */ + + ih->handle = (InativeHandle*)CreatePopupMenu(); + if (!ih->handle) + return IUP_ERROR; + + if (winMenuAddParentSubmenu(ih->parent) == IUP_ERROR) + { + DestroyMenu((HMENU)ih->handle); + return IUP_ERROR; + } + } + else + { + /* top level menu used for IupPopup */ + + ih->handle = (InativeHandle*)CreatePopupMenu(); + if (!ih->handle) + return IUP_ERROR; + + iupAttribSetStr(ih, "_IUPWIN_POPUP_MENU", "1"); + } + } + + menuinfo.cbSize = sizeof(MENUINFO); + menuinfo.fMask = MIM_MENUDATA; + menuinfo.dwMenuData = (ULONG_PTR)ih; + + if (!iupAttribGetInherit(ih, "_IUPWIN_POPUP_MENU")) /* check in the top level menu using inheritance */ + { + menuinfo.fMask |= MIM_STYLE; + menuinfo.dwStyle = MNS_NOTIFYBYPOS; + } + + SetMenuInfo((HMENU)ih->handle, &menuinfo); + + winMenuUpdateBar(ih); + + return IUP_NOERROR; +} + +static void winMenuUnMapMethod(Ihandle* ih) +{ + if (iupMenuIsMenuBar(ih)) + SetMenu(ih->parent->handle, NULL); + + DestroyMenu((HMENU)ih->handle); /* DestroyMenu is recursive */ +} + +void iupdrvMenuInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = winMenuMapMethod; + ic->UnMap = winMenuUnMapMethod; + + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winMenuSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "MENUBGCOLOR", IUPAF_DEFAULT); +} + + +/*******************************************************************************************/ + + +static int winItemSetImageAttrib(Ihandle* ih, const char* value) +{ + HBITMAP hBitmapUnchecked, hBitmapChecked; + char* impress; + + if (ih->handle == (InativeHandle*)-1) /* check if submenu is actually created */ + return 1; + + hBitmapUnchecked = iupImageGetImage(value, ih, 0); + + impress = iupAttribGet(ih, "IMPRESS"); + if (impress) + hBitmapChecked = iupImageGetImage(impress, ih, 0); + else + hBitmapChecked = hBitmapUnchecked; + + SetMenuItemBitmaps((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND, hBitmapUnchecked, hBitmapChecked); + + winMenuUpdateBar(ih); + + return 1; +} + +static int winItemSetImpressAttrib(Ihandle* ih, const char* value) +{ + HBITMAP hBitmapUnchecked, hBitmapChecked; + + char *image = iupAttribGet(ih, "IMPRESS"); + hBitmapUnchecked = iupImageGetImage(image, ih, 0); + + if (value) + hBitmapChecked = iupImageGetImage(value, ih, 0); + else + hBitmapChecked = hBitmapUnchecked; + + SetMenuItemBitmaps((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND, hBitmapUnchecked, hBitmapChecked); + + winMenuUpdateBar(ih); + + return 1; +} + +static int winItemSetTitleAttrib(Ihandle* ih, const char* value) +{ + char *str; + MENUITEMINFO menuiteminfo; + + if (ih->handle == (InativeHandle*)-1) /* check if submenu is actually created */ + return 1; + + if (!value) + { + str = " "; + value = str; + } + else + str = iupMenuProcessTitle(ih, value); + + menuiteminfo.cbSize = sizeof(MENUITEMINFO); + menuiteminfo.fMask = MIIM_TYPE; + menuiteminfo.fType = MFT_STRING; + menuiteminfo.dwTypeData = str; + menuiteminfo.cch = strlen(str); + + SetMenuItemInfo((HMENU)ih->handle, (UINT)ih->serial, FALSE, &menuiteminfo); + + if (str != value) free(str); + + winMenuUpdateBar(ih); + + return 1; +} + +static int winItemSetTitleImageAttrib(Ihandle* ih, const char* value) +{ + HBITMAP hBitmap; + MENUITEMINFO menuiteminfo; + + if (ih->handle == (InativeHandle*)-1) /* check if submenu is actually created */ + return 1; + + hBitmap = iupImageGetImage(value, ih, 0); + + menuiteminfo.cbSize = sizeof(MENUITEMINFO); + menuiteminfo.fMask = MIIM_BITMAP; + menuiteminfo.hbmpItem = hBitmap; + + SetMenuItemInfo((HMENU)ih->handle, (UINT)ih->serial, FALSE, &menuiteminfo); + + winMenuUpdateBar(ih); + + return 1; +} + +static int winItemSetActiveAttrib(Ihandle* ih, const char* value) +{ + if (ih->handle == (InativeHandle*)-1) /* check if submenu is actually created */ + return 1; + + if (iupStrBoolean(value)) + EnableMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_ENABLED|MF_BYCOMMAND); + else + EnableMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_GRAYED|MF_BYCOMMAND); + + winMenuUpdateBar(ih); + + return 0; +} + +static char* winItemGetActiveAttrib(Ihandle* ih) +{ + if (ih->handle == (InativeHandle*)-1) /* check if submenu is actually created */ + return NULL; + + if (GetMenuState((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND) & MF_GRAYED) + return "NO"; + else + return "YES"; +} + +static int winItemSetValueAttrib(Ihandle* ih, const char* value) +{ + if (iupAttribGetBoolean(ih->parent, "RADIO")) + { + int last_pos, pos; + winMenuGetLastPos(ih, &last_pos, &pos); + CheckMenuRadioItem((HMENU)ih->handle, 0, last_pos, pos, MF_BYPOSITION); + } + else + { + if (iupStrBoolean(value)) + CheckMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_CHECKED|MF_BYCOMMAND); + else + CheckMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_UNCHECKED|MF_BYCOMMAND); + } + + winMenuUpdateBar(ih); + + return 0; +} + +static char* winItemGetValueAttrib(Ihandle* ih) +{ + if (GetMenuState((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND) & MF_CHECKED) + return "ON"; + else + return "OFF"; +} + +static int winItemMapMethod(Ihandle* ih) +{ + int pos; + MENUITEMINFO menuiteminfo; + + if (!ih->parent || !IsMenu((HMENU)ih->parent->handle)) + return IUP_ERROR; + + pos = IupGetChildPos(ih->parent, ih); + ih->serial = iupMenuGetChildId(ih); + + menuiteminfo.cbSize = sizeof(MENUITEMINFO); + menuiteminfo.fMask = MIIM_ID|MIIM_DATA|MIIM_STRING; + menuiteminfo.dwTypeData = ""; /* must set or it will be not possible to update */ + menuiteminfo.cch = 0; + menuiteminfo.wID = (UINT)ih->serial; + menuiteminfo.dwItemData = (ULONG_PTR)ih; + + if (!InsertMenuItem((HMENU)ih->parent->handle, pos, TRUE, &menuiteminfo)) + return IUP_ERROR; + + ih->handle = ih->parent->handle; /* gets the HMENU of the parent */ + winMenuUpdateBar(ih); + + return IUP_NOERROR; +} + +void iupdrvItemInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = winItemMapMethod; + ic->UnMap = winMenuChildUnMapMethod; + + /* Visual */ + iupClassRegisterAttribute(ic, "ACTIVE", winItemGetActiveAttrib, winItemSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "MENUBGCOLOR", IUPAF_DEFAULT); /* used by IupImage */ + + /* IupItem only */ + iupClassRegisterAttribute(ic, "VALUE", winItemGetValueAttrib, winItemSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TITLE", NULL, winItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TITLEIMAGE", NULL, winItemSetTitleImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE", NULL, winItemSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMPRESS", NULL, winItemSetImpressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* Used by iupdrvImageCreateImage */ + /* necessary because it uses an old HBITMAP solution */ + iupClassRegisterAttribute(ic, "FLAT_ALPHA", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); +} + + +/*******************************************************************************************/ + + +static int winSubmenuMapMethod(Ihandle* ih) +{ + if (!ih->parent || !IsMenu((HMENU)ih->parent->handle)) + return IUP_ERROR; + + return iupBaseTypeVoidMapMethod(ih); +} + +void iupdrvSubmenuInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = winSubmenuMapMethod; + + /* IupSubmenu only */ + iupClassRegisterAttribute(ic, "ACTIVE", winItemGetActiveAttrib, winItemSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "TITLE", NULL, winItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE", NULL, winItemSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "MENUBGCOLOR", IUPAF_DEFAULT); /* used by IupImage */ + + /* Used by iupdrvImageCreateImage */ + /* necessary because it uses an old HBITMAP solution */ + iupClassRegisterAttribute(ic, "FLAT_ALPHA", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); +} + + +/*******************************************************************************************/ + + +static int winSeparatorMapMethod(Ihandle* ih) +{ + int pos; + MENUITEMINFO menuiteminfo; + + if (!ih->parent || !IsMenu((HMENU)ih->parent->handle)) + return IUP_ERROR; + + pos = IupGetChildPos(ih->parent, ih); + ih->serial = iupMenuGetChildId(ih); + + menuiteminfo.cbSize = sizeof(MENUITEMINFO); + menuiteminfo.fMask = MIIM_FTYPE|MIIM_ID|MIIM_DATA; + menuiteminfo.fType = MFT_SEPARATOR; + menuiteminfo.wID = (UINT)ih->serial; + menuiteminfo.dwItemData = (ULONG_PTR)ih; + + if (!InsertMenuItem((HMENU)ih->parent->handle, pos, TRUE, &menuiteminfo)) + return IUP_ERROR; + + ih->handle = ih->parent->handle; /* gets the HMENU of the parent */ + winMenuUpdateBar(ih); + + return IUP_NOERROR; +} + +void iupdrvSeparatorInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = winSeparatorMapMethod; + ic->UnMap = winMenuChildUnMapMethod; +} diff --git a/iup/src/win/iupwin_messagedlg.c b/iup/src/win/iupwin_messagedlg.c new file mode 100755 index 0000000..63159aa --- /dev/null +++ b/iup/src/win/iupwin_messagedlg.c @@ -0,0 +1,105 @@ +/** \file + * \brief Windows IupMessageDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_dialog.h" + + +static void winMessageDlgHelpCallback(HELPINFO* HelpInfo) +{ + Ihandle* ih = (Ihandle*)HelpInfo->dwContextId; + Icallback cb = (Icallback)IupGetCallback(ih, "HELP_CB"); + if (cb && cb(ih) == IUP_CLOSE) + { + if (iupStrEqualNoCase(iupAttribGetStr(ih, "BUTTONS"), "OK")) /* only one button */ + EndDialog((HWND)HelpInfo->hItemHandle, IDOK); + else + EndDialog((HWND)HelpInfo->hItemHandle, IDCANCEL); + } +} + +static int winMessageDlgPopup(Ihandle* ih, int x, int y) +{ + InativeHandle* parent = iupDialogGetNativeParent(ih); + MSGBOXPARAMS MsgBoxParams; + int result, num_but = 2; + DWORD dwStyle = MB_TASKMODAL; + char *icon, *buttons; + (void)x; + (void)y; + + if (!parent) + parent = GetActiveWindow(); + + icon = iupAttribGetStr(ih, "DIALOGTYPE"); + if (iupStrEqualNoCase(icon, "ERROR")) + dwStyle |= MB_ICONERROR; + else if (iupStrEqualNoCase(icon, "WARNING")) + dwStyle |= MB_ICONWARNING; + else if (iupStrEqualNoCase(icon, "INFORMATION")) + dwStyle |= MB_ICONINFORMATION; + else if (iupStrEqualNoCase(icon, "QUESTION")) + dwStyle |= MB_ICONQUESTION; + + buttons = iupAttribGetStr(ih, "BUTTONS"); + if (iupStrEqualNoCase(buttons, "OKCANCEL")) + dwStyle |= MB_OKCANCEL; + else if (iupStrEqualNoCase(buttons, "YESNO")) + dwStyle |= MB_YESNO; + else + { + dwStyle |= MB_OK; + num_but = 1; + } + + if (IupGetCallback(ih, "HELP_CB")) + dwStyle |= MB_HELP; + + if (num_but == 2 && iupAttribGetInt(ih, "BUTTONDEFAULT") == 2) + dwStyle |= MB_DEFBUTTON2; + else + dwStyle |= MB_DEFBUTTON1; + + MsgBoxParams.cbSize = sizeof(MSGBOXPARAMS); + MsgBoxParams.hwndOwner = parent; + MsgBoxParams.hInstance = NULL; + MsgBoxParams.lpszText = iupAttribGet(ih, "VALUE"); + MsgBoxParams.lpszCaption = iupAttribGet(ih, "TITLE"); + MsgBoxParams.dwStyle = dwStyle; + MsgBoxParams.lpszIcon = NULL; + MsgBoxParams.dwContextHelpId = (DWORD_PTR)ih; + MsgBoxParams.lpfnMsgBoxCallback = (MSGBOXCALLBACK)winMessageDlgHelpCallback; + MsgBoxParams.dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT); + + result = MessageBoxIndirect(&MsgBoxParams); + if (result == 0) + { + iupAttribSetStr(ih, "BUTTONRESPONSE", NULL); + return IUP_ERROR; + } + + if (result == IDNO || result == IDCANCEL) + iupAttribSetStr(ih, "BUTTONRESPONSE", "2"); + else + iupAttribSetStr(ih, "BUTTONRESPONSE", "1"); + + return IUP_NOERROR; +} + +void iupdrvMessageDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = winMessageDlgPopup; +} + +/* +In Windows it will always sound a beep. The beep is different for each dialog type. +*/ diff --git a/iup/src/win/iupwin_open.c b/iup/src/win/iupwin_open.c new file mode 100755 index 0000000..7357cde --- /dev/null +++ b/iup/src/win/iupwin_open.c @@ -0,0 +1,124 @@ +/** \file + * \brief Windows Driver Core + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <windows.h> +#include <commctrl.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_globalattrib.h" + +#include "iupwin_drv.h" +#include "iupwin_info.h" +#include "iupwin_handle.h" +#include "iupwin_brush.h" +#include "iupwin_draw.h" + + +HINSTANCE iupwin_hinstance = 0; +int iupwin_comctl32ver6 = 0; + +void* iupdrvGetDisplay(void) +{ + return NULL; +} + +void iupwinShowLastError(void) +{ + int error = GetLastError(); + if (error) + { + LPVOID lpMsgBuf; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL); + MessageBox(NULL, (LPCTSTR)lpMsgBuf, "GetLastError:", MB_OK|MB_ICONERROR); + LocalFree(lpMsgBuf); + } +} + +static void winSetGlobalColor(int index, const char* name) +{ + COLORREF color = GetSysColor(index); + iupGlobalSetDefaultColorAttrib(name, (int)GetRValue(color), + (int)GetGValue(color), + (int)GetBValue(color)); +} + +int iupdrvOpen(int *argc, char ***argv) +{ + (void)argc; /* unused in the Windows driver */ + (void)argv; + + if (iupwinGetSystemMajorVersion() < 5) /* older than Windows 2000 */ + return IUP_ERROR; + + IupSetGlobal("DRIVER", "Win32"); + + { +#ifdef __MINGW32__ + /* MingW fails to create windows if using a console and HINSTANCE is not from the console */ + HWND win = GetConsoleWindow(); + if (win) + iupwin_hinstance = (HINSTANCE)GetWindowLongPtr(win, GWLP_HINSTANCE); + else +#endif + iupwin_hinstance = GetModuleHandle(NULL); + IupSetGlobal("HINSTANCE", (char*)iupwin_hinstance); + } + + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + { + INITCOMMONCONTROLSEX InitCtrls; + InitCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX); + InitCtrls.dwICC = ICC_WIN95_CLASSES; /* trackbar, tooltips, updown, tab, progress */ + InitCommonControlsEx(&InitCtrls); + } + + iupwin_comctl32ver6 = (iupwinGetComCtl32Version() >= 0x060000)? 1: 0; + if (iupwin_comctl32ver6 && !iupwinIsAppThemed()) /* When the user seleted the Windows Classic theme */ + iupwin_comctl32ver6 = 0; + + IupSetGlobal("SYSTEMLANGUAGE", iupwinGetSystemLanguage()); + + /* default colors */ + winSetGlobalColor(COLOR_BTNFACE, "DLGBGCOLOR"); + winSetGlobalColor(COLOR_BTNTEXT, "DLGFGCOLOR"); + winSetGlobalColor(COLOR_WINDOW, "TXTBGCOLOR"); + winSetGlobalColor(COLOR_WINDOWTEXT, "TXTFGCOLOR"); + winSetGlobalColor(COLOR_MENU, "MENUBGCOLOR"); + winSetGlobalColor(COLOR_MENUTEXT, "MENUFGCOLOR"); + + iupwinHandleInit(); + iupwinBrushInit(); + iupwinDrawInit(); + +#ifdef __WATCOMC__ + { + /* this is used to force Watcom to link the winmain.c module. */ + void iupwinMainDummy(void); + iupwinMainDummy(); + } +#endif + + return IUP_NOERROR; +} + +void iupdrvClose(void) +{ + iupwinHandleFinish(); + iupwinBrushFinish(); + + CoUninitialize(); +} diff --git a/iup/src/win/iupwin_progressbar.c b/iup/src/win/iupwin_progressbar.c new file mode 100755 index 0000000..9038d79 --- /dev/null +++ b/iup/src/win/iupwin_progressbar.c @@ -0,0 +1,164 @@ +/** \file + * \brief Progress bar Control + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> +#include <commctrl.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_progressbar.h" +#include "iup_drv.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" + + +#ifndef PBS_MARQUEE /* it is defined only when _WIN32_WINNT >= 0x0501 */ +#define PBS_MARQUEE 0x08 +#define PBM_SETMARQUEE (WM_USER+10) +#endif + +#define IUP_PB_MAX 32000 + + +static int winProgressBarSetMarqueeAttrib(Ihandle* ih, const char* value) +{ + /* MARQUEE only works when using XP Styles */ + if (!iupwin_comctl32ver6) + return 0; + + if (iupStrBoolean(value)) + SendMessage(ih->handle, PBM_SETMARQUEE, TRUE, 100); + else + SendMessage(ih->handle, PBM_SETMARQUEE, FALSE, 0); + + return 1; +} + +static int winProgressBarSetValueAttrib(Ihandle* ih, const char* value) +{ + if (!value) + ih->data->value = 0; + else + ih->data->value = atof(value); + + iProgressBarCropValue(ih); + + /* Shows when the marquee style is not set */ + if (!ih->data->marquee) + { + double factor = (ih->data->value - ih->data->vmin) / (ih->data->vmax - ih->data->vmin); + int val = (int)(IUP_PB_MAX * factor); + SendMessage(ih->handle, PBM_SETPOS, (WPARAM)val, 0); + } + + return 0; +} + +static int winProgressBarSetBgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + + /* Only works when using Classic style */ + if (iupwin_comctl32ver6) + return 0; + + if (iupStrToRGB(value, &r, &g, &b)) + { + COLORREF color = RGB(r,g,b); + SendMessage(ih->handle, PBM_SETBKCOLOR, 0, (LPARAM)color); + } + else + SendMessage(ih->handle, PBM_SETBKCOLOR, 0, (LPARAM)CLR_DEFAULT); + return 1; +} + +static int winProgressBarSetFgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + + /* Only works when using Classic style */ + if (iupwin_comctl32ver6) + return 0; + + if (iupStrToRGB(value, &r, &g, &b)) + { + COLORREF color = RGB(r,g,b); + SendMessage(ih->handle, PBM_SETBARCOLOR, 0, (LPARAM)color); + } + else + SendMessage(ih->handle, PBM_SETBARCOLOR, 0, (LPARAM)CLR_DEFAULT); + return 1; +} + +static int winProgressBarMapMethod(Ihandle* ih) +{ + DWORD dwStyle = WS_CHILD; + + if (!ih->parent) + return IUP_ERROR; + + if (iupStrEqualNoCase(iupAttribGetStr(ih, "ORIENTATION"), "VERTICAL")) + { + dwStyle |= PBS_VERTICAL; + + if (ih->currentheight < ih->currentwidth) + { + int tmp = ih->currentheight; + ih->currentheight = ih->currentwidth; + ih->currentwidth = tmp; + } + } + + if (!iupwin_comctl32ver6 && !iupAttribGetBoolean(ih, "DASHED")) + dwStyle |= PBS_SMOOTH; + + if (iupwin_comctl32ver6 && iupAttribGetBoolean(ih, "MARQUEE")) + { + dwStyle |= PBS_MARQUEE; + ih->data->marquee = 1; + } + + if (!iupwinCreateWindowEx(ih, PROGRESS_CLASS, 0, dwStyle)) + return IUP_ERROR; + + /* configure the native range */ + SendMessage(ih->handle, PBM_SETRANGE, 0, MAKELPARAM(0, IUP_PB_MAX)); + + return IUP_NOERROR; +} + +void iupdrvProgressBarInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = winProgressBarMapMethod; + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winProgressBarSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + /* Only works when using Classic style */ + if (iupwin_comctl32ver6) + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, winProgressBarSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + else + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED); + + /* IupProgressBar only */ + iupClassRegisterAttribute(ic, "VALUE", iProgressBarGetValueAttrib, winProgressBarSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ORIENTATION", NULL, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MARQUEE", NULL, winProgressBarSetMarqueeAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DASHED", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); +} diff --git a/iup/src/win/iupwin_tabs.c b/iup/src/win/iupwin_tabs.c new file mode 100755 index 0000000..682f451 --- /dev/null +++ b/iup/src/win/iupwin_tabs.c @@ -0,0 +1,680 @@ +/** \file +* \brief Tabs Control +* +* See Copyright Notice in "iup.h" +*/ + +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#include <windows.h> +#include <commctrl.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_stdcontrols.h" +#include "iup_tabs.h" +#include "iup_image.h" +#include "iup_array.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" +#include "iupwin_draw.h" +#include "iupwin_info.h" + + +int iupdrvTabsExtraDecor(Ihandle* ih) +{ + (void)ih; + return 0; +} + +int iupdrvTabsGetLineCountAttrib(Ihandle* ih) +{ + return (int)SendMessage(ih->handle, TCM_GETROWCOUNT, 0, 0); +} + +static HWND winTabsGetPageWindow(Ihandle* ih, int pos) +{ + TCITEM tie; + tie.mask = TCIF_PARAM; + SendMessage(ih->handle, TCM_GETITEM, pos, (LPARAM)&tie); + return (HWND)tie.lParam; +} + +void iupdrvTabsSetCurrentTab(Ihandle* ih, int pos) +{ + int prev_pos = SendMessage(ih->handle, TCM_GETCURSEL, 0, 0); + HWND tab_page = winTabsGetPageWindow(ih, prev_pos); + ShowWindow(tab_page, SW_HIDE); + + SendMessage(ih->handle, TCM_SETCURSEL, pos, 0); + + tab_page = winTabsGetPageWindow(ih, pos); + ShowWindow(tab_page, SW_SHOW); +} + +int iupdrvTabsGetCurrentTab(Ihandle* ih) +{ + return (int)SendMessage(ih->handle, TCM_GETCURSEL, 0, 0); +} + +static int winTabsGetImageIndex(Ihandle* ih, const char* name) +{ + HIMAGELIST image_list; + int count, i, bpp, ret; + Iarray* bmp_array; + HBITMAP *bmp_array_data, hMask=NULL; + HBITMAP bmp = iupImageGetImage(name, ih, 0); + if (!bmp) + return -1; + + /* the array is used to avoi adding the same bitmap twice */ + bmp_array = (Iarray*)iupAttribGet(ih, "_IUPWIN_BMPARRAY"); + if (!bmp_array) + { + /* create the array if does not exist */ + bmp_array = iupArrayCreate(50, sizeof(HBITMAP)); + iupAttribSetStr(ih, "_IUPWIN_BMPARRAY", (char*)bmp_array); + } + + bmp_array_data = iupArrayGetData(bmp_array); + + image_list = (HIMAGELIST)SendMessage(ih->handle, TCM_GETIMAGELIST, 0, 0); + if (!image_list) + { + int width, height; + UINT flags = ILC_COLOR32|ILC_MASK; + + /* must use this info, since image can be a driver image loaded from resources */ + iupdrvImageGetInfo(bmp, &width, &height, &bpp); + + /* create the image list if does not exist */ + image_list = ImageList_Create(width, height, flags, 0, 50); + SendMessage(ih->handle, TCM_SETIMAGELIST, 0, (LPARAM)image_list); + } + else + iupdrvImageGetInfo(bmp, NULL, NULL, &bpp); + + /* check if that bitmap is already added to the list, + but we can not compare with the actual bitmap at the list since it is a copy */ + count = ImageList_GetImageCount(image_list); + for (i=0; i<count; i++) + { + if (bmp_array_data[i] == bmp) + return i; + } + + if (bpp == 8) + { + Ihandle* image = IupGetHandle(name); + if (image) + { + iupAttribSetStr(image, "_IUPIMG_NO_INVERT", "1"); + hMask = iupdrvImageCreateMask(image); + iupAttribSetStr(image, "_IUPIMG_NO_INVERT", NULL); + } + } + + bmp_array_data = iupArrayInc(bmp_array); + bmp_array_data[i] = bmp; + ret = ImageList_Add(image_list, bmp, hMask); /* the bmp is duplicated at the list */ + DeleteObject(hMask); + return ret; +} + +static int winTabsGetPageWindowPos(Ihandle* ih, HWND tab_page) +{ + TCITEM tie; + int pos, num_tabs; + + num_tabs = (int)SendMessage(ih->handle, TCM_GETITEMCOUNT, 0, 0); + tie.mask = TCIF_PARAM; + + for (pos=0; pos<num_tabs; pos++) + { + SendMessage(ih->handle, TCM_GETITEM, pos, (LPARAM)&tie); + if (tab_page == (HWND)tie.lParam) + return pos; + } + + return -1; +} + +static void winTabsPlacePageWindows(Ihandle* ih, int w, int h) +{ + TCITEM tie; + int pos, num_tabs; + RECT rect; + + num_tabs = (int)SendMessage(ih->handle, TCM_GETITEMCOUNT, 0, 0); + tie.mask = TCIF_PARAM; + + /* Calculate the display rectangle, assuming the + tab control is the size of the client area. */ + SetRect(&rect, 0, 0, w, h); + SendMessage(ih->handle, TCM_ADJUSTRECT, FALSE, (LPARAM)&rect); + + for (pos=0; pos<num_tabs; pos++) + { + SendMessage(ih->handle, TCM_GETITEM, pos, (LPARAM)&tie); + + SetWindowPos((HWND)tie.lParam, NULL, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOACTIVATE|SWP_NOZORDER); + } +} + +static int winTabsUsingXPStyles(Ihandle* ih) +{ + return iupwin_comctl32ver6 && ih->data->type == ITABS_TOP; +} + +static void winTabsDrawPageBackground(Ihandle* ih, HDC hDC, RECT* rect) +{ + unsigned char r=0, g=0, b=0; + char* color = iupAttribGetInheritNativeParent(ih, "BGCOLOR"); + if (!color) color = iupAttribGetInheritNativeParent(ih, "BACKGROUND"); + if (!color) color = iupAttribGet(ih, "BACKGROUND"); + if (!color) color = IupGetGlobal("DLGBGCOLOR"); + iupStrToRGB(color, &r, &g, &b); + SetDCBrushColor(hDC, RGB(r,g,b)); + FillRect(hDC, rect, (HBRUSH)GetStockObject(DC_BRUSH)); +} + +static LRESULT CALLBACK winTabsPageWinProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) +{ + switch (msg) + { + case WM_ERASEBKGND: + { + RECT rect; + HDC hDC = (HDC)wp; + Ihandle* ih = iupwinHandleGet(hWnd); + GetClientRect(ih->handle, &rect); + winTabsDrawPageBackground(ih, hDC, &rect); + + /* return non zero value */ + return 1; + } + case WM_COMMAND: + case WM_CTLCOLORSCROLLBAR: + case WM_CTLCOLORBTN: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORSTATIC: + case WM_DRAWITEM: + case WM_HSCROLL: + case WM_NOTIFY: + case WM_VSCROLL: + /* Forward the container messages to its parent. */ + return SendMessage(GetParent(hWnd), msg, wp, lp); + } + + return DefWindowProc(hWnd, msg, wp, lp); +} + +static HWND winTabCreatePageWindow(Ihandle* ih) +{ + HWND hWnd; + DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS, + dwExStyle = 0; + + if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED")) + dwExStyle |= WS_EX_COMPOSITED; + else + dwStyle |= WS_CLIPCHILDREN; + + hWnd = CreateWindowEx(dwExStyle, "IupTabsPage", NULL, dwStyle, + 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, + ih->handle, NULL, iupwin_hinstance, NULL); + + iupwinHandleAdd(ih, hWnd); + + return hWnd; +} + +/* ------------------------------------------------------------------------- */ +/* winTabs - Sets and Gets accessors */ +/* ------------------------------------------------------------------------- */ + +static int winTabsSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + + if (ih->handle) + SendMessage(ih->handle, TCM_SETPADDING, 0, MAKELPARAM(ih->data->horiz_padding, ih->data->vert_padding)); + + return 0; +} + +static int winTabsSetMultilineAttrib(Ihandle* ih, const char* value) +{ + if (ih->handle) /* allow to set only before mapping */ + return 0; + + if (iupStrBoolean(value)) + ih->data->is_multiline = 1; + else + { + if (ih->data->type == ITABS_BOTTOM || ih->data->type == ITABS_TOP) + ih->data->is_multiline = 0; + else + ih->data->is_multiline = 1; /* always true if left/right */ + } + + return 0; +} + +static char* winTabsGetMultilineAttrib(Ihandle* ih) +{ + if (ih->data->is_multiline) + return "YES"; + else + return "NO"; +} + +static int winTabsSetTabTypeAttrib(Ihandle* ih, const char* value) +{ + if (ih->handle) /* allow to set only before mapping */ + return 0; + + if(iupStrEqualNoCase(value, "BOTTOM")) + { + ih->data->is_multiline = 0; + ih->data->type = ITABS_BOTTOM; + ih->data->orientation = ITABS_HORIZONTAL; + } + else if(iupStrEqualNoCase(value, "LEFT")) + { + ih->data->type = ITABS_LEFT; + ih->data->orientation = ITABS_VERTICAL; + ih->data->is_multiline = 1; /* VERTICAL works only with MULTILINE */ + } + else if(iupStrEqualNoCase(value, "RIGHT")) + { + ih->data->is_multiline = 1; /* VERTICAL works only with MULTILINE */ + ih->data->type = ITABS_RIGHT; + ih->data->orientation = ITABS_VERTICAL; + } + else /* "TOP" */ + { + ih->data->is_multiline = 0; + ih->data->type = ITABS_TOP; + ih->data->orientation = ITABS_HORIZONTAL; + } + + return 0; +} + +static int winTabsSetTabTitleAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int pos; + if (value && iupStrToInt(name_id, &pos)==1) + { + TCITEM tie; + + tie.mask = TCIF_TEXT; + tie.pszText = (char*)value; + tie.cchTextMax = strlen(value); + + SendMessage(ih->handle, TCM_SETITEM, pos, (LPARAM)&tie); + } + return 1; +} + +static int winTabsSetTabImageAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int pos; + if (value && iupStrToInt(name_id, &pos)==1) + { + TCITEM tie; + + tie.mask = TCIF_IMAGE; + tie.iImage = winTabsGetImageIndex(ih, value); + + SendMessage(ih->handle, TCM_SETITEM, pos, (LPARAM)&tie); + } + return 1; +} + +static char* winTabsGetBgColorAttrib(Ihandle* ih) +{ + /* the most important use of this is to provide + the correct background for images */ + if (iupwin_comctl32ver6) + { + COLORREF cr; + if (iupwinDrawGetThemeTabsBgColor(ih->handle, &cr)) + { + char* str = iupStrGetMemory(20); + sprintf(str, "%d %d %d", (int)GetRValue(cr), (int)GetGValue(cr), (int)GetBValue(cr)); + return str; + } + } + + return IupGetGlobal("DLGBGCOLOR"); +} + + +/* ------------------------------------------------------------------------- */ +/* winTabs - Calls the user callback to change of tab */ +/* ------------------------------------------------------------------------- */ + +static int winTabsCtlColor(Ihandle* ih, HDC hdc, LRESULT *result) +{ + /* works only when NOT winTabsUsingXPStyles */ + unsigned char r, g, b; + char* color = iupBaseNativeParentGetBgColorAttrib(ih); + if (iupStrToRGB(color, &r, &g, &b)) + { + SetDCBrushColor(hdc, RGB(r,g,b)); + *result = (LRESULT)GetStockObject(DC_BRUSH); + return 1; + } + return 0; +} + +static int winTabsWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) +{ + (void)result; + + if (msg_info->code == TCN_SELCHANGING) + { + IFnnn cb = (IFnnn)IupGetCallback(ih, "TABCHANGE_CB"); + int prev_pos = SendMessage(ih->handle, TCM_GETCURSEL, 0, 0); + iupAttribSetInt(ih, "_IUPTABS_PREV_CHILD_POS", prev_pos); + + if (cb) + { + Ihandle* prev_child = IupGetChild(ih, prev_pos); + iupAttribSetStr(ih, "_IUPTABS_PREV_CHILD", (char*)prev_child); + } + } + + if (msg_info->code == TCN_SELCHANGE) + { + IFnnn cb = (IFnnn)IupGetCallback(ih, "TABCHANGE_CB"); + int pos = SendMessage(ih->handle, TCM_GETCURSEL, 0, 0); + int prev_pos = iupAttribGetInt(ih, "_IUPTABS_PREV_CHILD_POS"); + HWND tab_page = winTabsGetPageWindow(ih, pos); + ShowWindow(tab_page, SW_SHOW); + tab_page = winTabsGetPageWindow(ih, prev_pos); + ShowWindow(tab_page, SW_HIDE); + + if (cb) + { + Ihandle* child = IupGetChild(ih, pos); + Ihandle* prev_child = (Ihandle*)iupAttribGet(ih, "_IUPTABS_PREV_CHILD"); + iupAttribSetStr(ih, "_IUPTABS_PREV_CHILD", NULL); + + cb(ih, child, prev_child); + } + } + + return 0; /* result not used */ +} + +static int winTabsProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + switch(msg) + { + case WM_SIZE: + { + WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB"); + CallWindowProc(oldProc, ih->handle, msg, wp, lp); + + winTabsPlacePageWindows(ih, LOWORD(lp), HIWORD(lp)); + + *result = 0; + return 1; + } + } + + return iupwinBaseContainerProc(ih, msg, wp, lp, result); +} + +/* ------------------------------------------------------------------------- */ +/* winTabs - Methods and Init Class */ +/* ------------------------------------------------------------------------- */ + +static void winTabsChildAddedMethod(Ihandle* ih, Ihandle* child) +{ + if (IupGetName(child) == NULL) + iupAttribSetHandleName(child); + + if (ih->handle) + { + TCITEM tie; + HWND tab_page; + char *tabtitle, *tabimage; + int pos, old_rowcount; + RECT rect; + + pos = IupGetChildPos(ih, child); + + tab_page = winTabCreatePageWindow(ih); + + if (pos == 0) + ShowWindow(tab_page, SW_SHOW); + + tabtitle = iupAttribGet(child, "TABTITLE"); + if (!tabtitle) tabtitle = iupTabsAttribGetStrId(ih, "TABTITLE", pos); + tabimage = iupAttribGet(child, "TABIMAGE"); + if (!tabimage) tabimage = iupTabsAttribGetStrId(ih, "TABIMAGE", pos); + if (!tabtitle && !tabimage) + tabtitle = " "; + + old_rowcount = (int)SendMessage(ih->handle, TCM_GETROWCOUNT, 0, 0); + + tie.mask = TCIF_PARAM; + + if (tabtitle) + { + tie.mask |= TCIF_TEXT; + tie.pszText = tabtitle; + tie.cchTextMax = strlen(tabtitle); + } + + if (tabimage) + { + tie.mask |= TCIF_IMAGE; + tie.iImage = winTabsGetImageIndex(ih, tabimage); + } + + /* create tabs and label them */ + tie.lParam = (LPARAM)tab_page; + SendMessage(ih->handle, TCM_INSERTITEM, pos, (LPARAM)&tie); + + /* Calculate the display rectangle, assuming the + tab control is the size of the client area. */ + GetClientRect(ih->handle, &rect); + SendMessage(ih->handle, TCM_ADJUSTRECT, FALSE, (LPARAM)&rect); + + SetWindowPos(tab_page, NULL, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOACTIVATE|SWP_NOZORDER); + + iupAttribSetStr(child, "_IUPTAB_CONTAINER", (char*)tab_page); + + if (ih->data->is_multiline) + { + if (ih->data->type == ITABS_LEFT || ih->data->type == ITABS_RIGHT) + { + int rowcount = (int)SendMessage(ih->handle, TCM_GETROWCOUNT, 0, 0); + if (rowcount != old_rowcount) + { + GetClientRect(ih->handle, &rect); + winTabsPlacePageWindows(ih, rect.right - rect.left, rect.bottom - rect.top); + } + } + + iupdrvDisplayRedraw(ih); + } + } +} + +static void winTabsChildRemovedMethod(Ihandle* ih, Ihandle* child) +{ + if (ih->handle) + { + HWND tab_page = (HWND)iupAttribGet(child, "_IUPTAB_CONTAINER"); + if (tab_page) + { + int pos = winTabsGetPageWindowPos(ih, tab_page); + SendMessage(ih->handle, TCM_DELETEITEM, pos, 0); + DestroyWindow(tab_page); + + if (pos==0) pos++; + iupdrvTabsSetCurrentTab(ih, pos-1); + + iupAttribSetStr(child, "_IUPTAB_CONTAINER", NULL); + } + } +} + +static int winTabsMapMethod(Ihandle* ih) +{ + DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | TCS_HOTTRACK | WS_TABSTOP, + dwExStyle = 0; + + if (!ih->parent) + return IUP_ERROR; + + if (ih->data->type == ITABS_BOTTOM) + dwStyle |= TCS_BOTTOM; + else if (ih->data->type == ITABS_RIGHT) + dwStyle |= TCS_VERTICAL|TCS_RIGHT; + else if (ih->data->type == ITABS_LEFT) + dwStyle |= TCS_VERTICAL; + + if (ih->data->is_multiline) + dwStyle |= TCS_MULTILINE; + + if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED")) + { + dwExStyle |= WS_EX_COMPOSITED; + + if (!ih->data->is_multiline && iupwinIsVista()) + { + /* workaround for composite bug in Vista */ + ih->data->is_multiline = 1; + dwStyle |= TCS_MULTILINE; + } + } + else + dwStyle |= WS_CLIPCHILDREN; + + if (!iupwinCreateWindowEx(ih, WC_TABCONTROL, dwExStyle, dwStyle)) + return IUP_ERROR; + + /* replace the WinProc to handle other messages */ + IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winTabsProc); + + /* Process WM_NOTIFY */ + IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winTabsWmNotify); + + /* Process background color */ + IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winTabsCtlColor); + + if (iupwin_comctl32ver6 && ih->data->type != ITABS_TOP) + { + /* XP Styles support only TABTYPE=TOP */ + iupwinDrawRemoveTheme(ih->handle); + } + + /* Change children background */ + if (winTabsUsingXPStyles(ih)) + { + char* color = iupAttribGetInheritNativeParent(ih, "BGCOLOR"); + if (!color) + color = iupAttribGetInheritNativeParent(ih, "BACKGROUND"); + if (!color) + { + COLORREF cr; + if (iupwinDrawGetThemeTabsBgColor(ih->handle, &cr)) + iupAttribSetStrf(ih, "BACKGROUND", "%d %d %d", (int)GetRValue(cr), (int)GetGValue(cr), (int)GetBValue(cr)); + } + } + + /* Create pages and tabs */ + if (ih->firstchild) + { + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + winTabsChildAddedMethod(ih, child); + } + + return IUP_NOERROR; +} + +static void winTabsUnMapMethod(Ihandle* ih) +{ + Iarray* bmp_array; + + HIMAGELIST image_list = (HIMAGELIST)SendMessage(ih->handle, TCM_GETIMAGELIST, 0, 0); + if (image_list) + ImageList_Destroy(image_list); + + bmp_array = (Iarray*)iupAttribGet(ih, "_IUPWIN_BMPARRAY"); + if (bmp_array) + iupArrayDestroy(bmp_array); + + iupdrvBaseUnMapMethod(ih); +} + +static void winTabsRegisterClass(void) +{ + WNDCLASS wndclass; + ZeroMemory(&wndclass, sizeof(WNDCLASS)); + + wndclass.hInstance = iupwin_hinstance; + wndclass.lpszClassName = "IupTabsPage"; + wndclass.lpfnWndProc = (WNDPROC)winTabsPageWinProc; + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.style = CS_PARENTDC; + wndclass.hbrBackground = NULL; /* remove the background to optimize redraw */ + + RegisterClass(&wndclass); +} + +void iupdrvTabsInitClass(Iclass* ic) +{ + if (!iupwinClassExist("IupTabsPage")) + winTabsRegisterClass(); + + /* Driver Dependent Class functions */ + ic->Map = winTabsMapMethod; + ic->UnMap = winTabsUnMapMethod; + ic->ChildAdded = winTabsChildAddedMethod; + ic->ChildRemoved = winTabsChildRemovedMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", winTabsGetBgColorAttrib, NULL, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_NOT_MAPPED); + + /* IupTabs only */ + iupClassRegisterAttribute(ic, "TABTYPE", iupTabsGetTabTypeAttrib, winTabsSetTabTypeAttrib, IUPAF_SAMEASSYSTEM, "TOP", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TABORIENTATION", iupTabsGetTabOrientationAttrib, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); /* can not be set, depends on TABTYPE in Windows */ + iupClassRegisterAttribute(ic, "MULTILINE", winTabsGetMultilineAttrib, winTabsSetMultilineAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TABTITLE", NULL, winTabsSetTabTitleAttrib, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TABIMAGE", NULL, winTabsSetTabImageAttrib, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, winTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); +} diff --git a/iup/src/win/iupwin_text.c b/iup/src/win/iupwin_text.c new file mode 100755 index 0000000..dfe489a --- /dev/null +++ b/iup/src/win/iupwin_text.c @@ -0,0 +1,1993 @@ +/** \file + * \brief Text Control + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> +#include <commctrl.h> +#include <richedit.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_mask.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_array.h" +#include "iup_text.h" +#include "iup_key.h" +#include "iup_dialog.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" + +/* Cygwin and MingW Win32api does not define these */ + +#ifndef PFN_ARABIC +#define PFN_ARABIC 2 +#define PFN_LCLETTER 3 +#define PFN_UCLETTER 4 +#define PFN_LCROMAN 5 +#define PFN_UCROMAN 6 +#endif + +#ifndef PFNS_PAREN +#define PFNS_PAREN 0x000 +#define PFNS_PARENS 0x100 +#define PFNS_PERIOD 0x200 +#define PFNS_PLAIN 0x300 +#define PFNS_NONUMBER 0x400 +#endif + +#ifndef CFM_BACKCOLOR +#define CFM_BACKCOLOR 0x04000000 +#define CFM_UNDERLINETYPE 0x00800000 +#define CFM_WEIGHT 0x00400000 +#define CFM_DISABLED 0x2000 +#define CFE_DISABLED CFM_DISABLED +#endif + +#ifndef CFU_UNDERLINEDOTTED +#define CFU_UNDERLINEDOTTED 4 +#define CFU_UNDERLINEDOUBLE 3 +#define CFU_UNDERLINE 1 +#define CFU_UNDERLINENONE 0 +#endif + +#ifndef SES_UPPERCASE +#define SES_UPPERCASE 512 +#define SES_LOWERCASE 1024 +#endif +/* End Cygwin/MingW */ + +#ifndef EM_SETCUEBANNER /* defined only if _WIN32_WINNT >= 0x501 */ +#define ECM_FIRST 0x1500 /* Edit control messages */ +#define EM_SETCUEBANNER (ECM_FIRST + 1) +#endif + +#define WM_CARET WM_APP+1 /* Custom IUP message */ + + +void iupdrvTextAddSpin(int *w, int h) +{ + *w += h; +} + +void iupdrvTextAddBorders(int *w, int *h) +{ + int border_size = 2*3; + (*w) += border_size; + (*h) += border_size; +} + +static void winTextParseParagraphFormat(Ihandle* formattag, PARAFORMAT2 *paraformat, int convert2twips) +{ + int val; + char* format; + + ZeroMemory(paraformat, sizeof(PARAFORMAT2)); + paraformat->cbSize = sizeof(PARAFORMAT2); + + format = iupAttribGet(formattag, "NUMBERING"); + if (format) + { + paraformat->dwMask |= PFM_NUMBERING; + + if (iupStrEqualNoCase(format, "BULLET")) + paraformat->wNumbering = PFN_BULLET; + else if (iupStrEqualNoCase(format, "ARABIC")) + paraformat->wNumbering = PFN_ARABIC; + else if (iupStrEqualNoCase(format, "LCLETTER")) + paraformat->wNumbering = PFN_LCLETTER; + else if (iupStrEqualNoCase(format, "UCLETTER")) + paraformat->wNumbering = PFN_UCLETTER; + else if (iupStrEqualNoCase(format, "LCROMAN")) + paraformat->wNumbering = PFN_LCROMAN; + else if (iupStrEqualNoCase(format, "UCROMAN")) + paraformat->wNumbering = PFN_UCROMAN; + else + paraformat->wNumbering = 0; /* "NONE" */ + + format = iupAttribGet(formattag, "NUMBERINGSTYLE"); + if (format) + { + paraformat->dwMask |= PFM_NUMBERINGSTYLE; + + if (iupStrEqualNoCase(format, "RIGHTPARENTESES")) + paraformat->wNumberingStyle = PFNS_PAREN; + else if (iupStrEqualNoCase(format, "PARENTESES")) + paraformat->wNumberingStyle = PFNS_PARENS; + else if (iupStrEqualNoCase(format, "PERIOD")) + paraformat->wNumberingStyle = PFNS_PERIOD; + else if (iupStrEqualNoCase(format, "NONUMBER")) + paraformat->wNumberingStyle = PFNS_NONUMBER; + else + paraformat->wNumberingStyle = PFNS_PLAIN; /* "NONE" */ + } + + format = iupAttribGet(formattag, "NUMBERINGTAB"); + if (format && iupStrToInt(format, &val)) + { + paraformat->dwMask |= PFM_NUMBERINGTAB; + paraformat->wNumberingTab = (WORD)(val*convert2twips); + } + } + + format = iupAttribGet(formattag, "INDENT"); + if (format && iupStrToInt(format, &val)) + { + paraformat->dwMask |= PFM_STARTINDENT|PFM_RIGHTINDENT|PFM_OFFSET; + paraformat->dxStartIndent = val*convert2twips; + + format = iupAttribGet(formattag, "INDENTRIGHT"); + if (format && iupStrToInt(format, &val)) + paraformat->dxRightIndent = val*convert2twips; + else + paraformat->dxRightIndent = paraformat->dxStartIndent; + + format = iupAttribGet(formattag, "INDENTOFFSET"); + if (format && iupStrToInt(format, &val)) + paraformat->dxOffset = val*convert2twips; + else + paraformat->dxOffset = 0; + } + + format = iupAttribGet(formattag, "ALIGNMENT"); + if (format) + { + paraformat->dwMask |= PFM_ALIGNMENT; + + if (iupStrEqualNoCase(format, "JUSTIFY")) + paraformat->wAlignment = PFA_JUSTIFY; + else if (iupStrEqualNoCase(format, "RIGHT")) + paraformat->wAlignment = PFA_RIGHT; + else if (iupStrEqualNoCase(format, "CENTER")) + paraformat->wAlignment = PFA_CENTER; + else + paraformat->wAlignment = PFA_LEFT; /* "LEFT" */ + } + + format = iupAttribGet(formattag, "TABSARRAY"); + if (format) + { + int pos, align, i = 0; + LONG tab; + char* str; + + paraformat->dwMask |= PFM_TABSTOPS; + + while (format) + { + str = iupStrCopyUntil((char**)&format, ' '); + if (!str) break; + pos = atoi(str)*convert2twips; + free(str); + + str = iupStrCopyUntil((char**)&format, ' '); + if (!str) break; + + if (iupStrEqualNoCase(str, "DECIMAL")) + align = 3; + else if (iupStrEqualNoCase(str, "RIGHT")) + align = 2; + else if (iupStrEqualNoCase(str, "CENTER")) + align = 1; + else /* "LEFT" */ + align = 0; + free(str); + + tab = (pos&0xFFF)|(align<<24); + paraformat->rgxTabs[i] = tab; + i++; + if (i == 32) break; + } + paraformat->cTabCount = (SHORT)i; + } + + format = iupAttribGet(formattag, "SPACEBEFORE"); + if (format && iupStrToInt(format, &val)) + { + paraformat->dwMask |= PFM_SPACEBEFORE; + paraformat->dySpaceBefore = val*convert2twips; + } + + format = iupAttribGet(formattag, "SPACEAFTER"); + if (format && iupStrToInt(format, &val)) + { + paraformat->dwMask |= PFM_SPACEAFTER; + paraformat->dySpaceAfter = val*convert2twips; + } + + format = iupAttribGet(formattag, "LINESPACING"); + if (format) + { + paraformat->dwMask |= PFM_LINESPACING; + + if (iupStrEqualNoCase(format, "SINGLE")) + paraformat->bLineSpacingRule = 0; + else if (iupStrEqualNoCase(format, "ONEHALF")) + paraformat->bLineSpacingRule = 1; + else if (iupStrEqualNoCase(format, "DOUBLE")) + paraformat->bLineSpacingRule = 2; + else if (iupStrToInt(format, &val)) + { + paraformat->bLineSpacingRule = 3; + paraformat->dyLineSpacing = val*convert2twips; + } + } +} + +static void winTextParseCharacterFormat(Ihandle* formattag, CHARFORMAT2 *charformat, int pixel2twips) +{ + int val; + char* format; + + ZeroMemory(charformat, sizeof(CHARFORMAT2)); + charformat->cbSize = sizeof(CHARFORMAT2); + + format = iupAttribGet(formattag, "DISABLED"); + if (format) + { + charformat->dwMask |= CFM_DISABLED; + if (iupStrBoolean(format)) + charformat->dwEffects |= CFE_DISABLED; + } + + format = iupAttribGet(formattag, "RISE"); + if (format) + { + if (iupStrEqualNoCase(format, "SUPERSCRIPT")) + { + charformat->dwMask |= CFM_SUPERSCRIPT; + charformat->dwEffects |= CFE_SUPERSCRIPT; + } + else if (iupStrEqualNoCase(format, "SUBSCRIPT")) + { + charformat->dwMask |= CFM_SUBSCRIPT; + charformat->dwEffects |= CFE_SUBSCRIPT; + } + else if (iupStrToInt(format, &val)) + { + charformat->dwMask |= CFM_OFFSET; + charformat->yOffset = val; + } + } + + format = iupAttribGet(formattag, "ITALIC"); + if (format) + { + charformat->dwMask |= CFM_ITALIC; + if (iupStrBoolean(format)) + charformat->dwEffects |= CFE_ITALIC; + } + + format = iupAttribGet(formattag, "STRIKEOUT"); + if (format) + { + charformat->dwMask |= CFM_STRIKEOUT; + if (iupStrBoolean(format)) + charformat->dwEffects |= CFE_STRIKEOUT; + } + + format = iupAttribGet(formattag, "PROTECTED"); + if (format) + { + charformat->dwMask |= CFM_PROTECTED; + if (iupStrBoolean(format)) + charformat->dwEffects |= CFE_PROTECTED; + } + + format = iupAttribGet(formattag, "FONTSIZE"); + if (format && iupStrToInt(format, &val)) + { + /* (1/1440 of an inch, or 1/20 of a printer's point) */ + charformat->dwMask |= CFM_SIZE; + if (val < 0) /* in pixels */ + charformat->yHeight = (-val)*pixel2twips; + else + charformat->yHeight = val*20; + } + + format = iupAttribGet(formattag, "FONTSCALE"); + if (format && charformat->yHeight != 0) + { + float fval = 0; + if (iupStrEqualNoCase(format, "XX-SMALL")) + fval = 0.5787037037037f; + else if (iupStrEqualNoCase(format, "X-SMALL")) + fval = 0.6444444444444f; + else if (iupStrEqualNoCase(format, "SMALL")) + fval = 0.8333333333333f; + else if (iupStrEqualNoCase(format, "MEDIUM")) + fval = 1.0f; + else if (iupStrEqualNoCase(format, "LARGE")) + fval = 1.2f; + else if (iupStrEqualNoCase(format, "X-LARGE")) + fval = 1.4399999999999f; + else if (iupStrEqualNoCase(format, "XX-LARGE")) + fval = 1.728f; + else + iupStrToFloat(format, &fval); + + if (fval > 0) + { + fval = ((float)charformat->yHeight)*fval; + charformat->yHeight = iupROUND(fval); + } + } + + format = iupAttribGet(formattag, "FONTFACE"); + if (format) + { + charformat->dwMask |= CFM_FACE; + strcpy(charformat->szFaceName, format); + } + + format = iupAttribGet(formattag, "FGCOLOR"); + if (format) + { + unsigned char r, g, b; + if (iupStrToRGB(format, &r, &g, &b)) + { + charformat->dwMask |= CFM_COLOR; + charformat->crTextColor = RGB(r, g, b); + } + } + + format = iupAttribGet(formattag, "BGCOLOR"); + if (format) + { + unsigned char r, g, b; + if (iupStrToRGB(format, &r, &g, &b)) + { + charformat->dwMask |= CFM_BACKCOLOR; + charformat->crBackColor = RGB(r, g, b); + } + } + + format = iupAttribGet(formattag, "UNDERLINE"); + if (format) + { + charformat->dwMask |= CFM_UNDERLINETYPE; + + if (iupStrEqualNoCase(format, "SINGLE")) + charformat->bUnderlineType = CFU_UNDERLINE; + else if (iupStrEqualNoCase(format, "DOUBLE")) + charformat->bUnderlineType = CFU_UNDERLINEDOUBLE; + else if (iupStrEqualNoCase(format, "DOTTED")) + charformat->bUnderlineType = CFU_UNDERLINEDOTTED; + else /* "NONE" */ + charformat->bUnderlineType = CFU_UNDERLINENONE; + + if (charformat->bUnderlineType != CFU_UNDERLINENONE) + { + charformat->dwMask |= CFM_UNDERLINE; + charformat->dwEffects |= CFE_UNDERLINE; + } + } + + format = iupAttribGet(formattag, "WEIGHT"); + if (format) + { + charformat->dwMask |= CFM_WEIGHT; + + if (iupStrEqualNoCase(format, "EXTRALIGHT")) + charformat->wWeight = FW_EXTRALIGHT; + else if (iupStrEqualNoCase(format, "LIGHT")) + charformat->wWeight = FW_LIGHT; + else if (iupStrEqualNoCase(format, "SEMIBOLD")) + charformat->wWeight = FW_SEMIBOLD; + else if (iupStrEqualNoCase(format, "BOLD")) + charformat->wWeight = FW_BOLD; + else if (iupStrEqualNoCase(format, "EXTRABOLD")) + charformat->wWeight = FW_EXTRABOLD; + else if (iupStrEqualNoCase(format, "HEAVY")) + charformat->wWeight = FW_HEAVY; + else /* "NORMAL" */ + charformat->wWeight = FW_NORMAL; + + if (charformat->wWeight != FW_NORMAL) + { + charformat->dwMask |= CFM_BOLD; + charformat->dwEffects |= CFE_BOLD; + } + } +} + +static int winTextSetLinColToPosition(Ihandle *ih, int lin, int col) +{ + int linmax, colmax, lineindex; + + lin--; /* IUP starts at 1 */ + col--; + + linmax = SendMessage(ih->handle, EM_GETLINECOUNT, 0, 0L); + if (lin > linmax) + lin = linmax; + + lineindex = SendMessage(ih->handle, EM_LINEINDEX, (WPARAM)lin, 0L); + + colmax = SendMessage(ih->handle, EM_LINELENGTH, (WPARAM)lineindex, 0L); + if (col > colmax) + col = colmax; /* after the last character */ + + return lineindex + col; +} + +static void winTextGetLinColFromPosition(Ihandle* ih, int pos, int* lin, int* col) +{ + /* here "pos" must contains the extra chars if the case */ + int lineindex; + + if (ih->data->has_formatting) + *lin = SendMessage(ih->handle, EM_EXLINEFROMCHAR, (WPARAM)0, (LPARAM)pos); + else + *lin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L); + + lineindex = SendMessage(ih->handle, EM_LINEINDEX, (WPARAM)(*lin), (LPARAM)0L); + *col = pos - lineindex; /* lineindex is at the first character of the line */ + + (*lin)++; /* IUP starts at 1 */ + (*col)++; +} + +static int winTextRemoveExtraChars(Ihandle* ih, int pos) +{ + /* called only if not single line and not formatting */ + int lin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L); + pos -= lin; /* remove \r characters from count */ + return pos; +} + +static int winTextAddExtraChars(Ihandle* ih, int pos) +{ + /* called only if not single line and not formatting */ + int lin, clin; + + clin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L); + + /* pos is smaller than the actual pos (missing the \r count), + so we must calculate the line until the returned value is the same as the expected. */ + do + { + lin = clin; + clin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)(pos+lin+1), (LPARAM)0L); /* add one because we can be at the last character */ + } while (clin != lin); /* and it will not change to the next line by 1 */ + + pos += lin; /* add \r characters from count */ + return pos; +} + +static int winTextGetCaretPos(Ihandle* ih) +{ + int pos = 0; + POINT point; + + if (GetFocus() != ih->handle || !GetCaretPos(&point)) + { + /* if does not have the focus, or could not get caret position, + then use the selection start position */ + SendMessage(ih->handle, EM_GETSEL, (WPARAM)&pos, 0); + } + else + { + if (ih->data->has_formatting) + pos = SendMessage(ih->handle, EM_CHARFROMPOS, 0, (LPARAM)&point); + else + { + LRESULT ret; + + /* Workaround for weird behavior because of the return value in GetCaretPos */ + if (ih->data->is_multiline && point.y < 5) + point.y += 5; + + ret = SendMessage(ih->handle, EM_CHARFROMPOS, 0, MAKELPARAM(point.x, point.y)); + pos = LOWORD(ret); + } + } + + return pos; +} + +static int winTextGetCaret(Ihandle* ih, int *lin, int *col) +{ + int pos = winTextGetCaretPos(ih); + + if (ih->data->is_multiline) + { + winTextGetLinColFromPosition(ih, pos, lin, col); + + if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + pos = winTextRemoveExtraChars(ih, pos); + } + else + { + *col = pos; + (*col)++; /* IUP starts at 1 */ + *lin = 1; + } + + return pos; +} + +static void winTextGetSelection(Ihandle* ih, int *start, int *end) +{ + *start = 0; + *end = 0; + + SendMessage(ih->handle, EM_GETSEL, (WPARAM)start, (LPARAM)end); + + if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + { + (*start) = winTextRemoveExtraChars(ih, *start); + (*end) = winTextRemoveExtraChars(ih, *end); + } +} + +void iupdrvTextConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos) +{ + *pos = winTextSetLinColToPosition(ih, lin, col); + + if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + *pos = winTextRemoveExtraChars(ih, *pos); +} + +void iupdrvTextConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col) +{ + if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + pos = winTextAddExtraChars(ih, pos); + + winTextGetLinColFromPosition(ih, pos, lin, col); +} + +static int winTextConvertXYToPos(Ihandle* ih, int x, int y) +{ + int pos; + + if (ih->data->has_formatting) + { + POINT point; + point.x = x; + point.y = y; + pos = (int)SendMessage(ih->handle, EM_CHARFROMPOS, 0, (LPARAM)&point); + } + else + { + LRESULT ret = SendMessage(ih->handle, EM_CHARFROMPOS, 0, MAKELPARAM(x, y)); + pos = LOWORD(ret); + } + + if (ih->data->is_multiline) + { + if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + pos = winTextRemoveExtraChars(ih, pos); + } + + return pos; +} + + +/***********************************************************************************************/ + + +static int winTextSetValueAttrib(Ihandle* ih, const char* value) +{ + char* str; + if (!value) value = ""; + str = (char*)value; + if (ih->data->is_multiline) + { + if (ih->data->has_formatting) + str = iupStrToMac(str); + else + str = iupStrToDos(str); + } + iupAttribSetStr(ih, "IUPWIN_IGNORECHANGE", "1"); + SetWindowText(ih->handle, str); + iupAttribSetStr(ih, "IUPWIN_IGNORECHANGE", NULL); + if (str != value) free(str); + return 0; +} + +static char* winTextGetValueAttrib(Ihandle* ih) +{ + int nc = GetWindowTextLength(ih->handle); + if (nc) + { + char* str = iupStrGetMemory(nc+1); + GetWindowText(ih->handle, str, nc+1); /* notice that this function always returns in DOS format */ + if (ih->data->is_multiline) + iupStrToUnix(str); + return str; + } + else + return ""; +} + +static int winTextSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &(ih->data->horiz_padding), &(ih->data->vert_padding), 'x'); + ih->data->vert_padding = 0; + if (ih->handle) + SendMessage(ih->handle, EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN, MAKELPARAM(ih->data->horiz_padding, ih->data->horiz_padding)); + return 0; +} + +static int winTextSetSelectedTextAttrib(Ihandle* ih, const char* value) +{ + if (value) + { + int start = 0, end = 0; + char* str; + + SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); + if (start == end) + return 0; + + str = (char*)value; + if (ih->data->is_multiline) + { + if (ih->data->has_formatting) + str = iupStrToMac(str); + else + str = iupStrToDos(str); + } + SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)str); + if (str != value) free(str); + } + return 0; +} + +static char* winTextGetSelectedTextAttrib(Ihandle* ih) +{ + int nc = GetWindowTextLength(ih->handle); + if (nc) + { + int start = 0, end = 0; + char* str; + + SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); + if (start == end) + return NULL; + + if (ih->data->has_formatting) + { + str = iupStrGetMemory(end-start+1); + SendMessage(ih->handle, EM_GETSELTEXT, 0, (LPARAM)str); + } + else + { + str = iupStrGetMemory(nc+1); + GetWindowText(ih->handle, str, nc+1); /* notice that this function always returns in DOS format */ + /* returns only the selected text */ + str[end] = 0; + str += start; + } + + if (ih->data->is_multiline) + iupStrToUnix(str); + return str; + } + else + return NULL; +} + +static int winTextSetNCAttrib(Ihandle* ih, const char* value) +{ + if (!iupStrToInt(value, &ih->data->nc)) + ih->data->nc = 0; + + if (ih->handle) + { + if (ih->data->has_formatting) + SendMessage(ih->handle, EM_EXLIMITTEXT, 0, ih->data->nc); /* so it can be larger than 64k */ + else + SendMessage(ih->handle, EM_LIMITTEXT, ih->data->nc, 0L); + } + return 0; +} + +static int winTextSetSelectionAttrib(Ihandle* ih, const char* value) +{ + int start=1, end=1; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + SendMessage(ih->handle, EM_SETSEL, (WPARAM)-1, (LPARAM)0); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + SendMessage(ih->handle, EM_SETSEL, (WPARAM)0, (LPARAM)-1); + return 0; + } + + if (ih->data->is_multiline) + { + int lin_start=1, col_start=1, lin_end=1, col_end=1; + + if (sscanf(value, "%d,%d:%d,%d", &lin_start, &col_start, &lin_end, &col_end)!=4) return 0; + if (lin_start<1 || col_start<1 || lin_end<1 || col_end<1) return 0; + + start = winTextSetLinColToPosition(ih, lin_start, col_start); + end = winTextSetLinColToPosition(ih, lin_end, col_end); + } + else + { + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<1 || end<1) + return 0; + + start--; /* IUP starts at 1 */ + end--; + } + + SendMessage(ih->handle, EM_SETSEL, (WPARAM)start, (LPARAM)end); + + return 0; +} + +static char* winTextGetSelectionAttrib(Ihandle* ih) +{ + int start = 0, end = 0; + char* str; + + SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); + if (start == end) + return NULL; + + str = iupStrGetMemory(100); + + if (ih->data->is_multiline) + { + int start_col, start_lin, end_col, end_lin; + winTextGetLinColFromPosition(ih, start, &start_lin, &start_col); + winTextGetLinColFromPosition(ih, end, &end_lin, &end_col); + sprintf(str,"%d,%d:%d,%d", start_lin, start_col, end_lin, end_col); + } + else + { + start++; /* IUP starts at 1 */ + end++; + sprintf(str, "%d:%d", start, end); + } + + return str; +} + +static int winTextSetSelectionPosAttrib(Ihandle* ih, const char* value) +{ + int start=0, end=0; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + SendMessage(ih->handle, EM_SETSEL, (WPARAM)-1, (LPARAM)0); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + SendMessage(ih->handle, EM_SETSEL, (WPARAM)0, (LPARAM)-1); + return 0; + } + + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<0 || end<0) + return 0; + + if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + { + start = winTextAddExtraChars(ih, start); + end = winTextAddExtraChars(ih, end); + } + + SendMessage(ih->handle, EM_SETSEL, (WPARAM)start, (LPARAM)end); + + return 0; +} + +static char* winTextGetSelectionPosAttrib(Ihandle* ih) +{ + int start = 0, end = 0; + char* str; + + SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); + if (start == end) + return NULL; + + if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + { + start = winTextRemoveExtraChars(ih, start); + end = winTextRemoveExtraChars(ih, end); + } + + str = iupStrGetMemory(100); + + sprintf(str, "%d:%d", start, end); + + return str; +} + +static int winTextSetInsertAttrib(Ihandle* ih, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + if (value) + { + char* str = (char*)value; + if (ih->data->is_multiline) + { + if (ih->data->has_formatting) + str = iupStrToMac(str); + else + str = iupStrToDos(str); + } + + SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)str); + + if (str != value) free(str); + } + return 0; +} + +static int winTextSetAppendAttrib(Ihandle* ih, const char* value) +{ + int len; + char* str; + if (!ih->handle) /* do not store the action before map */ + return 0; + if (!value) value = ""; + str = (char*)value; + if (ih->data->is_multiline) + { + if (ih->data->has_formatting) + str = iupStrToMac(str); + else + str = iupStrToDos(str); + } + + len = GetWindowTextLength(ih->handle)+1; + SendMessage(ih->handle, EM_SETSEL, (WPARAM)len, (LPARAM)len); + if (ih->data->is_multiline && ih->data->append_newline) + { + if (ih->data->has_formatting) + SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)"\r"); + else + SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)"\r\n"); + } + SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)str); + + if (str != value) free(str); + return 0; +} + +static int winTextSetReadOnlyAttrib(Ihandle* ih, const char* value) +{ + SendMessage(ih->handle, EM_SETREADONLY, (WPARAM)iupStrBoolean(value), 0); + return 0; +} + +static char* winTextGetReadOnlyAttrib(Ihandle* ih) +{ + DWORD style = GetWindowLong(ih->handle, GWL_STYLE); + if (style & ES_READONLY) + return "YES"; + else + return "NO"; +} + +static int winTextSetTabSizeAttrib(Ihandle* ih, const char* value) +{ + int tabsize; + if (!ih->data->is_multiline) + return 0; + + iupStrToInt(value, &tabsize); + tabsize *= 4; + SendMessage(ih->handle, EM_SETTABSTOPS, (WPARAM)1L, (LPARAM)&tabsize); + iupdrvDisplayRedraw(ih); + return 1; +} + +static int winTextSetCaretAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + + if (!value) + return 0; + + if (ih->data->is_multiline) + { + int lin = 1, col = 1; + iupStrToIntInt(value, &lin, &col, ','); /* be permissive in SetCaret, do not abort if invalid */ + if (lin < 1) lin = 1; + if (col < 1) col = 1; + + pos = winTextSetLinColToPosition(ih, lin, col); + } + else + { + sscanf(value,"%i",&pos); + if (pos < 1) pos = 1; + pos--; /* IUP starts at 1 */ + } + + SendMessage(ih->handle, EM_SETSEL, (WPARAM)pos, (LPARAM)pos); + SendMessage(ih->handle, EM_SCROLLCARET, 0L, 0L); + + return 0; +} + +static char* winTextGetCaretAttrib(Ihandle* ih) +{ + int col, lin; + char* str; + + str = iupStrGetMemory(100); + + winTextGetCaret(ih, &lin, &col); + + if (ih->data->is_multiline) + sprintf(str, "%d,%d", lin, col); + else + sprintf(str, "%d", col); + + return str; +} + +static int winTextSetCaretPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); /* be permissive in SetCaret, do not abort if invalid */ + if (pos < 0) pos = 0; + + if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + pos = winTextAddExtraChars(ih, pos); + + SendMessage(ih->handle, EM_SETSEL, (WPARAM)pos, (LPARAM)pos); + SendMessage(ih->handle, EM_SCROLLCARET, 0L, 0L); + + return 0; +} + +static char* winTextGetCaretPosAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(100); + int pos = winTextGetCaretPos(ih); + if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + pos = winTextRemoveExtraChars(ih, pos); + sprintf(str, "%d", pos); + return str; +} + +static int winTextSetScrollToAttrib(Ihandle* ih, const char* value) +{ + int lin = 1, col = 1; + + if (!value) + return 0; + + if (ih->data->is_multiline) + { + iupStrToIntInt(value, &lin, &col, ','); + if (lin < 1) lin = 1; + if (col < 1) col = 1; + } + else + { + sscanf(value,"%i",&col); + if (col < 1) col = 1; + } + + lin--; /* return to Windows referece */ + col--; + + if (ih->data->has_formatting) + SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)0, (LPARAM)lin); + else + SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)col, (LPARAM)lin); + + return 0; +} + +static int winTextSetScrollToPosAttrib(Ihandle* ih, const char* value) +{ + int lin, col, pos = 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + pos = winTextAddExtraChars(ih, pos); + + winTextGetLinColFromPosition(ih, pos, &lin, &col); + lin--; /* return to Windows referece */ + col--; + + if (ih->data->has_formatting) + SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)0, (LPARAM)lin); + else + SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)col, (LPARAM)lin); + + return 0; +} + +static int winTextSetFilterAttrib(Ihandle *ih, const char *value) +{ + int style = 0; + + if (iupStrEqualNoCase(value, "LOWERCASE")) + { + if (ih->data->has_formatting) + { + SendMessage(ih->handle, EM_SETEDITSTYLE, SES_LOWERCASE, SES_LOWERCASE); + return 1; + } + style = ES_LOWERCASE; + } + else if (iupStrEqualNoCase(value, "NUMBER")) + style = ES_NUMBER; + else if (iupStrEqualNoCase(value, "UPPERCASE")) + { + if (ih->data->has_formatting) + { + SendMessage(ih->handle, EM_SETEDITSTYLE, SES_UPPERCASE, SES_UPPERCASE); + return 1; + } + style = ES_UPPERCASE; + } + + if (style) + iupwinMergeStyle(ih, ES_LOWERCASE|ES_NUMBER|ES_UPPERCASE, style); + + return 1; +} + +static int winTextSetClipboardAttrib(Ihandle *ih, const char *value) +{ + UINT msg = 0; + + if (iupStrEqualNoCase(value, "COPY")) + msg = WM_COPY; + else if (iupStrEqualNoCase(value, "CUT")) + msg = WM_CUT; + else if (iupStrEqualNoCase(value, "PASTE")) + msg = WM_PASTE; + else if (iupStrEqualNoCase(value, "CLEAR")) + msg = WM_CLEAR; + else if (iupStrEqualNoCase(value, "UNDO")) + msg = WM_UNDO; + else if (ih->data->has_formatting && iupStrEqualNoCase(value, "REDO")) + msg = EM_REDO; + + if (msg) + SendMessage(ih->handle, msg, 0, 0); + + return 0; +} + +static int winTextSetBgColorAttrib(Ihandle *ih, const char *value) +{ + if (ih->data->has_formatting) + { + unsigned char r, g, b; + if (iupStrToRGB(value, &r, &g, &b)) + { + COLORREF color; + color = RGB(r,g,b); + SendMessage(ih->handle, EM_SETBKGNDCOLOR, 0, (LPARAM)color); + } + } + return 1; +} + +static int winTextSetCueBannerAttrib(Ihandle *ih, const char *value) +{ + if (!ih->data->is_multiline && iupwin_comctl32ver6) + { + WCHAR* wstr = iupwinStrChar2Wide(value); + SendMessage(ih->handle, EM_SETCUEBANNER, (WPARAM)FALSE, (LPARAM)wstr); + free(wstr); + return 1; + } + return 0; +} + +static int winTextSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + int new_style; + + if (iupStrEqualNoCase(value, "ARIGHT")) + new_style = ES_RIGHT; + else if (iupStrEqualNoCase(value, "ACENTER")) + new_style = ES_CENTER; + else /* "ALEFT" */ + new_style = ES_LEFT; + + iupwinMergeStyle(ih, ES_LEFT|ES_CENTER|ES_RIGHT, new_style); + + return 1; +} + +static int winTextSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + /* ignore the first call that is done in IupMap, + it is already done before calling iupTextUpdateFormatTags. */ + if (ih->data->has_formatting && iupAttribGet(ih, "_IUPWIN_IGNORE_FONT")) + { + iupAttribSetStr(ih, "_IUPWIN_IGNORE_FONT", NULL); + return 0; + } + return iupdrvSetStandardFontAttrib(ih, value); +} + +void iupdrvTextAddFormatTag(Ihandle* ih, Ihandle* formattag) +{ + int convert2twips, pixel2twips; + char *selection, *units; + PARAFORMAT2 paraformat; + CHARFORMAT2 charformat; + + /* one twip is 1/1440 inch */ + /* twip = (pixel*1440)/(pixel/inch) */ + pixel2twips = 1440/iupwinGetScreenRes(); + + /* default is PIXELS */ + convert2twips = pixel2twips; + units = iupAttribGet(formattag, "UNITS"); + if (units) + { + int val; + if (iupStrEqualNoCase(units, "TWIPS")) + convert2twips = 1; + else if (iupStrToInt(units, &val)) + convert2twips = val; + } + + selection = iupAttribGet(formattag, "SELECTION"); + if (selection) + { + /* In Windows, the format message use the current selection */ + winTextSetSelectionAttrib(ih, selection); + iupAttribSetStr(ih, "SELECTION", NULL); + } + else + { + char* selectionpos = iupAttribGet(formattag, "SELECTIONPOS"); + if (selectionpos) + { + /* In Windows, the format message use the current selection */ + winTextSetSelectionPosAttrib(ih, selectionpos); + iupAttribSetStr(ih, "SELECTIONPOS", NULL); + } + } + + if (iupAttribGet(formattag, "FONTSCALE") && !iupAttribGet(formattag, "FONTSIZE")) + iupAttribSetStr(formattag, "FONTSIZE", iupGetFontSizeAttrib(ih)); + + winTextParseParagraphFormat(formattag, ¶format, convert2twips); + if (paraformat.dwMask != 0) + SendMessage(ih->handle, EM_SETPARAFORMAT, 0, (LPARAM)¶format); + + winTextParseCharacterFormat(formattag, &charformat, pixel2twips); + if (charformat.dwMask != 0) + SendMessage(ih->handle, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charformat); + + /* reset the selection, if changed here */ + if (selection) + winTextSetSelectionAttrib(ih, NULL); +} + +static int winTextSetRemoveFormattingAttrib(Ihandle* ih, const char* value) +{ + PARAFORMAT2 paraformat; + CHARFORMAT2 charformat; + COLORREF colorref; + int val; + + if (!ih->data->has_formatting) + return 0; + + ZeroMemory(¶format, sizeof(PARAFORMAT2)); + paraformat.cbSize = sizeof(PARAFORMAT2); + paraformat.dwMask = PFM_NUMBERING|PFM_STARTINDENT|PFM_RIGHTINDENT|PFM_OFFSET| + PFM_ALIGNMENT|PFM_SPACEBEFORE|PFM_SPACEAFTER|PFM_LINESPACING; + paraformat.wAlignment = PFA_LEFT; + + ZeroMemory(&charformat, sizeof(CHARFORMAT2)); + charformat.cbSize = sizeof(CHARFORMAT2); + charformat.dwMask = CFM_DISABLED|CFM_OFFSET|CFM_ITALIC|CFM_STRIKEOUT|CFM_PROTECTED| + CFM_UNDERLINETYPE|CFM_UNDERLINE|CFM_WEIGHT|CFM_FACE; + charformat.wWeight = FW_NORMAL; + strcpy(charformat.szFaceName, iupGetFontFaceAttrib(ih)); + + if (iupwinGetColorRef(ih, "FGCOLOR", &colorref)) + { + charformat.dwMask |= CFM_COLOR; + charformat.crTextColor = colorref; + } + + if (iupwinGetColorRef(ih, "BGCOLOR", &colorref)) + { + charformat.dwMask |= CFM_BACKCOLOR; + charformat.crBackColor = colorref; + } + + if (iupStrToInt(iupGetFontSizeAttrib(ih), &val)) + { + /* (1/1440 of an inch, or 1/20 of a printer's point) */ + charformat.dwMask |= CFM_SIZE; + if (val < 0) /* in pixels */ + { + int pixel2twips = 1440/iupwinGetScreenRes(); + charformat.yHeight = (-val)*pixel2twips; + } + else + charformat.yHeight = val*20; + } + + SendMessage(ih->handle, EM_SETPARAFORMAT, 0, (LPARAM)¶format); + SendMessage(ih->handle, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charformat); + + (void)value; + return 0; +} + +static int winTextSetOverwriteAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->has_formatting) + return 0; + + if (iupAttribGetBoolean(ih, "OVERWRITE")) + { + if (!iupStrBoolean(value)) + SendMessage(ih->handle, WM_KEYDOWN, VK_INSERT, 0); /* toggle from ON to OFF */ + } + else + { + if (iupStrBoolean(value)) + SendMessage(ih->handle, WM_KEYDOWN, VK_INSERT, 0); /* toggle from OFF to ON */ + } + return 1; +} + + +static int winTextSetVisibleAttrib(Ihandle* ih, const char* value) +{ + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + if (hSpin) + ShowWindow(hSpin, iupStrBoolean(value)? SW_SHOWNORMAL: SW_HIDE); + + return iupBaseSetVisibleAttrib(ih, value); +} + +static void winTextCropSpinValue(HWND hSpin, int min, int max) +{ + /* refresh if internally cropped, but text still shows an invalid value */ + int pos = SendMessage(hSpin, UDM_GETPOS32, 0, 0); + if (pos <= min) + SendMessage(hSpin, UDM_SETPOS32, 0, min); + if (pos >= max) + SendMessage(hSpin, UDM_SETPOS32, 0, max); +} + +static int winTextSetSpinMinAttrib(Ihandle* ih, const char* value) +{ + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + if (hSpin) + { + int min; + if (iupStrToInt(value, &min)) + { + int max = iupAttribGetInt(ih, "SPINMAX"); + SendMessage(hSpin, UDM_SETRANGE32, min, max); + + winTextCropSpinValue(hSpin, min, max); + } + } + return 1; +} + +static int winTextSetSpinMaxAttrib(Ihandle* ih, const char* value) +{ + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + if (hSpin) + { + int max; + if (iupStrToInt(value, &max)) + { + int min = iupAttribGetInt(ih, "SPINMIN"); + SendMessage(hSpin, UDM_SETRANGE32, min, max); + + winTextCropSpinValue(hSpin, min, max); + } + } + return 1; +} + +static int winTextSetSpinIncAttrib(Ihandle* ih, const char* value) +{ + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + if (hSpin) + { + int inc; + if (iupStrToInt(value, &inc)) + { + UDACCEL paAccels[3]; + paAccels[0].nInc = inc; + paAccels[0].nSec = 0; + paAccels[1].nInc = inc*5; + paAccels[1].nSec = 2; + paAccels[2].nInc = inc*20; + paAccels[2].nSec = 5; + SendMessage(hSpin, UDM_SETACCEL, 3, (LPARAM)paAccels); + } + } + return 1; +} + +static int winTextSetSpinValueAttrib(Ihandle* ih, const char* value) +{ + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + if (hSpin) + { + int pos; + if (iupStrToInt(value, &pos)) + SendMessage(hSpin, UDM_SETPOS32, 0, pos); + } + return 1; +} + +static char* winTextGetSpinValueAttrib(Ihandle* ih) +{ + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + if (hSpin) + { + int pos = SendMessage(hSpin, UDM_GETPOS32, 0, 0); + char *str = iupStrGetMemory(50); + sprintf(str, "%d", pos); + return str; + } + return NULL; +} + + +/****************************************************************************************/ + + +static int winTextCtlColor(Ihandle* ih, HDC hdc, LRESULT *result) +{ + COLORREF cr; + + if (iupwinGetColorRef(ih, "FGCOLOR", &cr)) + SetTextColor(hdc, cr); + + if (iupwinGetColorRef(ih, "BGCOLOR", &cr)) + { + SetBkColor(hdc, cr); + SetDCBrushColor(hdc, cr); + *result = (LRESULT)GetStockObject(DC_BRUSH); + return 1; + } + return 0; +} + +static void winTextCallCaretCb(Ihandle* ih) +{ + int col, lin, pos; + + IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB"); + if (!cb) return; + + pos = winTextGetCaret(ih, &lin, &col); + + if (pos != ih->data->last_caret_pos) + { + ih->data->last_caret_pos = pos; + + cb(ih, lin, col, pos); + } +} + +static int winTextCallActionCb(Ihandle* ih, const char* insert_value, int key, int dir) +{ + int start, end, ret = 1; + char *value, *new_value; + + IFnis cb = (IFnis)IupGetCallback(ih, "ACTION"); + if (!cb && !ih->data->mask) + return 1; + + winTextGetSelection(ih, &start, &end); + + value = winTextGetValueAttrib(ih); + + if (value[0]==0) + new_value = iupStrDup(insert_value); + else if (insert_value) + new_value = iupStrInsert(value, insert_value, start, end); + else + { + new_value = value; + iupStrRemove(value, start, end, dir); + } + + if (!new_value) + return 0; /* abort */ + + if (ih->data->nc && (int)strlen(new_value) > ih->data->nc) + { + if (new_value != value) free(new_value); + return 0; /* abort */ + } + + if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0) + { + if (new_value != value) free(new_value); + return 0; /* abort */ + } + + if (cb) + { + int cb_ret = cb(ih, key, (char*)new_value); + if (cb_ret==IUP_IGNORE) + ret = 0; /* abort processing */ + else if (cb_ret==IUP_CLOSE) + { + IupExitLoop(); + ret = 0; /* abort processing */ + } + else if (cb_ret!=0 && key!=0 && + cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE) + { + WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB"); + CallWindowProc(oldProc, ih->handle, WM_CHAR, cb_ret, 0); /* replace key */ + ret = 0; /* abort processing */ + } + } + + if (new_value != value) free(new_value); + return ret; +} + +static int winTextSpinWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) +{ + if (msg_info->code == UDN_DELTAPOS) + { + NMUPDOWN *updown = (NMUPDOWN*)msg_info; + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + int pos = updown->iPos+updown->iDelta; + int min, max; + SendMessage(hSpin, UDM_GETRANGE32, (WPARAM)&min, (LPARAM)&max); + if (pos>=min && pos<=max) + { + IFni cb = (IFni) IupGetCallback(ih, "SPIN_CB"); + if (cb) + { + int ret = cb(ih, pos); + if (ret == IUP_IGNORE) + { + *result = 1; + return 1; + } + } + } + } + + (void)result; + return 0; /* result not used */ +} + +static int winTextProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + int ret = 0; + + if (msg==WM_KEYDOWN) /* process K_ANY before text callbacks */ + { + ret = iupwinBaseProc(ih, msg, wp, lp, result); + if (ret) + { + *result = 0; + return 1; + } + } + + switch (msg) + { + case WM_CHAR: + { + if ((char)wp == '\b') + { + if (!winTextCallActionCb(ih, NULL, 0, -1)) + ret = 1; + } + else if ((char)wp == '\n' || (char)wp == '\r') + { + if (!ih->data->has_formatting && !(GetKeyState(VK_CONTROL) & 0x8000)) /* when formatting is processed in WM_KEYDOWN */ + { + char insert_value[2]; + insert_value[0] = '\n'; + insert_value[1] = 0; + + if (!winTextCallActionCb(ih, insert_value, wp, 1)) + ret = 1; + } + } + else if (!(GetKeyState(VK_CONTROL) & 0x8000 || + GetKeyState(VK_MENU) & 0x8000 || + GetKeyState(VK_LWIN) & 0x8000 || + GetKeyState(VK_RWIN) & 0x8000)) + { + char insert_value[2]; + insert_value[0] = (char)wp; + insert_value[1] = 0; + + if (!winTextCallActionCb(ih, insert_value, wp, 1)) + ret = 1; + } + + PostMessage(ih->handle, WM_CARET, 0, 0L); + + if (!ih->data->is_multiline && + (wp==VK_RETURN || wp==VK_ESCAPE || wp==VK_TAB)) /* the keys have the same definitions as the chars */ + ret = 1; /* abort default processing to avoid beep */ + + if (ih->data->is_multiline && + (wp=='\n' && (GetKeyState(VK_CONTROL) & 0x8000))) + ret = 1; /* abort default processing to avoid inserting a new line */ + + break; + } + case WM_KEYDOWN: + { + if (wp == VK_DELETE) /* Del does not generates a WM_CHAR */ + { + if (!winTextCallActionCb(ih, NULL, 0, 1)) + ret = 1; + } + else if (wp == VK_INSERT && ih->data->has_formatting) + { + if (iupAttribGetBoolean(ih, "OVERWRITE")) + iupAttribSetStr(ih, "OVERWRITE", "OFF"); /* toggle from ON to OFF */ + else + iupAttribSetStr(ih, "OVERWRITE", "ON"); /* toggle from OFF to ON */ + } + else if (wp == 'A' && GetKeyState(VK_CONTROL) & 0x8000) /* Ctrl+A = Select All */ + { + SendMessage(ih->handle, EM_SETSEL, (WPARAM)0, (LPARAM)-1); + } + else if (wp == VK_RETURN && ih->data->has_formatting && !(GetKeyState(VK_CONTROL) & 0x8000)) + { + char insert_value[2]; + insert_value[0] = '\n'; + insert_value[1] = 0; + + if (!winTextCallActionCb(ih, insert_value, '\n', 1)) + ret = 1; + } + + PostMessage(ih->handle, WM_CARET, 0, 0L); + + if (ret) /* if abort processing, then the result is 0 */ + { + *result = 0; + return 1; + } + else + return 0; /* already processed at the begining of this function */ + } + case WM_KEYUP: + { + PostMessage(ih->handle, WM_CARET, 0, 0L); + break; + } + case WM_CLEAR: + { + if (!winTextCallActionCb(ih, NULL, 0, 1)) + ret = 1; + + PostMessage(ih->handle, WM_CARET, 0, 0L); + break; + } + case WM_CUT: + { + if (!winTextCallActionCb(ih, NULL, 0, 1)) + ret = 1; + + PostMessage(ih->handle, WM_CARET, 0, 0L); + break; + } + case WM_PASTE: + { + if (IupGetCallback(ih,"ACTION") || ih->data->mask) /* test before to avoid alocate clipboard text memory */ + { + char* insert_value = iupwinGetClipboardText(ih); + if (insert_value) + { + if (!winTextCallActionCb(ih, insert_value, 0, 1)) + ret = 1; + free(insert_value); + } + } + + PostMessage(ih->handle, WM_CARET, 0, 0L); + break; + } + case WM_UNDO: + { + IFnis cb = (IFnis)IupGetCallback(ih, "ACTION"); + if (cb) + { + char* value; + WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB"); + CallWindowProc(oldProc, ih->handle, WM_UNDO, 0, 0); + + value = winTextGetValueAttrib(ih); + cb(ih, 0, (char*)value); + + ret = 1; + } + + PostMessage(ih->handle, WM_CARET, 0, 0L); + break; + } + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + { + if (iupwinButtonDown(ih, msg, wp, lp)==-1) + { + *result = 0; + return 1; + } + PostMessage(ih->handle, WM_CARET, 0, 0L); + break; + } + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONUP: + { + if (iupwinButtonUp(ih, msg, wp, lp)==-1) + { + *result = 0; + return 1; + } + PostMessage(ih->handle, WM_CARET, 0, 0L); + break; + } + case WM_CARET: + { + winTextCallCaretCb(ih); + break; + } + case WM_MOUSEMOVE: + { + iupwinMouseMove(ih, msg, wp, lp); + break; + } + case WM_VSCROLL: + case WM_HSCROLL: + { + if (ih->data->has_formatting) + { + /* fix weird behavior when dialog has COMPOSITE=YES, + scrollbars are not updated when dragging */ + if (LOWORD(wp) == SB_THUMBTRACK) + SendMessage(ih->handle, EM_SHOWSCROLLBAR, msg==WM_VSCROLL? SB_VERT: SB_HORZ, TRUE); + } + break; + } + } + + if (ret) /* if abort processing, then the result is 0 */ + { + *result = 0; + return 1; + } + else + return iupwinBaseProc(ih, msg, wp, lp, result); +} + +static void winTextCreateSpin(Ihandle* ih) +{ + HWND hSpin; + DWORD dwStyle = WS_CHILD|UDS_ARROWKEYS|UDS_HOTTRACK|UDS_NOTHOUSANDS; + int serial = iupDialogGetChildId(ih); + + if (iupStrEqualNoCase(iupAttribGetStr(ih, "SPINALIGN"), "LEFT")) + dwStyle |= UDS_ALIGNLEFT; + else + dwStyle |= UDS_ALIGNRIGHT; + + if (iupAttribGetBoolean(ih, "SPINWRAP")) + dwStyle |= UDS_WRAP; + + if (iupAttribGetBoolean(ih, "SPINAUTO")) + dwStyle |= UDS_SETBUDDYINT; + + hSpin = CreateWindowEx(0, /* extended window style */ + UPDOWN_CLASS, /* window class */ + NULL, /* title */ + dwStyle, /* window style */ + 0, /* x-position */ + 0, /* y-position */ + 10, /* default width to avoid 0 */ + 10, /* default height to avoid 0 */ + GetParent(ih->handle), /* window parent */ + (HMENU)serial, /* child identifier */ + iupwin_hinstance, /* instance of app. */ + NULL); + + if (!hSpin) + return; + + iupwinHandleAdd(ih, hSpin); + + /* Process WM_NOTIFY */ + IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winTextSpinWmNotify); + + SendMessage(hSpin, UDM_SETBUDDY, (WPARAM)ih->handle, 0); + iupAttribSetStr(ih, "_IUPWIN_SPIN", (char*)hSpin); + + /* default values */ + SendMessage(hSpin, UDM_SETRANGE32, 0, 100); + SendMessage(hSpin, UDM_SETPOS32, 0, 0); +} + +static int winTextWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp) +{ + int cmd = HIWORD(wp); + switch (cmd) + { + case EN_CHANGE: + { + if (iupAttribGetStr(ih, "IUPWIN_IGNORECHANGE")) + return 0; + + iupBaseCallValueChangedCb(ih); + break; + } + } + + (void)lp; + return 0; /* not used */ +} + +static void winTextLayoutUpdateMethod(Ihandle* ih) +{ + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + if (hSpin) + { + if (iupStrEqualNoCase(iupAttribGetStr(ih, "SPINALIGN"), "LEFT")) + { + SetWindowPos(ih->handle, NULL, ih->x+ih->currentheight-1, ih->y, ih->currentwidth-ih->currentheight, ih->currentheight, + SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER); + + SetWindowPos(hSpin, NULL, ih->x, ih->y, ih->currentheight, ih->currentheight, + SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER); + } + else + { + SetWindowPos(ih->handle, NULL, ih->x, ih->y, ih->currentwidth-ih->currentheight, ih->currentheight, + SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER); + + SetWindowPos(hSpin, NULL, ih->x+ih->currentwidth-ih->currentheight-1, ih->y, ih->currentheight, ih->currentheight, + SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER); + } + } + else + iupdrvBaseLayoutUpdateMethod(ih); +} + +static int winTextMapMethod(Ihandle* ih) +{ + DWORD dwStyle = WS_CHILD, + dwExStyle = 0; + char* winclass = "EDIT", *value; + + if (!ih->parent) + return IUP_ERROR; + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + dwStyle |= WS_TABSTOP; + + if (ih->data->has_formatting) + { + /* enable richedit 3.0 */ + static HMODULE richedit = NULL; + if (!richedit) + richedit = LoadLibrary("Riched20.dll"); + if (!richedit) + return IUP_ERROR; + + winclass = RICHEDIT_CLASS; + } + + if (ih->data->is_multiline) + { + dwStyle |= ES_AUTOVSCROLL|ES_MULTILINE|ES_WANTRETURN; + + if (iupAttribGetBoolean(ih, "WORDWRAP")) + { + ih->data->sb &= ~IUP_SB_HORIZ; /* must remove the horizontal scroolbar */ + /* and do not specify ES_AUTOHSCROLL, the control automatically wraps words */ + } + else + dwStyle |= ES_AUTOHSCROLL; + + if (ih->data->sb & IUP_SB_HORIZ) + dwStyle |= WS_HSCROLL; + if (ih->data->sb & IUP_SB_VERT) + dwStyle |= WS_VSCROLL; + + if (ih->data->has_formatting && ih->data->sb != IUP_SB_NONE) + { + if (!iupAttribGetBoolean(ih, "AUTOHIDE")) + dwStyle |= ES_DISABLENOSCROLL; + } + } + else + { + dwStyle |= ES_AUTOHSCROLL|ES_NOHIDESEL; + + if (iupAttribGetBoolean(ih, "PASSWORD")) + dwStyle |= ES_PASSWORD; + } + + value = iupAttribGet(ih, "ALIGNMENT"); + if (value) + { + if (iupStrEqualNoCase(value, "ARIGHT")) + dwStyle |= ES_RIGHT; + else if (iupStrEqualNoCase(value, "ACENTER")) + dwStyle |= ES_CENTER; + else /* default "ALEFT" */ + dwStyle |= ES_LEFT; + } + + if (iupAttribGetBoolean(ih, "BORDER")) + dwExStyle |= WS_EX_CLIENTEDGE; + + if (!iupwinCreateWindowEx(ih, winclass, dwExStyle, dwStyle)) + return IUP_ERROR; + + /* Process ACTION_CB and CARET_CB */ + IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winTextProc); + + /* Process background color */ + IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winTextCtlColor); + + /* Process WM_COMMAND */ + IupSetCallback(ih, "_IUPWIN_COMMAND_CB", (Icallback)winTextWmCommand); + + /* set defaults */ + SendMessage(ih->handle, EM_LIMITTEXT, 0, 0L); + { + int tabsize = 8*4; + SendMessage(ih->handle, EM_SETTABSTOPS, (WPARAM)1L, (LPARAM)&tabsize); + } + + if (!ih->data->is_multiline && iupAttribGetBoolean(ih, "SPIN")) + winTextCreateSpin(ih); + + /* configure for DRAG&DROP */ + if (IupGetCallback(ih, "DROPFILES_CB")) + iupAttribSetStr(ih, "DRAGDROP", "YES"); + + if (ih->data->has_formatting) + { + SendMessage(ih->handle, EM_SETTEXTMODE, (WPARAM)(TM_RICHTEXT|TM_MULTILEVELUNDO|TM_SINGLECODEPAGE), 0); + SendMessage(ih->handle, EM_SETEVENTMASK, 0, ENM_CHANGE); + } + + if (ih->data->formattags) + { + /* must update FONT before updating the format during map */ + iupUpdateStandardFontAttrib(ih); + iupAttribSetStr(ih, "_IUPWIN_IGNORE_FONT", "1"); + + iupTextUpdateFormatTags(ih); + } + + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)winTextConvertXYToPos); + + return IUP_NOERROR; +} + +void iupdrvTextInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = winTextMapMethod; + ic->LayoutUpdate = winTextLayoutUpdateMethod; + + /* Driver Dependent Attribute functions */ + + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, winTextSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winTextSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, winTextSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_NOT_MAPPED); /* usually black */ + + /* IupText only */ + iupClassRegisterAttribute(ic, "PADDING", iupTextGetPaddingAttrib, winTextSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "VALUE", winTextGetValueAttrib, winTextSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTEDTEXT", winTextGetSelectedTextAttrib, winTextSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTION", winTextGetSelectionAttrib, winTextSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTIONPOS", winTextGetSelectionPosAttrib, winTextSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARET", winTextGetCaretAttrib, winTextSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARETPOS", winTextGetCaretPosAttrib, winTextSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INSERT", NULL, winTextSetInsertAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "APPEND", NULL, winTextSetAppendAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "READONLY", winTextGetReadOnlyAttrib, winTextSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "NC", iupTextGetNCAttrib, winTextSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, winTextSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTO", NULL, winTextSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, winTextSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINMIN", NULL, winTextSetSpinMinAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINMAX", NULL, winTextSetSpinMaxAttrib, IUPAF_SAMEASSYSTEM, "100", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPININC", NULL, winTextSetSpinIncAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINVALUE", winTextGetSpinValueAttrib, winTextSetSpinValueAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT); + + /* IupText Windows and GTK only */ + iupClassRegisterAttribute(ic, "ADDFORMATTAG", NULL, iupTextSetAddFormatTagAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ADDFORMATTAG_HANDLE", NULL, iupTextSetAddFormatTagHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, winTextSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ALEFT", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FORMATTING", iupTextGetFormattingAttrib, iupTextSetFormattingAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "OVERWRITE", NULL, winTextSetOverwriteAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "REMOVEFORMATTING", NULL, winTextSetRemoveFormattingAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TABSIZE", NULL, winTextSetTabSizeAttrib, IUPAF_SAMEASSYSTEM, "8", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "PASSWORD", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + + /* IupText Windows only */ + iupClassRegisterAttribute(ic, "CUEBANNER", NULL, winTextSetCueBannerAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FILTER", NULL, winTextSetFilterAttrib, NULL, NULL, IUPAF_NO_INHERIT); +} diff --git a/iup/src/win/iupwin_timer.c b/iup/src/win/iupwin_timer.c new file mode 100755 index 0000000..f2bb9c5 --- /dev/null +++ b/iup/src/win/iupwin_timer.c @@ -0,0 +1,88 @@ +/** \file + * \brief Timer for the Windows Driver. + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_assert.h" +#include "iup_timer.h" + + +static Itable* wintimer_id_table = NULL; /* table indexed by ID containing Ihandle* address */ + +static void CALLBACK winTimerProc(HWND hwnd, UINT msg, UINT_PTR wid, DWORD time) +{ + Icallback cb; + Ihandle *ih; + + (void)time; + (void)msg; + (void)hwnd; + + ih = (Ihandle*)iupTableGet(wintimer_id_table, (char*)wid); + + if (!iupObjectCheck(ih)) /* control could be destroyed before timer callback */ + return; + + cb = IupGetCallback(ih, "ACTION_CB"); + if(cb) + { + if (cb(ih) == IUP_CLOSE) + IupExitLoop(); + } +} + +void iupdrvTimerRun(Ihandle *ih) +{ + unsigned int time_ms; + + if (ih->serial > 0) /* timer already started */ + return; + + time_ms = iupAttribGetInt(ih, "TIME"); + if (time_ms > 0) + { + ih->serial = SetTimer(NULL, 0, time_ms, (TIMERPROC)winTimerProc); + iupTableSet(wintimer_id_table, (const char*)ih->serial, ih, IUPTABLE_POINTER); + } +} + +void iupdrvTimerStop(Ihandle* ih) +{ + if (ih->serial > 0) + { + KillTimer(NULL, ih->serial); + iupTableRemove(wintimer_id_table, (const char*)ih->serial); + ih->serial = -1; + } +} + +static void winTimerRelease(Iclass* ic) +{ + (void)ic; + + if (wintimer_id_table) + { + iupTableDestroy(wintimer_id_table); + wintimer_id_table = NULL; + } +} + +void iupdrvTimerInitClass(Iclass* ic) +{ + ic->Release = winTimerRelease; + + if (!wintimer_id_table) + wintimer_id_table = iupTableCreate(IUPTABLE_POINTERINDEXED); +} diff --git a/iup/src/win/iupwin_tips.c b/iup/src/win/iupwin_tips.c new file mode 100755 index 0000000..f717ace --- /dev/null +++ b/iup/src/win/iupwin_tips.c @@ -0,0 +1,191 @@ +/** \file + * \brief Windows Driver TIPS management + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> + +#include <windows.h> +#include <commctrl.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" + + +#ifndef TTM_POPUP /* it is defined only when _WIN32_WINNT >= 0x0501 */ +#define TTM_POPUP (WM_USER + 34) +#endif + +static HWND winTipsCreate(HWND hParent) +{ + RECT rect = {1,1,1,1}; + HWND tips_hwnd = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, (LPSTR) NULL, TTS_ALWAYSTIP, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + hParent, (HMENU)NULL, iupwin_hinstance, NULL); + SendMessage(tips_hwnd, TTM_SETMAXTIPWIDTH, 0, (LPARAM)(INT)3000); + SendMessage(tips_hwnd, TTM_SETMARGIN, (WPARAM)0, (LPARAM)&rect); + return tips_hwnd; +} + +static int winTipsSendMessage(Ihandle* ih, HWND tips_hwnd, UINT msg) +{ + TOOLINFO ti; + ZeroMemory(&ti, sizeof(TOOLINFO)); + ti.cbSize = sizeof(TOOLINFO); + ti.uFlags = TTF_SUBCLASS; + ti.hinst = iupwin_hinstance; + ti.uId = 0; + ti.hwnd = ih->handle; + ti.lpszText = LPSTR_TEXTCALLBACK; + ti.rect.right = 3000; + ti.rect.bottom = 3000; + + return SendMessage(tips_hwnd, msg, 0, (LPARAM)&ti); +} + +int iupdrvBaseSetTipAttrib(Ihandle* ih, const char* value) +{ + HWND tips_hwnd = (HWND)iupAttribGet(ih, "_IUPWIN_TIPSWIN"); + if (!tips_hwnd) + { + tips_hwnd = winTipsCreate(ih->handle); + iupAttribSetStr(ih, "_IUPWIN_TIPSWIN", (char*)tips_hwnd); + iupwinHandleAdd(ih, tips_hwnd); + } + + if (value) + winTipsSendMessage(ih, tips_hwnd, TTM_ADDTOOL); + else + winTipsSendMessage(ih, tips_hwnd, TTM_DELTOOL); + + return 1; +} + +int iupdrvBaseSetTipVisibleAttrib(Ihandle* ih, const char* value) +{ + HWND tips_hwnd = (HWND)iupAttribGet(ih, "_IUPWIN_TIPSWIN"); + if (!tips_hwnd) + return 0; + + /* must use IupGetAttribute to use inheritance */ + if (!IupGetAttribute(ih, "TIP")) + return 0; + + if (iupStrBoolean(value)) + SendMessage(tips_hwnd, TTM_POPUP, 0, 0); /* XP Only */ + else + SendMessage(tips_hwnd, TTM_POP, 0, 0); + + return 0; +} + +void iupwinTipsGetDispInfo(LPARAM lp) +{ + COLORREF color, tip_color; + NMTTDISPINFO* tips_info; + Ihandle* ih; + HWND tips_hwnd; + char* value; + + if (!lp) return; + + tips_info = (NMTTDISPINFO*)lp; + ih = iupwinHandleGet(tips_info->hdr.hwndFrom); /* hwndFrom is the tooltip window */ + if (!ih) return; + + tips_hwnd = (HWND)iupAttribGet(ih, "_IUPWIN_TIPSWIN"); + if (tips_hwnd != tips_info->hdr.hwndFrom) return; + + tips_info->hinst = NULL; + tips_info->lpszText = IupGetAttribute(ih, "TIP"); /* must use IupGetAttribute to use inheritance */ + + { + HFONT hfont; + value = iupAttribGetStr(ih, "TIPFONT"); + if (value) + { + if (iupStrEqualNoCase(value, "SYSTEM")) + hfont = NULL; + else + hfont = iupwinGetHFont(value); + } + else + hfont = (HFONT)iupwinGetHFontAttrib(ih); + + if (hfont) + { + HFONT tip_hfont = (HFONT)SendMessage(tips_hwnd, WM_GETFONT, 0, 0); + if (tip_hfont != hfont) + SendMessage(tips_hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE,0)); + } + } + + iupwinGetColorRef(ih, "TIPBGCOLOR", &color); + tip_color = (COLORREF)SendMessage(tips_hwnd, TTM_GETTIPBKCOLOR, 0, 0); + if (color != tip_color) + SendMessage(tips_hwnd, TTM_SETTIPBKCOLOR, (WPARAM)color, 0); + + iupwinGetColorRef(ih, "TIPFGCOLOR", &color); + tip_color = (COLORREF)SendMessage(tips_hwnd, TTM_GETTIPTEXTCOLOR, 0, 0); + if (color != tip_color) + SendMessage(tips_hwnd, TTM_SETTIPTEXTCOLOR, (WPARAM)color, 0); + + { + int ballon = IupGetInt(ih, "TIPBALLON"); /* must use IupGetInt to use inheritance */ + DWORD style = GetWindowLong(tips_hwnd, GWL_STYLE); + int tip_ballon = style & TTS_BALLOON? 1: 0; + if (tip_ballon != ballon) + { + if (ballon) + style |= TTS_BALLOON; + else + style &= ~TTS_BALLOON; + SetWindowLong(tips_hwnd, GWL_STYLE, style); + } + + if (ballon) + { + char* ballon_title = IupGetAttribute(ih, "TIPBALLONTITLE"); /* must use IupGetAttribute to use inheritance */ + int ballon_icon = IupGetInt(ih, "TIPBALLONTITLEICON"); /* must use IupGetInt to use inheritance */ + SendMessage(tips_hwnd, TTM_SETTITLEA, ballon_icon, (LPARAM)ballon_title); + } + else + SendMessage(tips_hwnd, TTM_SETTITLEA, 0, 0); + } + + { + int delay = IupGetInt(ih, "TIPDELAY"); /* must use IupGetInt to use inheritance */ + int tip_delay = SendMessage(tips_hwnd, TTM_GETDELAYTIME, TTDT_AUTOPOP, 0); + if (delay != tip_delay) + SendMessage(tips_hwnd, TTM_SETDELAYTIME, TTDT_AUTOPOP, (LPARAM)MAKELONG(delay, 0)); + } + + { + TOOLINFO ti; + + ZeroMemory(&ti, sizeof(TOOLINFO)); + ti.cbSize = sizeof(TOOLINFO); + ti.uId = 0; + ti.hwnd = ih->handle; + + value = iupAttribGet(ih, "TIPRECT"); + if (value) + { + int x1, x2, y1, y2; + sscanf(value, "%d %d %d %d", &x1, &y1, &x2, &y2); + ti.rect.left = x1; ti.rect.right = x2; + ti.rect.top = y1; ti.rect.bottom = y2; + } + else + GetClientRect(ih->handle, &ti.rect); + + SendMessage(tips_hwnd, TTM_NEWTOOLRECT, 0, (LPARAM)&ti); + } +} diff --git a/iup/src/win/iupwin_toggle.c b/iup/src/win/iupwin_toggle.c new file mode 100755 index 0000000..fcaa438 --- /dev/null +++ b/iup/src/win/iupwin_toggle.c @@ -0,0 +1,693 @@ +/** \file + * \brief Toggle Control + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> +#include <commctrl.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_toggle.h" +#include "iup_drv.h" +#include "iup_image.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" +#include "iupwin_draw.h" + + +#ifndef CDIS_SHOWKEYBOARDCUES +#define CDIS_SHOWKEYBOARDCUES 0x0200 /* it is defined only when _WIN32_WINNT >= 0x0501 */ +#endif + + +void iupdrvToggleAddCheckBox(int *x, int *y) +{ + (*x) += 16+6; + if ((*y) < 16) (*y) = 16; /* minimum height */ +} + +static int winToggleIsActive(Ihandle* ih) +{ + return iupAttribGetInt(ih, "_IUPWIN_ACTIVE"); +} + +static void winToggleSetBitmap(Ihandle* ih, const char* name, int make_inactive) +{ + if (name) + { + HBITMAP bitmap = iupImageGetImage(name, ih, make_inactive); + SendMessage(ih->handle, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)bitmap); + } + else + SendMessage(ih->handle, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)NULL); /* if not defined */ +} + +static void winToggleUpdateImage(Ihandle* ih, int active, int check) +{ + /* called only when (ih->data->type == IUP_TOGGLE_IMAGE && !iupwin_comctl32ver6) */ + char* name; + + if (!active) + { + name = iupAttribGet(ih, "IMINACTIVE"); + if (name) + winToggleSetBitmap(ih, name, 0); + else + { + /* if not defined then automaticaly create one based on IMAGE */ + name = iupAttribGet(ih, "IMAGE"); + winToggleSetBitmap(ih, name, 1); /* make_inactive */ + } + } + else + { + /* must restore the normal image */ + if (check) + { + name = iupAttribGet(ih, "IMPRESS"); + if (name) + winToggleSetBitmap(ih, name, 0); + else + { + /* if not defined then automaticaly create one based on IMAGE */ + name = iupAttribGet(ih, "IMAGE"); + winToggleSetBitmap(ih, name, 0); + } + } + else + { + name = iupAttribGet(ih, "IMAGE"); + if (name) + winToggleSetBitmap(ih, name, 0); + } + } +} + +static void winToggleGetAlignment(Ihandle* ih, int *horiz_alignment, int *vert_alignment) +{ + char value1[30]="", value2[30]=""; + + iupStrToStrStr(iupAttribGetStr(ih, "ALIGNMENT"), value1, value2, ':'); + + if (iupStrEqualNoCase(value1, "ARIGHT")) + *horiz_alignment = IUP_ALIGN_ARIGHT; + else if (iupStrEqualNoCase(value1, "ALEFT")) + *horiz_alignment = IUP_ALIGN_ALEFT; + else /* "ACENTER" */ + *horiz_alignment = IUP_ALIGN_ACENTER; + + if (iupStrEqualNoCase(value2, "ABOTTOM")) + *vert_alignment = IUP_ALIGN_ABOTTOM; + else if (iupStrEqualNoCase(value2, "ATOP")) + *vert_alignment = IUP_ALIGN_ATOP; + else /* "ACENTER" */ + *vert_alignment = IUP_ALIGN_ACENTER; +} + +static void winToggleDrawImage(Ihandle* ih, HDC hDC, int rect_width, int rect_height, int border, UINT itemState) +{ + int xpad = ih->data->horiz_padding + border, + ypad = ih->data->vert_padding + border; + int horiz_alignment, vert_alignment; + int x, y, width, height, bpp, shift = 1; + HBITMAP hBitmap, hMask = NULL; + char *name; + int make_inactive = 0; + + if (itemState & ODS_DISABLED) + { + name = iupAttribGet(ih, "IMINACTIVE"); + if (!name) + { + name = iupAttribGet(ih, "IMAGE"); + make_inactive = 1; + } + } + else + { + name = iupAttribGet(ih, "IMPRESS"); + if (itemState & ODS_SELECTED && name) + shift = 0; + else + name = iupAttribGet(ih, "IMAGE"); + } + + hBitmap = iupImageGetImage(name, ih, make_inactive); + if (!hBitmap) + return; + + /* must use this info, since image can be a driver image loaded from resources */ + iupdrvImageGetInfo(hBitmap, &width, &height, &bpp); + + winToggleGetAlignment(ih, &horiz_alignment, &vert_alignment); + if (horiz_alignment == IUP_ALIGN_ARIGHT) + x = rect_width - (width + 2*xpad); + else if (horiz_alignment == IUP_ALIGN_ACENTER) + x = (rect_width - (width + 2*xpad))/2; + else /* ALEFT */ + x = 0; + + if (vert_alignment == IUP_ALIGN_ABOTTOM) + y = rect_height - (height + 2*ypad); + else if (vert_alignment == IUP_ALIGN_ATOP) + y = 0; + else /* ACENTER */ + y = (rect_height - (height + 2*ypad))/2; + + x += xpad; + y += ypad; + + if (itemState & ODS_SELECTED && !iupwin_comctl32ver6 && shift) + { + x++; + y++; + } + + if (bpp == 8) + hMask = iupdrvImageCreateMask(IupGetHandle(name)); + + iupwinDrawBitmap(hDC, hBitmap, hMask, x, y, width, height, bpp); + + if (hMask) + DeleteObject(hMask); +} + +static void winToggleDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem) +{ + int width, height, border = 4, check; + HDC hDC; + iupwinBitmapDC bmpDC; + + width = drawitem->rcItem.right - drawitem->rcItem.left; + height = drawitem->rcItem.bottom - drawitem->rcItem.top; + + hDC = iupwinDrawCreateBitmapDC(&bmpDC, drawitem->hDC, width, height); + + iupwinDrawParentBackground(ih, hDC, &drawitem->rcItem); + + check = SendMessage(ih->handle, BM_GETCHECK, 0, 0L); + if (check) + drawitem->itemState |= ODS_SELECTED; + else + drawitem->itemState |= ODS_DEFAULT; /* use default mark for NOT checked */ + + iupwinDrawButtonBorder(ih->handle, hDC, &drawitem->rcItem, drawitem->itemState); + + winToggleDrawImage(ih, hDC, width, height, border, drawitem->itemState); + + if (drawitem->itemState & ODS_FOCUS) + { + border--; + iupdrvDrawFocusRect(ih, hDC, border, border, width-2*border, height-2*border); + } + + iupwinDrawDestroyBitmapDC(&bmpDC); +} + + +/***********************************************************************************************/ + + +static int winToggleSetImageAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + if (value != iupAttribGet(ih, "IMAGE")) + iupAttribSetStr(ih, "IMAGE", (char*)value); + + if (iupwin_comctl32ver6) + iupdrvDisplayRedraw(ih); + else + { + int check = SendMessage(ih->handle, BM_GETCHECK, 0L, 0L); + winToggleUpdateImage(ih, winToggleIsActive(ih), check); + } + return 1; + } + else + return 0; +} + +static int winToggleSetImInactiveAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + if (value != iupAttribGet(ih, "IMINACTIVE")) + iupAttribSetStr(ih, "IMINACTIVE", (char*)value); + + if (iupwin_comctl32ver6) + iupdrvDisplayRedraw(ih); + else + { + int check = SendMessage(ih->handle, BM_GETCHECK, 0L, 0L); + winToggleUpdateImage(ih, winToggleIsActive(ih), check); + } + return 1; + } + else + return 0; +} + +static int winToggleSetImPressAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + if (value != iupAttribGet(ih, "IMPRESS")) + iupAttribSetStr(ih, "IMPRESS", (char*)value); + + if (iupwin_comctl32ver6) + iupdrvDisplayRedraw(ih); + else + { + int check = SendMessage(ih->handle, BM_GETCHECK, 0L, 0L); + winToggleUpdateImage(ih, winToggleIsActive(ih), check); + } + return 1; + } + else + return 0; +} + +static int winToggleSetValueAttrib(Ihandle* ih, const char* value) +{ + Ihandle *radio; + int check; + + if (iupStrEqualNoCase(value,"NOTDEF")) + check = BST_INDETERMINATE; + else if (iupStrBoolean(value)) + check = BST_CHECKED; + else + check = BST_UNCHECKED; + + /* This is necessary because Windows does not handle the radio state + when a toggle is programatically changed. */ + radio = iupRadioFindToggleParent(ih); + if (radio) + { + int oldcheck = (int)SendMessage(ih->handle, BM_GETCHECK, 0, 0L); + + Ihandle* last_tg = (Ihandle*)iupAttribGet(radio, "_IUPWIN_LASTTOGGLE"); + if (check) + { + if (iupObjectCheck(last_tg) && last_tg != ih) + SendMessage(last_tg->handle, BM_SETCHECK, BST_UNCHECKED, 0L); + iupAttribSetStr(radio, "_IUPWIN_LASTTOGGLE", (char*)ih); + } + + if (last_tg != ih && oldcheck != check) + SendMessage(ih->handle, BM_SETCHECK, check, 0L); + } + else + SendMessage(ih->handle, BM_SETCHECK, check, 0L); + + if (ih->data->type == IUP_TOGGLE_IMAGE && !iupwin_comctl32ver6) + winToggleUpdateImage(ih, winToggleIsActive(ih), check); + + return 0; +} + +static char* winToggleGetValueAttrib(Ihandle* ih) +{ + int check = (int)SendMessage(ih->handle, BM_GETCHECK, 0, 0L); + if (check == BST_INDETERMINATE) + return "NOTDEF"; + else if (check == BST_CHECKED) + return "ON"; + else + return "OFF"; +} + +static int winToggleSetActiveAttrib(Ihandle* ih, const char* value) +{ + /* update the inactive image if necessary */ + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + if (iupwin_comctl32ver6) + { + iupBaseSetActiveAttrib(ih, value); + iupdrvDisplayRedraw(ih); + return 0; + } + else + { + int active = iupStrBoolean(value); + int check = SendMessage(ih->handle, BM_GETCHECK, 0, 0L); + if (active) + iupAttribSetStr(ih, "_IUPWIN_ACTIVE", "YES"); + else + iupAttribSetStr(ih, "_IUPWIN_ACTIVE", "NO"); + winToggleUpdateImage(ih, active, check); + return 0; + } + } + + return iupBaseSetActiveAttrib(ih, value); +} + +static char* winToggleGetActiveAttrib(Ihandle* ih) +{ + if (ih->data->type == IUP_TOGGLE_IMAGE && !iupwin_comctl32ver6) + return iupAttribGet(ih, "_IUPWIN_ACTIVE"); + else + return iupBaseGetActiveAttrib(ih); +} + +static int winToggleSetTitleAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_TEXT) + { + if (!value) + value = ""; + SetWindowText(ih->handle, value); + } + return 0; +} + +static int winToggleSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + + if (ih->handle && iupwin_comctl32ver6 && ih->data->type == IUP_TOGGLE_IMAGE) + iupdrvDisplayRedraw(ih); + + return 0; +} + +static int winToggleSetBgColorAttrib(Ihandle* ih, const char* value) +{ + (void)value; + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + /* update internal image cache for controls that have the IMAGE attribute */ + iupAttribSetStr(ih, "BGCOLOR", value); + iupImageUpdateParent(ih); + iupdrvDisplayRedraw(ih); + } + return 1; +} + +static char* winToggleGetBgColorAttrib(Ihandle* ih) +{ + /* the most important use of this is to provide + the correct background for images */ + if (iupwin_comctl32ver6 && ih->data->type == IUP_TOGGLE_IMAGE) + { + COLORREF cr; + if (iupwinDrawGetThemeButtonBgColor(ih->handle, &cr)) + { + char* str = iupStrGetMemory(20); + sprintf(str, "%d %d %d", (int)GetRValue(cr), (int)GetGValue(cr), (int)GetBValue(cr)); + return str; + } + } + + if (ih->data->type == IUP_TOGGLE_TEXT) + return iupBaseNativeParentGetBgColorAttrib(ih); + else + return IupGetGlobal("DLGBGCOLOR"); +} + + +/****************************************************************************************/ + + +static int winToggleCtlColor(Ihandle* ih, HDC hdc, LRESULT *result) +{ + COLORREF cr; + + SetBkMode(hdc, TRANSPARENT); + + if (iupwinGetColorRef(ih, "FGCOLOR", &cr)) + SetTextColor(hdc, cr); + + if (iupwinGetParentBgColor(ih, &cr)) + { + SetDCBrushColor(hdc, cr); + *result = (LRESULT)GetStockObject(DC_BRUSH); + return 1; + } + return 0; +} + +static int winToggleWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) +{ + if (msg_info->code == NM_CUSTOMDRAW) + { + /* called only when iupwin_comctl32ver6 AND (ih->data->type==IUP_TOGGLE_IMAGE) */ + NMCUSTOMDRAW *customdraw = (NMCUSTOMDRAW*)msg_info; + + if (customdraw->dwDrawStage==CDDS_PREERASE) + { + DRAWITEMSTRUCT drawitem; + drawitem.itemState = 0; + + if (customdraw->uItemState & CDIS_DISABLED) + drawitem.itemState |= ODS_DISABLED; + else if (customdraw->uItemState & CDIS_SELECTED) + drawitem.itemState |= ODS_SELECTED; + else if (customdraw->uItemState & CDIS_HOT) + drawitem.itemState |= ODS_HOTLIGHT; + else if (customdraw->uItemState & CDIS_DEFAULT) + drawitem.itemState |= ODS_DEFAULT; + + if (customdraw->uItemState & CDIS_FOCUS && (customdraw->uItemState & CDIS_SHOWKEYBOARDCUES)) + drawitem.itemState |= ODS_FOCUS; + + drawitem.hDC = customdraw->hdc; + drawitem.rcItem = customdraw->rc; + + winToggleDrawItem(ih, (void*)&drawitem); /* Simulate a WM_DRAWITEM */ + + *result = CDRF_SKIPDEFAULT; + return 1; + } + } + + return 0; /* result not used */ +} + +static int winToggleProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + (void)lp; + (void)wp; + + switch (msg) + { + case WM_MOUSEACTIVATE: + if (!winToggleIsActive(ih)) + { + *result = MA_NOACTIVATEANDEAT; + return 1; + } + break; + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_ACTIVATE: + case WM_SETFOCUS: + if (!winToggleIsActive(ih)) + { + *result = 0; + return 1; + } + break; + } + + if (msg == WM_LBUTTONDOWN) + winToggleUpdateImage(ih, 1, 1); + else if (msg == WM_LBUTTONUP) + winToggleUpdateImage(ih, 1, 0); + + return iupwinBaseProc(ih, msg, wp, lp, result); +} + +static int winToggleWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp) +{ + (void)lp; + + switch (HIWORD(wp)) + { + case BN_DOUBLECLICKED: + case BN_CLICKED: + { + Ihandle *radio; + IFni cb; + int check = SendMessage(ih->handle, BM_GETCHECK, 0, 0L); + + if (ih->data->type == IUP_TOGGLE_IMAGE && !iupwin_comctl32ver6) + { + int active = winToggleIsActive(ih); + winToggleUpdateImage(ih, active, check); + if (!active) + return 0; + } + + radio = iupRadioFindToggleParent(ih); + if (radio) + { + /* This is necessary because Windows does not send a message + when a toggle is unchecked in a Radio. + Also if the toggle is already checked in a radio, + a click will call the callback again. */ + + Ihandle* last_tg = (Ihandle*)iupAttribGet(radio, "_IUPWIN_LASTTOGGLE"); + if (iupObjectCheck(last_tg) && last_tg != ih) + { + /* uncheck last toggle */ + SendMessage(last_tg->handle, BM_SETCHECK, BST_UNCHECKED, 0L); + + cb = (IFni) IupGetCallback(last_tg, "ACTION"); + if (cb && cb(last_tg, 0) == IUP_CLOSE) + IupExitLoop(); + + iupBaseCallValueChangedCb(last_tg); + } + iupAttribSetStr(radio, "_IUPWIN_LASTTOGGLE", (char*)ih); + + if (last_tg != ih) + { + /* check new toggle */ + SendMessage(ih->handle, BM_SETCHECK, BST_CHECKED, 0L); + + cb = (IFni)IupGetCallback(ih, "ACTION"); + if (cb && cb (ih, 1) == IUP_CLOSE) + IupExitLoop(); + + iupBaseCallValueChangedCb(ih); + } + } + else + { + if (check == BST_INDETERMINATE) + check = -1; + + cb = (IFni)IupGetCallback(ih, "ACTION"); + if (cb && cb (ih, check) == IUP_CLOSE) + IupExitLoop(); + + iupBaseCallValueChangedCb(ih); + } + } + } + + + return 0; /* not used */ +} + +static int winToggleMapMethod(Ihandle* ih) +{ + Ihandle* radio = iupRadioFindToggleParent(ih); + char* value; + DWORD dwStyle = WS_CHILD | + BS_NOTIFY; /* necessary because of the base messages */ + + if (!ih->parent) + return IUP_ERROR; + + if (radio) + ih->data->radio = 1; + + value = iupAttribGet(ih, "IMAGE"); + if (value) + { + ih->data->type = IUP_TOGGLE_IMAGE; + dwStyle |= BS_BITMAP|BS_PUSHLIKE; + } + else + { + ih->data->type = IUP_TOGGLE_TEXT; + dwStyle |= BS_TEXT|BS_MULTILINE; + + if (iupAttribGetBoolean(ih, "RIGHTBUTTON")) + dwStyle |= BS_RIGHTBUTTON; + } + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + dwStyle |= WS_TABSTOP; + + if (radio) + { + dwStyle |= BS_RADIOBUTTON; + + if (!iupAttribGet(radio, "_IUPWIN_LASTTOGGLE")) + { + /* this is the first toggle in the radio, and the last toggle with VALUE=ON */ + iupAttribSetStr(ih, "VALUE","ON"); + } + } + else + { + if (ih->data->type == IUP_TOGGLE_TEXT && iupAttribGetBoolean(ih, "3STATE")) + dwStyle |= BS_AUTO3STATE; + else + dwStyle |= BS_AUTOCHECKBOX; + } + + if (!iupwinCreateWindowEx(ih, "BUTTON", 0, dwStyle)) + return IUP_ERROR; + + /* Process WM_COMMAND */ + IupSetCallback(ih, "_IUPWIN_COMMAND_CB", (Icallback)winToggleWmCommand); + + /* Process background color */ + IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winToggleCtlColor); + + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + if (iupwin_comctl32ver6) + IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winToggleWmNotify); /* Process WM_NOTIFY */ + else + { + IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winToggleProc); + iupAttribSetStr(ih, "_IUPWIN_ACTIVE", "YES"); + } + } + + return IUP_NOERROR; +} + +void iupdrvToggleInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = winToggleMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "ACTIVE", winToggleGetActiveAttrib, winToggleSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", winToggleGetBgColorAttrib, winToggleSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, "DLGFGCOLOR", NULL, IUPAF_NOT_MAPPED); /* force the new default value */ + iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, winToggleSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupToggle only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, NULL, IUPAF_SAMEASSYSTEM, "ACENTER:ACENTER", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE", NULL, winToggleSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, winToggleSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMPRESS", NULL, winToggleSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE", winToggleGetValueAttrib, winToggleSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PADDING", iupToggleGetPaddingAttrib, winToggleSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + + /* IupToggle Windows only */ + iupClassRegisterAttribute(ic, "RIGHTBUTTON", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + + /* necessary because it uses an old HBITMAP solution when NOT using styles */ + if (!iupwin_comctl32ver6) /* Used by iupdrvImageCreateImage */ + iupClassRegisterAttribute(ic, "FLAT_ALPHA", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); +} diff --git a/iup/src/win/iupwin_tree.c b/iup/src/win/iupwin_tree.c new file mode 100755 index 0000000..e6877dc --- /dev/null +++ b/iup/src/win/iupwin_tree.c @@ -0,0 +1,2542 @@ +/** \file + * \brief Tree Control + * + * See Copyright Notice in iup.h + */ + +#undef NOTREEVIEW +#include <windows.h> +#include <commctrl.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_stdcontrols.h" +#include "iup_tree.h" +#include "iup_image.h" +#include "iup_array.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" +#include "iupwin_draw.h" +#include "iupwin_info.h" + +typedef struct _winTreeItemData +{ + COLORREF color; + unsigned char kind; + void* userdata; + HFONT hFont; + short image; + short image_expanded; +} winTreeItemData; + +#ifndef TVN_ITEMCHANGING /* Vista Only */ +typedef struct tagNMTVITEMCHANGE { + NMHDR hdr; + UINT uChanged; + HTREEITEM hItem; + UINT uStateNew; + UINT uStateOld; + LPARAM lParam; +} NMTVITEMCHANGE; +#define TVN_ITEMCHANGINGA (TVN_FIRST-16) +#define TVN_ITEMCHANGINGW (TVN_FIRST-17) +#endif + +static void winTreeSetFocusNode(Ihandle* ih, HTREEITEM hItem); +typedef int (*winTreeNodeFunc)(Ihandle* ih, HTREEITEM hItem, void* userdata); + +static int winTreeForEach(Ihandle* ih, HTREEITEM hItem, winTreeNodeFunc func, void* userdata) +{ + HTREEITEM hItemChild; + + if (!hItem) + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); + + while(hItem != NULL) + { + if (!func(ih, hItem, userdata)) + return 0; + + hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + if (hItemChild) + { + /* Recursively traverse child items */ + if (!winTreeForEach(ih, hItemChild, func, userdata)) + return 0; + } + + /* Go to next sibling item */ + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); + } + + return 1; +} + +/*****************************************************************************/ +/* FINDING ITEMS */ +/*****************************************************************************/ +static HTREEITEM winTreeFindNodeID(Ihandle* ih, HTREEITEM hItem, HTREEITEM hNode) +{ + TVITEM item; + winTreeItemData* itemData; + + while(hItem != NULL) + { + /* ID control to traverse items */ + ih->data->id_control++; + + /* StateID founded! */ + if(hItem == hNode) + return hItem; + + /* Get hItem attributes */ + item.hItem = hItem; + item.mask = TVIF_HANDLE|TVIF_PARAM; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + /* Check whether we have child items */ + if (itemData->kind == ITREE_BRANCH) + { + /* Recursively traverse child items */ + HTREEITEM hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + hItemChild = winTreeFindNodeID(ih, hItemChild, hNode); + + /* StateID founded! */ + if(hItemChild) + return hItemChild; + } + /* Go to next sibling item */ + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); + } + + return NULL; +} + +static int winTreeGetNodeId(Ihandle* ih, HTREEITEM hItem) +{ + HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); + ih->data->id_control = -1; + if (winTreeFindNodeID(ih, hItemRoot, hItem)) + return ih->data->id_control; + else + return -1; +} + +static HTREEITEM winTreeFindUserDataID(Ihandle* ih, HTREEITEM hItem, void* userdata) +{ + TVITEM item; + winTreeItemData* itemData; + + while(hItem != NULL) + { + /* ID control to traverse items */ + ih->data->id_control++; + + /* Get hItem attributes */ + item.hItem = hItem; + item.mask = TVIF_HANDLE|TVIF_PARAM; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + /* userdata founded! */ + if(itemData->userdata == userdata) + return hItem; + + /* Check whether we have child items */ + if (itemData->kind == ITREE_BRANCH) + { + /* Recursively traverse child items */ + HTREEITEM hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + hItemChild = winTreeFindUserDataID(ih, hItemChild, userdata); + + /* userdata founded! */ + if (hItemChild) + return hItemChild; + } + + /* Go to next sibling item */ + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); + } + + return NULL; +} + +static int winTreeGetUserDataId(Ihandle* ih, void* userdata) +{ + HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); + ih->data->id_control = -1; + if (winTreeFindUserDataID(ih, hItemRoot, userdata)) + return ih->data->id_control; + else + return -1; +} + +static HTREEITEM winTreeFindNodeFromID(Ihandle* ih, HTREEITEM hItem) +{ + TVITEM item; + winTreeItemData* itemData; + + while(hItem != NULL) + { + /* ID control to traverse items */ + ih->data->id_control--; + + /* StateID founded! */ + if(ih->data->id_control < 0) + return hItem; + + /* Get hItem attributes */ + item.hItem = hItem; + item.mask = TVIF_HANDLE|TVIF_PARAM; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + /* Check whether we have child items */ + if (itemData->kind == ITREE_BRANCH) + { + /* Recursively traverse child items */ + HTREEITEM hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + hItemChild = winTreeFindNodeFromID(ih, hItemChild); + + /* StateID founded! */ + if(ih->data->id_control < 0) + return hItemChild; + } + + /* Go to next sibling item */ + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); + } + + return hItem; +} + +static HTREEITEM winTreeFindNodeFromString(Ihandle* ih, const char* name_id) +{ + if (name_id[0]) + { + HTREEITEM hRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); + iupStrToInt(name_id, &ih->data->id_control); + return winTreeFindNodeFromID(ih, hRoot); + } + else + return (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CARET, 0); +} + +/* Recursively, find a new brother for the item + that will have its depth changed. Returns the new brother. */ +static HTREEITEM winTreeFindNewBrother(Ihandle* ih, HTREEITEM hBrotherItem) +{ + TVITEM item; + winTreeItemData* itemData; + + while(hBrotherItem != NULL) + { + if(ih->data->id_control < 0) + return hBrotherItem; + + item.hItem = hBrotherItem; + item.mask = TVIF_HANDLE|TVIF_PARAM; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + if (itemData->kind == ITREE_BRANCH) + { + HTREEITEM hItemChild; + + ih->data->id_control--; + hItemChild = winTreeFindNewBrother(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hBrotherItem)); + + if(ih->data->id_control < 0) + return hItemChild; + } + + hBrotherItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hBrotherItem); + } + + return hBrotherItem; +} + +static HTREEITEM winTreeFindNodePointed(Ihandle* ih) +{ + TVHITTESTINFO info; + DWORD pos = GetMessagePos(); + info.pt.x = LOWORD(pos); + info.pt.y = HIWORD(pos); + + ScreenToClient(ih->handle, &info.pt); + + return (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)(LPTVHITTESTINFO)&info); +} + +int iupwinGetColor(const char* value, COLORREF *color) +{ + unsigned char r, g, b; + if (iupStrToRGB(value, &r, &g, &b)) + { + *color = RGB(r,g,b); + return 1; + } + return 0; +} + +/*****************************************************************************/ +/* ADDING ITEMS */ +/*****************************************************************************/ +void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* title, int add) +{ + TVITEM item, tviPrevItem; + TVINSERTSTRUCT tvins; + HTREEITEM hPrevItem = winTreeFindNodeFromString(ih, name_id); + int kindPrev; + winTreeItemData* itemData; + + if (!hPrevItem) + return; + + itemData = calloc(1, sizeof(winTreeItemData)); + itemData->image = -1; + itemData->image_expanded = -1; + itemData->kind = (unsigned char)kind; + + item.mask = TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT; + item.pszText = (char*)title; + item.lParam = (LPARAM)itemData; + + iupwinGetColor(iupAttribGetStr(ih, "FGCOLOR"), &itemData->color); + + if (kind == ITREE_BRANCH) + { + item.iSelectedImage = item.iImage = (int)ih->data->def_image_collapsed; + + if (ih->data->add_expanded) + { + item.mask |= TVIF_STATE; + item.state = item.stateMask = TVIS_EXPANDED; + item.iSelectedImage = item.iImage = (int)ih->data->def_image_expanded; + } + } + else + item.iSelectedImage = item.iImage = (int)ih->data->def_image_leaf; + + /* Save the heading level in the node's application-defined data area */ + tvins.item = item; + + /* get the KIND attribute of node selected */ + tviPrevItem.hItem = hPrevItem; + tviPrevItem.mask = TVIF_PARAM|TVIF_CHILDREN; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&tviPrevItem); + kindPrev = ((winTreeItemData*)tviPrevItem.lParam)->kind; + + /* Define the parent and the position to the new node inside + the list, using the KIND attribute of node selected */ + if (kindPrev == ITREE_BRANCH && add) + { + tvins.hParent = hPrevItem; + tvins.hInsertAfter = TVI_FIRST; /* insert the new node after item selected, as first child */ + } + else + { + tvins.hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hPrevItem); + tvins.hInsertAfter = hPrevItem; /* insert the new node after item selected */ + } + + /* Add the node to the tree-view control */ + SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins); + + if (kindPrev == ITREE_BRANCH && tviPrevItem.cChildren==0) + { + /* this is the first child, redraw to update the '+'/'-' buttons */ + iupdrvDisplayRedraw(ih); + } +} + +static void winTreeAddRootNode(Ihandle* ih) +{ + TVITEM item; + TVINSERTSTRUCT tvins; + HTREEITEM hNewItem; + winTreeItemData* itemData; + + itemData = calloc(1, sizeof(winTreeItemData)); + itemData->image = -1; + itemData->image_expanded = -1; + itemData->kind = ITREE_BRANCH; + + item.mask = TVIF_PARAM | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; + item.state = item.stateMask = TVIS_EXPANDED; + item.iSelectedImage = item.iImage = (int)ih->data->def_image_expanded; + item.lParam = (LPARAM)itemData; + + iupwinGetColor(iupAttribGetStr(ih, "FGCOLOR"), &itemData->color); + + /* Save the heading level in the node's application-defined data area */ + tvins.item = item; + tvins.hInsertAfter = TVI_FIRST; + tvins.hParent = TVI_ROOT; + + /* Add the node to the tree-view control */ + hNewItem = (HTREEITEM)SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins); + + /* MarkStart node */ + iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)hNewItem); + + /* Set the default VALUE */ + winTreeSetFocusNode(ih, hNewItem); +} + +static int winTreeIsItemExpanded(Ihandle* ih, HTREEITEM hItem) +{ + TVITEM item; + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_STATE; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + return (item.state & TVIS_EXPANDED) != 0; +} + +static void winTreeExpandItem(Ihandle* ih, HTREEITEM hItem, int expand) +{ + if (expand == -1) + expand = !winTreeIsItemExpanded(ih, hItem); /* toggle */ + + if (expand) + SendMessage(ih->handle, TVM_EXPAND, TVE_EXPAND, (LPARAM)hItem); + else + SendMessage(ih->handle, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hItem); +} + +/*****************************************************************************/ +/* EXPANDING AND STORING ITEMS */ +/*****************************************************************************/ +static void winTreeExpandTree(Ihandle* ih, HTREEITEM hItem, int expand) +{ + HTREEITEM hItemChild; + while(hItem != NULL) + { + hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + + /* Check whether we have child items */ + if (hItemChild) + { + winTreeExpandItem(ih, hItem, expand); + + /* Recursively traverse child items */ + winTreeExpandTree(ih, hItemChild, expand); + } + + /* Go to next sibling item */ + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); + } +} + +/*****************************************************************************/ +/* SELECTING ITEMS */ +/*****************************************************************************/ + +static int winTreeIsItemSelected(Ihandle* ih, HTREEITEM hItem) +{ + return ((SendMessage(ih->handle, TVM_GETITEMSTATE, (WPARAM)hItem, TVIS_SELECTED)) & TVIS_SELECTED)!=0; +} + +static void winTreeSelectItem(Ihandle* ih, HTREEITEM hItem, int select) +{ + TV_ITEM item; + item.mask = TVIF_STATE | TVIF_HANDLE; + item.stateMask = TVIS_SELECTED; + item.hItem = hItem; + + if (select == -1) + select = !winTreeIsItemSelected(ih, hItem); + + item.state = select ? TVIS_SELECTED : 0; + + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)&item); +} + +static HTREEITEM winTreeGetFocusNode(Ihandle* ih) +{ + return (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CARET, 0); +} + +/* ------------Comment from wxWidgets-------------------- + Helper function which tricks the standard control into changing the focused + item without changing anything else. */ +static void winTreeSetFocusNode(Ihandle* ih, HTREEITEM hItem) +{ + HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + if (hItem != hItemFocus) + { + /* remember the selection state of the item */ + int wasSelected = winTreeIsItemSelected(ih, hItem); + int wasFocusSelected = 0; + + if (iupwinIsVista()) + iupAttribSetStr(ih, "_IUPTREE_ALLOW_CHANGE", (char*)hItem); /* Vista Only */ + else + wasFocusSelected = hItemFocus && winTreeIsItemSelected(ih, hItemFocus); + + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + + if (wasFocusSelected) + { + /* prevent the tree from unselecting the old focus which it would do by default */ + SendMessage(ih->handle, TVM_SELECTITEM, TVGN_CARET, (LPARAM)NULL); /* remove the focus */ + winTreeSelectItem(ih, hItemFocus, 1); /* select again */ + } + + SendMessage(ih->handle, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItem); /* set focus, selection, and unselect the previous focus */ + + if (!wasSelected) + winTreeSelectItem(ih, hItem, 0); /* need to clear the selection if was not selected */ + + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + iupAttribSetStr(ih, "_IUPTREE_ALLOW_CHANGE", NULL); + } +} + +typedef struct _winTreeRange{ + HTREEITEM hItem1, hItem2; + char inside, clear; +}winTreeRange; + +static int winTreeSelectRangeFunc(Ihandle* ih, HTREEITEM hItem, winTreeRange* range) +{ + int end_range = 0; + + if (range->inside == 0) /* detect the range start */ + { + if (range->hItem1 == hItem) range->inside=1; + else if (range->hItem2 == hItem) range->inside=1; + } + else if (range->inside == 1) /* detect the range end */ + { + if (range->hItem1 == hItem) end_range=1; + else if (range->hItem2 == hItem) end_range=1; + } + + if (range->inside == 1) /* if inside, select */ + winTreeSelectItem(ih, hItem, 1); + else if (range->clear) /* if outside and clear, unselect */ + winTreeSelectItem(ih, hItem, 0); + + if (end_range || (range->inside && range->hItem1==range->hItem2)) + range->inside=-1; /* update after selecting the node */ + + return 1; +} + +static void winTreeSelectRange(Ihandle* ih, HTREEITEM hItemFrom, HTREEITEM hItemTo, int clear) +{ + winTreeRange range; + range.hItem1 = hItemFrom; + range.hItem2 = hItemTo; + range.inside = 0; + range.clear = (char)clear; + winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeSelectRangeFunc, &range); +} + +static void winTreeSelectAll(Ihandle* ih) +{ + HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); + winTreeSelectRange(ih, hItemRoot, NULL, 0); +} + +static void winTreeClearSelection(Ihandle* ih, HTREEITEM hItemExcept) +{ + winTreeSelectRange(ih, hItemExcept, hItemExcept, 1); +} + +static int winTreeInvertSelectFunc(Ihandle* ih, HTREEITEM hItem, void* userdata) +{ + winTreeSelectItem(ih, hItem, -1); + (void)userdata; + return 1; +} + +typedef struct _winTreeSelArray{ + Iarray* markedArray; + char is_handle; + int id_control; +}winTreeSelArray; + +static int winTreeSelectedArrayFunc(Ihandle* ih, HTREEITEM hItem, winTreeSelArray* selarray) +{ + selarray->id_control++; + + if (winTreeIsItemSelected(ih, hItem)) + { + if (selarray->is_handle) + { + HTREEITEM* hItemArrayData = (HTREEITEM*)iupArrayInc(selarray->markedArray); + int i = iupArrayCount(selarray->markedArray); + hItemArrayData[i-1] = hItem; + } + else + { + int* intArrayData = (int*)iupArrayInc(selarray->markedArray); + int i = iupArrayCount(selarray->markedArray); + intArrayData[i-1] = selarray->id_control; + } + } + + return 1; +} + +static Iarray* winTreeGetSelectedArray(Ihandle* ih) +{ + Iarray* markedArray = iupArrayCreate(1, sizeof(HTREEITEM)); + winTreeSelArray selarray; + selarray.markedArray = markedArray; + selarray.id_control = -1; + selarray.is_handle = 1; + + winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeSelectedArrayFunc, &selarray); + + return markedArray; +} + +static Iarray* winTreeGetSelectedArrayId(Ihandle* ih) +{ + Iarray* markedArray = iupArrayCreate(1, sizeof(int)); + winTreeSelArray selarray; + selarray.markedArray = markedArray; + selarray.id_control = -1; + selarray.is_handle = 0; + + winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeSelectedArrayFunc, &selarray); + + return markedArray; +} + + +/*****************************************************************************/ +/* COPYING ITEMS (Branches and its children) */ +/*****************************************************************************/ +/* Insert the copied item in a new location. Returns the new item. */ +static HTREEITEM winTreeCopyItem(Ihandle* ih, HTREEITEM hItem, HTREEITEM hParent, HTREEITEM hPosition, int full_copy) +{ + TVITEM item; + TVINSERTSTRUCT tvins; + char* title = iupStrGetMemory(255); + + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_STATE | TVIF_PARAM; + item.pszText = title; + item.cchTextMax = 255; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + + if (full_copy) /* during a full copy the userdata reference is not copied */ + { + /* create a new one */ + winTreeItemData* itemDataNew = malloc(sizeof(winTreeItemData)); + memcpy(itemDataNew, (void*)item.lParam, sizeof(winTreeItemData)); + itemDataNew->userdata = NULL; + item.lParam = (LPARAM)itemDataNew; + } + + /* Copy everything including user data reference */ + tvins.item = item; + tvins.hInsertAfter = hPosition; + tvins.hParent = hParent; + + /* Add the node to the tree-view control */ + return (HTREEITEM)SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins); +} + +static void winTreeCopyChildren(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hItemDst, int full_copy) +{ + HTREEITEM hChildSrc = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItemSrc); + HTREEITEM hNewItem = TVI_FIRST; + while (hChildSrc != NULL) + { + hNewItem = winTreeCopyItem(ih, hChildSrc, hItemDst, hNewItem, full_copy); /* Use the same order they where enumerated */ + + /* Recursively transfer all the items */ + winTreeCopyChildren(ih, hChildSrc, hNewItem, full_copy); + + /* Go to next sibling item */ + hChildSrc = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hChildSrc); + } +} + +/* Copies all items in a branch to a new location. Returns the new branch node. */ +static HTREEITEM winTreeCopyNode(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hItemDst, int full_copy) +{ + HTREEITEM hNewItem, hParent; + TVITEM item; + winTreeItemData* itemDataDst; + + /* Get DST node attributes */ + item.hItem = hItemDst; + item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemDataDst = (winTreeItemData*)item.lParam; + + if (itemDataDst->kind == ITREE_BRANCH && (item.state & TVIS_EXPANDED)) + { + /* copy as first child of expanded branch */ + hParent = hItemDst; + hItemDst = TVI_FIRST; + } + else + { + /* copy as next brother of item or collapsed branch */ + hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItemDst); + } + + hNewItem = winTreeCopyItem(ih, hItemSrc, hParent, hItemDst, full_copy); + + winTreeCopyChildren(ih, hItemSrc, hNewItem, full_copy); + + return hNewItem; +} + +/*****************************************************************************/ +/* MANIPULATING IMAGES */ +/*****************************************************************************/ +static void winTreeUpdateImages(Ihandle* ih, HTREEITEM hItem, int mode) +{ + HTREEITEM hItemChild; + TVITEM item; + winTreeItemData* itemData; + + /* called when one of the default images is changed */ + + while(hItem != NULL) + { + /* Get node attributes */ + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + if (itemData->kind == ITREE_BRANCH) + { + if (item.state & TVIS_EXPANDED) + { + if (mode == ITREE_UPDATEIMAGE_EXPANDED) + { + item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; + item.iSelectedImage = item.iImage = (itemData->image_expanded!=-1)? itemData->image_expanded: (int)ih->data->def_image_expanded; + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item); + } + } + else + { + if (mode == ITREE_UPDATEIMAGE_COLLAPSED) + { + item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; + item.iSelectedImage = item.iImage = (itemData->image!=-1)? itemData->image: (int)ih->data->def_image_collapsed; + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item); + } + } + + /* Recursively traverse child items */ + hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + winTreeUpdateImages(ih, hItemChild, mode); + } + else + { + if (mode == ITREE_UPDATEIMAGE_LEAF) + { + item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; + item.iSelectedImage = item.iImage = (itemData->image!=-1)? itemData->image: (int)ih->data->def_image_leaf; + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item); + } + } + + /* Go to next sibling node */ + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); + } +} + +static int winTreeGetImageIndex(Ihandle* ih, const char* name) +{ + HIMAGELIST image_list; + int count, i; + Iarray* bmpArray; + HBITMAP *bmpArrayData; + HBITMAP bmp = iupImageGetImage(name, ih, 0); + if (!bmp) + return -1; + + /* the array is used to avoi adding the same bitmap twice */ + bmpArray = (Iarray*)iupAttribGet(ih, "_IUPWIN_BMPARRAY"); + if (!bmpArray) + { + /* create the array if does not exist */ + bmpArray = iupArrayCreate(50, sizeof(HBITMAP)); + iupAttribSetStr(ih, "_IUPWIN_BMPARRAY", (char*)bmpArray); + } + + bmpArrayData = iupArrayGetData(bmpArray); + + image_list = (HIMAGELIST)SendMessage(ih->handle, TVM_GETIMAGELIST, TVSIL_NORMAL, 0); + if (!image_list) + { + int width, height; + + /* must use this info, since image can be a driver image loaded from resources */ + iupdrvImageGetInfo(bmp, &width, &height, NULL); + + /* create the image list if does not exist */ + image_list = ImageList_Create(width, height, ILC_COLOR32, 0, 50); + SendMessage(ih->handle, TVM_SETIMAGELIST, 0, (LPARAM)image_list); + } + + /* check if that bitmap is already added to the list, + but we can not compare with the actual bitmap at the list since it is a copy */ + count = ImageList_GetImageCount(image_list); + for (i = 0; i < count; i++) + { + if (bmpArrayData[i] == bmp) + return i; + } + + bmpArrayData = iupArrayInc(bmpArray); + bmpArrayData[i] = bmp; + return ImageList_Add(image_list, bmp, NULL); /* the bmp is duplicated at the list */ +} + + +/*****************************************************************************/ +/* CALLBACKS */ +/*****************************************************************************/ + +static int winTreeCallBranchLeafCb(Ihandle* ih, HTREEITEM hItem) +{ + TVITEM item; + winTreeItemData* itemData; + + /* Get Children: branch or leaf */ + item.mask = TVIF_HANDLE|TVIF_PARAM|TVIF_STATE; + item.hItem = hItem; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + if (itemData->kind == ITREE_BRANCH) + { + if (item.state & TVIS_EXPANDED) + { + IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB"); + if (cbBranchClose) + return cbBranchClose(ih, winTreeGetNodeId(ih, hItem)); + } + else + { + IFni cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB"); + if (cbBranchOpen) + return cbBranchOpen(ih, winTreeGetNodeId(ih, hItem)); + } + } + else + { + IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB"); + if (cbExecuteLeaf) + return cbExecuteLeaf(ih, winTreeGetNodeId(ih, hItem)); + } + + return IUP_DEFAULT; +} + +static void winTreeCallMultiSelectionCb(Ihandle* ih) +{ + IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTISELECTION_CB"); + if(cbMulti) + { + Iarray* markedArray = winTreeGetSelectedArrayId(ih); + int* id_hitem = (int*)iupArrayGetData(markedArray); + + cbMulti(ih, id_hitem, iupArrayCount(markedArray)); + + iupArrayDestroy(markedArray); + } + else + { + IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); + if (cbSelec) + { + Iarray* markedArray = winTreeGetSelectedArrayId(ih); + int* id_hitem = (int*)iupArrayGetData(markedArray); + int i, count = iupArrayCount(markedArray); + + for (i=0; i<count; i++) + cbSelec(ih, id_hitem[i], 1); + + iupArrayDestroy(markedArray); + } + } +} + +static void winTreeCallSelectionCb(Ihandle* ih, int status, HTREEITEM hItem) +{ + IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); + if (cbSelec) + { + if (ih->data->mark_mode == ITREE_MARK_MULTIPLE && IupGetCallback(ih,"MULTISELECTION_CB")) + { + if ((GetKeyState(VK_SHIFT) & 0x8000)) + return; + } + + if (iupAttribGet(ih, "_IUPTREE_IGNORE_SELECTION_CB")) + return; + + cbSelec(ih, winTreeGetNodeId(ih, hItem), status); + } +} + +static int winTreeCallDragDropCb(Ihandle* ih, HTREEITEM hItemDrag, HTREEITEM hItemDrop, int *is_ctrl) +{ + IFniiii cbDragDrop = (IFniiii)IupGetCallback(ih, "DRAGDROP_CB"); + int is_shift = 0; + if ((GetKeyState(VK_SHIFT) & 0x8000)) + is_shift = 1; + if ((GetKeyState(VK_CONTROL) & 0x8000)) + *is_ctrl = 1; + else + *is_ctrl = 0; + + if (cbDragDrop) + { + int drag_id = winTreeGetNodeId(ih, hItemDrag); + int drop_id = winTreeGetNodeId(ih, hItemDrop); + return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl); + } + + return IUP_CONTINUE; /* allow to move by default if callback not defined */ +} + + +/*****************************************************************************/ +/* GET AND SET ATTRIBUTES */ +/*****************************************************************************/ + + +static int winTreeSetImageBranchExpandedAttrib(Ihandle* ih, const char* value) +{ + ih->data->def_image_expanded = (void*)winTreeGetImageIndex(ih, value); + + /* Update all images, starting at root node */ + winTreeUpdateImages(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0), ITREE_UPDATEIMAGE_EXPANDED); + + return 1; +} + +static int winTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value) +{ + ih->data->def_image_collapsed = (void*)winTreeGetImageIndex(ih, value); + + /* Update all images, starting at root node */ + winTreeUpdateImages(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0), ITREE_UPDATEIMAGE_COLLAPSED); + + return 1; +} + +static int winTreeSetImageLeafAttrib(Ihandle* ih, const char* value) +{ + ih->data->def_image_leaf = (void*)winTreeGetImageIndex(ih, value); + + /* Update all images, starting at root node */ + winTreeUpdateImages(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0), ITREE_UPDATEIMAGE_LEAF); + + return 1; +} + +static int winTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + TVITEM item; + winTreeItemData* itemData; + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return 0; + + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + itemData->image_expanded = (short)winTreeGetImageIndex(ih, value); + + if (itemData->kind == ITREE_BRANCH && item.state & TVIS_EXPANDED) + { + if (itemData->image_expanded == -1) + item.iSelectedImage = item.iImage = (int)ih->data->def_image_expanded; + else + item.iSelectedImage = item.iImage = itemData->image_expanded; + item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(const LPTVITEM)&item); + } + + return 1; +} + +static int winTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + TVITEM item; + winTreeItemData* itemData; + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return 0; + + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + itemData->image = (short)winTreeGetImageIndex(ih, value); + + if (itemData->kind == ITREE_BRANCH) + { + if (!(item.state & TVIS_EXPANDED)) + { + if (itemData->image == -1) + item.iSelectedImage = item.iImage = (int)ih->data->def_image_collapsed; + else + item.iSelectedImage = item.iImage = itemData->image; + + item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(const LPTVITEM)&item); + } + } + else + { + if (itemData->image == -1) + item.iSelectedImage = item.iImage = (int)ih->data->def_image_leaf; + else + item.iSelectedImage = item.iImage = itemData->image; + + item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(const LPTVITEM)&item); + } + + return 1; +} + +static int winTreeSetTopItemAttrib(Ihandle* ih, const char* value) +{ + HTREEITEM hItem = winTreeFindNodeFromString(ih, value); + if (hItem) + SendMessage(ih->handle, TVM_ENSUREVISIBLE, 0, (LPARAM)hItem); + return 0; +} + +static int winTreeSetSpacingAttrib(Ihandle* ih, const char* value) +{ + if (!iupStrToInt(value, &ih->data->spacing)) + ih->data->spacing = 1; + + if(ih->data->spacing < 1) + ih->data->spacing = 1; + + if (ih->handle) + { + int old_spacing = iupAttribGetInt(ih, "_IUPWIN_OLDSPACING"); + int height = SendMessage(ih->handle, TVM_GETITEMHEIGHT, 0, 0); + height -= 2*old_spacing; + height += 2*ih->data->spacing; + SendMessage(ih->handle, TVM_SETITEMHEIGHT, height, 0); + iupAttribSetInt(ih, "_IUPWIN_OLDSPACING", ih->data->spacing); + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ +} + +static int winTreeSetExpandAllAttrib(Ihandle* ih, const char* value) +{ + HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); + HTREEITEM hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItemRoot); /* skip the root node that is always expanded */ + int expand = iupStrBoolean(value); + winTreeExpandTree(ih, hItem, expand); + return 0; +} + +static int winTreeSetBgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + if (iupStrToRGB(value, &r, &g, &b)) + { + COLORREF cr = RGB(r,g,b); + SendMessage(ih->handle, TVM_SETBKCOLOR, 0, (LPARAM)cr); + + /* update internal image cache */ + iupTreeUpdateImages(ih); + } + return 0; +} + +static char* winTreeGetBgColorAttrib(Ihandle* ih) +{ + COLORREF cr = (COLORREF)SendMessage(ih->handle, TVM_GETBKCOLOR, 0, 0); + if (cr == (COLORREF)-1) + return IupGetGlobal("TXTBGCOLOR"); + else + { + char* str = iupStrGetMemory(20); + sprintf(str, "%d %d %d", (int)GetRValue(cr), (int)GetGValue(cr), (int)GetBValue(cr)); + return str; + } +} + +static void winTreeSetRenameCaretPos(HWND hEdit, const char* value) +{ + int pos = 1; + + if (iupStrToInt(value, &pos)) + { + if (pos < 1) pos = 1; + pos--; /* IUP starts at 1 */ + + SendMessage(hEdit, EM_SETSEL, (WPARAM)pos, (LPARAM)pos); + } +} + +static void winTreeSetRenameSelectionPos(HWND hEdit, const char* value) +{ + int start = 1, end = 1; + + if (iupStrToIntInt(value, &start, &end, ':') != 2) + return; + + if(start < 1 || end < 1) + return; + + start--; /* IUP starts at 1 */ + end--; + + SendMessage(hEdit, EM_SETSEL, (WPARAM)start, (LPARAM)end); +} + +static char* winTreeGetTitle(Ihandle* ih, HTREEITEM hItem) +{ + TVITEM item; + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_TEXT; + item.pszText = iupStrGetMemory(255); + item.cchTextMax = 255; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + return item.pszText; +} + +static char* winTreeGetTitleAttrib(Ihandle* ih, const char* name_id) +{ + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return NULL; + return winTreeGetTitle(ih, hItem); +} + +static int winTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + TVITEM item; + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return 0; + + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_TEXT; + item.pszText = (char*)value; + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(const LPTVITEM)&item); + return 0; +} + +static char* winTreeGetFindUserDataAttrib(Ihandle* ih, const char* name_id) +{ + int id; + char* str = (char*)(name_id+1); /* skip ':' */ + void* userdata = NULL; + if (sscanf(str, "%p", &userdata)!=1) + return NULL; + id = winTreeGetUserDataId(ih, userdata); + if (id == -1) + return NULL; + str = iupStrGetMemory(16); + sprintf(str, "%d", id); + return str; +} + +static char* winTreeGetUserDataAttrib(Ihandle* ih, const char* name_id) +{ + TVITEM item; + winTreeItemData* itemData; + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return NULL; + + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_PARAM; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + return itemData->userdata; +} + +static int winTreeSetUserDataAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + TVITEM item; + winTreeItemData* itemData; + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return 0; + + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_PARAM; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + itemData->userdata = (void*)value; + + return 0; +} + +static char* winTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id) +{ + TVITEM item; + winTreeItemData* itemData; + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return NULL; + + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_PARAM; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + return iupwinFindHFont(itemData->hFont); +} + +static int winTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + TVITEM item; + winTreeItemData* itemData; + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return 0; + + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_PARAM; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + if (value) + itemData->hFont = iupwinGetHFont(value); + else + itemData->hFont = NULL; + + iupdrvDisplayUpdate(ih); + + return 0; +} + +static char* winTreeGetIndentationAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(255); + int indent = (int)SendMessage(ih->handle, TVM_GETINDENT, 0, 0); + sprintf(str, "%d", indent); + return str; +} + +static int winTreeSetIndentationAttrib(Ihandle* ih, const char* value) +{ + int indent; + if (iupStrToInt(value, &indent)) + SendMessage(ih->handle, TVM_SETINDENT, (WPARAM)indent, 0); + return 0; +} + +static char* winTreeGetStateAttrib(Ihandle* ih, const char* name_id) +{ + TVITEM item; + winTreeItemData* itemData; + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return NULL; + + item.hItem = hItem; + item.mask = TVIF_HANDLE|TVIF_PARAM; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + if (itemData->kind == ITREE_BRANCH) + { + if (winTreeIsItemExpanded(ih, hItem)) + return "EXPANDED"; + else + return "COLLAPSED"; + } + + return NULL; +} + +static int winTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return 0; + + winTreeExpandItem(ih, hItem, iupStrEqualNoCase(value, "EXPANDED")); + return 0; +} + +static char* winTreeGetDepthAttrib(Ihandle* ih, const char* name_id) +{ + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); + int depth = 0; + char* str; + + if (!hItem) + return NULL; + + while((hItemRoot != hItem) && (hItem != NULL)) + { + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem); + depth++; + } + + str = iupStrGetMemory(10); + sprintf(str, "%d", depth); + return str; +} + +static int winTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + HTREEITEM hItemDst, hParent, hItemSrc; + + if (!ih->handle) /* do not store the action before map */ + return 0; + hItemSrc = winTreeFindNodeFromString(ih, name_id); + if (!hItemSrc) + return 0; + hItemDst = winTreeFindNodeFromString(ih, value); + if (!hItemDst) + return 0; + + /* If Drag item is an ancestor of Drop item then return */ + hParent = hItemDst; + while(hParent) + { + hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hParent); + if (hParent == hItemSrc) + return 0; + } + + /* Copying the node and its children to the new position */ + winTreeCopyNode(ih, hItemSrc, hItemDst, 0); /* not a full copy, preserve user data */ + + /* do not delete the user data, we copy the references in CopyNode */ + SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemSrc); + + return 0; +} + +static int winTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + HTREEITEM hItemDst, hParent, hItemSrc; + + if (!ih->handle) /* do not store the action before map */ + return 0; + hItemSrc = winTreeFindNodeFromString(ih, name_id); + if (!hItemSrc) + return 0; + hItemDst = winTreeFindNodeFromString(ih, value); + if (!hItemDst) + return 0; + + /* If Drag item is an ancestor of Drop item then return */ + hParent = hItemDst; + while(hParent) + { + hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hParent); + if (hParent == hItemSrc) + return 0; + } + + /* Copying the node and its children to the new position */ + winTreeCopyNode(ih, hItemSrc, hItemDst, 1); + + return 0; +} + +static char* winTreeGetColorAttrib(Ihandle* ih, const char* name_id) +{ + unsigned char r, g, b; + char* str; + TVITEM item; + winTreeItemData* itemData; + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return NULL; + + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_PARAM; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + r = GetRValue(itemData->color); + g = GetGValue(itemData->color); + b = GetBValue(itemData->color); + + str = iupStrGetMemory(12); + sprintf(str, "%d %d %d", r, g, b); + return str; +} + +static int winTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + unsigned char r, g, b; + TVITEM item; + winTreeItemData* itemData; + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return 0; + + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_PARAM; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + if (iupStrToRGB(value, &r, &g, &b)) + { + itemData->color = RGB(r,g,b); + iupdrvDisplayUpdate(ih); + } + + return 0; +} + +static int winTreeSetFgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + + if (iupStrToRGB(value, &r, &g, &b)) + { + COLORREF color = RGB(r,g,b); + SendMessage(ih->handle, TVM_SETTEXTCOLOR, 0, (LPARAM)color); + } + else + SendMessage(ih->handle, TVM_SETTEXTCOLOR, 0, (LPARAM)CLR_DEFAULT); + + return 0; +} + +static char* winTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) +{ + int count; + char* str; + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return NULL; + + count = 0; + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + while(hItem != NULL) + { + count++; + + /* Go to next sibling item */ + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); + } + + str = iupStrGetMemory(10); + sprintf(str, "%d", count); + return str; +} + +static char* winTreeGetCountAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(10); + sprintf(str, "%d", (int)SendMessage(ih->handle, TVM_GETCOUNT, 0, 0)); + return str; +} + +static char* winTreeGetKindAttrib(Ihandle* ih, const char* name_id) +{ + TVITEM item; + winTreeItemData* itemData; + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return NULL; + + item.hItem = hItem; + item.mask = TVIF_HANDLE|TVIF_PARAM; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + if(itemData->kind == ITREE_BRANCH) + return "BRANCH"; + else + return "LEAF"; +} + +static char* winTreeGetParentAttrib(Ihandle* ih, const char* name_id) +{ + char* str; + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return NULL; + + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem); + if (!hItem) + return NULL; + + str = iupStrGetMemory(10); + sprintf(str, "%d", winTreeGetNodeId(ih, hItem)); + return str; +} + +static void winTreeDelNodeData(Ihandle* ih, HTREEITEM hItem) +{ + TVITEM item; + HTREEITEM hChildItem; + + item.hItem = hItem; + item.mask = TVIF_HANDLE|TVIF_PARAM; + if (SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item)) + { + winTreeItemData* itemData = (winTreeItemData*)item.lParam; + if (itemData) + { + IFnis cb = (IFnis)IupGetCallback(ih, "NODEREMOVED_CB"); + if (cb) cb(ih, winTreeGetNodeId(ih, hItem), (char*)itemData->userdata); + free(itemData); + item.lParam = (LPARAM)NULL; + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item); + } + } + + hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + while (hChildItem) + { + winTreeDelNodeData(ih, hChildItem); + hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hChildItem); + } +} + +static int winTreeSetDelNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + if(iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */ + { + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); + + /* the root node can't be deleted */ + if(!hItem || hItem == hItemRoot) + return 0; + + /* deleting the specified node (and it's children) */ + winTreeDelNodeData(ih, hItem); + SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItem); + + return 0; + } + else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */ + { + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + HTREEITEM hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + + if(!hItem) + return 0; + + /* deleting the selected node's children */ + while (hChildItem) + { + winTreeDelNodeData(ih, hChildItem); + SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hChildItem); + hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + } + + return 0; + } + else if(iupStrEqualNoCase(value, "MARKED")) + { + int i, count; + Iarray* markedArray; + HTREEITEM* hItemArrayData; + HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); + + /* Delete the array of marked nodes */ + markedArray = winTreeGetSelectedArray(ih); + hItemArrayData = (HTREEITEM*)iupArrayGetData(markedArray); + count = iupArrayCount(markedArray); + + for(i = 0; i < count; i++) + { + if (hItemArrayData[i] != hItemRoot) /* the root node can't be deleted */ + { + winTreeDelNodeData(ih, hItemArrayData[i]); + SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemArrayData[i]); + } + } + + iupArrayDestroy(markedArray); + + return 0; + } + + return 0; +} + +static int winTreeSetRenameAttrib(Ihandle* ih, const char* value) +{ + HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + if (ih->data->show_rename) + { + IFni cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); + if (cbShowRename) + cbShowRename(ih, winTreeGetNodeId(ih, hItemFocus)); + + SetFocus(ih->handle); /* the tree must have focus to activate the edit */ + SendMessage(ih->handle, TVM_EDITLABEL, 0, (LPARAM)hItemFocus); + } + else + { + IFnis cbRenameNode = (IFnis)IupGetCallback(ih, "RENAMENODE_CB"); + if (cbRenameNode) + cbRenameNode(ih, winTreeGetNodeId(ih, hItemFocus), winTreeGetTitle(ih, hItemFocus)); + } + + (void)value; + return 0; +} + +static char* winTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) +{ + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return NULL; + + if (winTreeIsItemSelected(ih, hItem)) + return "YES"; + else + return "NO"; +} + +static int winTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return 0; + + winTreeSelectItem(ih, hItem, iupStrBoolean(value)); + return 0; +} + +static int winTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id) +{ + HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id); + if (!hItem) + return 0; + + iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)hItem); + + return 1; +} + +static char* winTreeGetValueAttrib(Ihandle* ih) +{ + char* str; + HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + if (!hItemFocus) + return "0"; /* default VALUE is root */ + + str = iupStrGetMemory(16); + sprintf(str, "%d", winTreeGetNodeId(ih, hItemFocus)); + return str; +} + +static int winTreeSetMarkAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + return 0; + + if(iupStrEqualNoCase(value, "BLOCK")) + { + HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + winTreeSelectRange(ih, (HTREEITEM)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"), hItemFocus, 0); + } + else if(iupStrEqualNoCase(value, "CLEARALL")) + winTreeClearSelection(ih, NULL); + else if(iupStrEqualNoCase(value, "MARKALL")) + winTreeSelectAll(ih); + else if(iupStrEqualNoCase(value, "INVERTALL")) /* INVERTALL *MUST* appear before INVERT, or else INVERTALL will never be called. */ + winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeInvertSelectFunc, NULL); + else if(iupStrEqualPartial(value, "INVERT")) /* iupStrEqualPartial allows the use of "INVERTid" form */ + { + HTREEITEM hItem = winTreeFindNodeFromString(ih, &value[strlen("INVERT")]); + if (!hItem) + return 0; + + winTreeSelectItem(ih, hItem, -1); /* toggle */ + } + else + { + HTREEITEM hItem1, hItem2; + + char str1[50], str2[50]; + if (iupStrToStrStr(value, str1, str2, '-')!=2) + return 0; + + hItem1 = winTreeFindNodeFromString(ih, str1); + if (!hItem1) + return 0; + hItem2 = winTreeFindNodeFromString(ih, str2); + if (!hItem2) + return 0; + + winTreeSelectRange(ih, hItem1, hItem2, 0); + } + + return 1; +} + +static int winTreeSetValueAttrib(Ihandle* ih, const char* value) +{ + HTREEITEM hItem = NULL; + HTREEITEM hItemFocus; + + if (winTreeSetMarkAttrib(ih, value)) + return 0; + + hItemFocus = winTreeGetFocusNode(ih); + + if(iupStrEqualNoCase(value, "ROOT")) + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); + else if(iupStrEqualNoCase(value, "LAST")) + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_LASTVISIBLE, 0); + else if(iupStrEqualNoCase(value, "PGUP")) + { + int i; + HTREEITEM hItemPrev = hItemFocus; + HTREEITEM hItemNext = hItemFocus; + for(i = 0; i < 10; i++) + { + hItemNext = hItemPrev; + hItemPrev = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItemPrev); + if(hItemPrev == NULL) + { + hItemPrev = hItemNext; + break; + } + } + + hItem = hItemPrev; + } + else if(iupStrEqualNoCase(value, "PGDN")) + { + int i; + HTREEITEM hItemPrev = hItemFocus; + HTREEITEM hItemNext = hItemFocus; + + for(i = 0; i < 10; i++) + { + hItemPrev = hItemNext; + hItemNext = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItemNext); + if(hItemNext == NULL) + { + hItemNext = hItemPrev; + break; + } + } + + hItem = hItemNext; + } + else if(iupStrEqualNoCase(value, "NEXT")) + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItemFocus); + else if(iupStrEqualNoCase(value, "PREVIOUS")) + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItemFocus); + else + hItem = winTreeFindNodeFromString(ih, value); + + if (hItem) + { + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + { + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + winTreeSelectItem(ih, hItem, 1); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + } + winTreeSetFocusNode(ih, hItem); + } + + return 0; +} + +void iupdrvTreeUpdateMarkMode(Ihandle *ih) +{ + /* does nothing, must handle single and multiple selection manually in Windows */ + (void)ih; +} + +/*********************************************************************************************************/ + + +static int winTreeEditProc(Ihandle* ih, HWND cbedit, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + switch (msg) + { + case WM_GETDLGCODE: + { + MSG* pMsg = (MSG*)lp; + + if (pMsg && (pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN)) + { + if (pMsg->wParam == VK_ESCAPE || pMsg->wParam == VK_RETURN) + { + /* these keys are not processed if the return code is not this */ + *result = DLGC_WANTALLKEYS; + return 1; + } + } + } + } + + (void)wp; + (void)cbedit; + (void)ih; + return 0; +} + +static LRESULT CALLBACK winTreeEditWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + int ret = 0; + LRESULT result = 0; + WNDPROC oldProc; + Ihandle *ih; + + ih = iupwinHandleGet(hwnd); + if (!ih) + return DefWindowProc(hwnd, msg, wp, lp); /* should never happen */ + + /* retrieve the control previous procedure for subclassing */ + oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_EDITOLDPROC_CB"); + + ret = winTreeEditProc(ih, hwnd, msg, wp, lp, &result); + + if (ret) + return result; + else + return CallWindowProc(oldProc, hwnd, msg, wp, lp); +} + +static void winTreeDrag(Ihandle* ih, int x, int y) +{ + HTREEITEM hItemDrop; + + HIMAGELIST dragImageList = (HIMAGELIST)iupAttribGet(ih, "_IUPTREE_DRAGIMAGELIST"); + if (dragImageList) + { + POINT pnt; + pnt.x = x; + pnt.y = y; + GetCursorPos(&pnt); + ClientToScreen(GetDesktopWindow(), &pnt) ; + ImageList_DragMove(pnt.x, pnt.y); + } + + if ((hItemDrop = winTreeFindNodePointed(ih)) != NULL) + { + if(dragImageList) + ImageList_DragShowNolock(FALSE); + + SendMessage(ih->handle, TVM_SELECTITEM, TVGN_DROPHILITE, (LPARAM)hItemDrop); + + /* store the drop item to be executed */ + iupAttribSetStr(ih, "_IUPTREE_DROPITEM", (char*)hItemDrop); + + if(dragImageList) + ImageList_DragShowNolock(TRUE); + } +} + +static void winTreeDrop(Ihandle* ih) +{ + HTREEITEM hItemDrag = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_DRAGITEM"); + HTREEITEM hItemDrop = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_DROPITEM"); + HIMAGELIST dragImageList = (HIMAGELIST)iupAttribGet(ih, "_IUPTREE_DRAGIMAGELIST"); + HTREEITEM hParent; + int is_ctrl; + + if (dragImageList) + { + ImageList_DragLeave(ih->handle); + ImageList_EndDrag(); + ImageList_Destroy(dragImageList); + iupAttribSetStr(ih, "_IUPTREE_DRAGIMAGELIST", NULL); + } + + ReleaseCapture(); + ShowCursor(TRUE); + + /* Remove drop target highlighting */ + SendMessage(ih->handle, TVM_SELECTITEM, TVGN_DROPHILITE, (LPARAM)NULL); + + iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", NULL); + iupAttribSetStr(ih, "_IUPTREE_DROPITEM", NULL); + + if (!hItemDrop || hItemDrag == hItemDrop) + return; + + /* If Drag item is an ancestor of Drop item then return */ + hParent = hItemDrop; + while(hParent) + { + hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hParent); + if (hParent == hItemDrag) + return; + } + + if (winTreeCallDragDropCb(ih, hItemDrag, hItemDrop, &is_ctrl) == IUP_CONTINUE) + { + /* Copy the dragged item to the new position. */ + HTREEITEM hItemNew = winTreeCopyNode(ih, hItemDrag, hItemDrop, is_ctrl); + + if (!is_ctrl) + { + /* do not delete the user data, we copy the references in CopyNode */ + SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemDrag); + } + + SendMessage(ih->handle, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItemNew); /* set focus and selection */ + } +} + +static void winTreeExtendSelect(Ihandle* ih, int x, int y) +{ + HTREEITEM hItemFirstSel; + TVHITTESTINFO info; + HTREEITEM hItem; + info.pt.x = x; + info.pt.y = y; + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)&info); + + if (!(info.flags & TVHT_ONITEM) || !hItem) + return; + + hItemFirstSel = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_FIRSTSELITEM"); + if (hItemFirstSel) + { + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + winTreeSelectRange(ih, hItemFirstSel, hItem, 1); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + + iupAttribSetStr(ih, "_IUPTREE_LASTSELITEM", (char*)hItem); + winTreeSetFocusNode(ih, hItem); + } +} + +static int winTreeMouseMultiSelect(Ihandle* ih, int x, int y) +{ + TVHITTESTINFO info; + HTREEITEM hItem; + info.pt.x = x; + info.pt.y = y; + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)&info); + + if (!(info.flags & TVHT_ONITEM) || !hItem) + return 0; + + if (GetKeyState(VK_CONTROL) & 0x8000) /* Control key is down */ + { + /* Toggle selection state */ + winTreeSelectItem(ih, hItem, -1); + iupAttribSetStr(ih, "_IUPTREE_FIRSTSELITEM", (char*)hItem); + + winTreeCallSelectionCb(ih, winTreeIsItemSelected(ih, hItem), hItem); + winTreeSetFocusNode(ih, hItem); + + return 1; + } + else if (GetKeyState(VK_SHIFT) & 0x8000) /* Shift key is down */ + { + HTREEITEM hItemFirstSel = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_FIRSTSELITEM"); + if (hItemFirstSel) + { + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + winTreeSelectRange(ih, hItemFirstSel, hItem, 1); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + + winTreeCallMultiSelectionCb(ih); + winTreeSetFocusNode(ih, hItem); + return 1; + } + } + + /* simple click */ + winTreeClearSelection(ih, hItem); + iupAttribSetStr(ih, "_IUPTREE_FIRSTSELITEM", (char*)hItem); + iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "1"); + + return 0; +} + +static int winTreeProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + switch (msg) + { + case WM_CTLCOLOREDIT: + { + HWND hEdit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); + if (hEdit) + { + winTreeItemData* itemData = (winTreeItemData*)iupAttribGet(ih, "_IUPWIN_EDIT_DATA"); + HDC hDC = (HDC)wp; + COLORREF cr; + + SetTextColor(hDC, itemData->color); + + cr = (COLORREF)SendMessage(ih->handle, TVM_GETBKCOLOR, 0, 0); + SetBkColor(hDC, cr); + SetDCBrushColor(hDC, cr); + *result = (LRESULT)GetStockObject(DC_BRUSH); + return 1; + } + + break; + } + case WM_SETFOCUS: + case WM_KILLFOCUS: + { + /* ------------Comment from wxWidgets-------------------- + the tree control greys out the selected item when it loses focus and + paints it as selected again when it regains it, but it won't do it + for the other items itself - help it */ + if (ih->data->mark_mode == ITREE_MARK_MULTIPLE) + { + HTREEITEM hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_FIRSTVISIBLE, 0); + RECT rect; + + while(hItemChild != NULL) + { + *(HTREEITEM*)&rect = hItemChild; + if (SendMessage(ih->handle, TVM_GETITEMRECT, TRUE, (LPARAM)&rect)) + InvalidateRect(ih->handle, &rect, FALSE); + + /* Go to next visible item */ + hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItemChild); + } + } + break; + } + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + { + if (iupwinBaseProc(ih, msg, wp, lp, result)==1) + return 1; + + if (wp == VK_RETURN) + { + HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + if (winTreeCallBranchLeafCb(ih, hItemFocus) != IUP_IGNORE) + winTreeExpandItem(ih, hItemFocus, -1); + + *result = 0; + return 1; + } + else if (wp == VK_F2) + { + winTreeSetRenameAttrib(ih, NULL); + *result = 0; + return 1; + } + else if (wp == VK_SPACE) + { + if (GetKeyState(VK_CONTROL) & 0x8000) + { + HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + /* Toggle selection state */ + winTreeSelectItem(ih, hItemFocus, -1); + } + } + else if (wp == VK_UP || wp == VK_DOWN) + { + HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + if (wp == VK_UP) + hItemFocus = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItemFocus); + else + hItemFocus = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItemFocus); + if (!hItemFocus) + return 0; + + if (GetKeyState(VK_CONTROL) & 0x8000) + { + /* Only move focus */ + winTreeSetFocusNode(ih, hItemFocus); + + *result = 0; + return 1; + } + else if (GetKeyState(VK_SHIFT) & 0x8000) + { + HTREEITEM hItemFirstSel = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_FIRSTSELITEM"); + if (hItemFirstSel) + { + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1"); + winTreeSelectRange(ih, hItemFirstSel, hItemFocus, 1); + iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL); + + winTreeCallMultiSelectionCb(ih); + winTreeSetFocusNode(ih, hItemFocus); + + *result = 0; + return 1; + } + } + + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE) + { + iupAttribSetStr(ih, "_IUPTREE_FIRSTSELITEM", (char*)hItemFocus); + winTreeClearSelection(ih, NULL); + /* normal processing will select the focus item */ + } + } + + return 0; + } + case WM_LBUTTONDOWN: + if (iupwinButtonDown(ih, msg, wp, lp)==-1) + { + *result = 0; + return 1; + } + + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE) + { + /* must set focus on left button down or the tree won't show its focus */ + if (iupAttribGetBoolean(ih, "CANFOCUS")) + SetFocus(ih->handle); + + if (winTreeMouseMultiSelect(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp))) + { + *result = 0; /* abort the normal processing if we process multiple selection */ + return 1; + } + } + break; + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + if (iupwinButtonDown(ih, msg, wp, lp)==-1) + { + *result = 0; + return 1; + } + break; + case WM_MOUSEMOVE: + if (ih->data->show_dragdrop && (HTREEITEM)iupAttribGet(ih, "_IUPTREE_DRAGITEM") != NULL) + winTreeDrag(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp)); + else if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT")) + winTreeExtendSelect(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp)); + + iupwinMouseMove(ih, msg, wp, lp); + break; + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + if (iupwinButtonUp(ih, msg, wp, lp)==-1) + { + *result = 0; + return 1; + } + + if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT")) + { + iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", NULL); + if (iupAttribGet(ih, "_IUPTREE_LASTSELITEM")) + { + winTreeCallMultiSelectionCb(ih); + iupAttribSetStr(ih, "_IUPTREE_LASTSELITEM", NULL); + } + } + + if (ih->data->show_dragdrop && (HTREEITEM)iupAttribGet(ih, "_IUPTREE_DRAGITEM") != NULL) + winTreeDrop(ih); + + break; + case WM_CHAR: + { + if (wp==VK_TAB) /* the keys have the same definitions as the chars */ + { + *result = 0; + return 1; /* abort default processing to avoid beep */ + } + break; + } + } + + return iupwinBaseProc(ih, msg, wp, lp, result); +} + +static COLORREF winTreeInvertColor(COLORREF color) +{ + return RGB(~GetRValue(color), ~GetGValue(color), ~GetBValue(color)); +} + +static int winTreeWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) +{ + if (msg_info->code == TVN_ITEMCHANGINGA || msg_info->code == TVN_ITEMCHANGINGW) /* Vista Only */ + { + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE) + { + NMTVITEMCHANGE* info = (NMTVITEMCHANGE*)msg_info; + HTREEITEM hItem = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_ALLOW_CHANGE"); + if (hItem && hItem != info->hItem) /* Workaround for Vista SetFocus */ + { + *result = TRUE; /* prevent the change */ + return 1; + } + } + } + else if (msg_info->code == TVN_SELCHANGED) + { + NMTREEVIEW* info = (NMTREEVIEW*)msg_info; + winTreeCallSelectionCb(ih, 0, info->itemOld.hItem); /* node unselected */ + winTreeCallSelectionCb(ih, 1, info->itemNew.hItem); /* node selected */ + } + else if(msg_info->code == TVN_BEGINLABELEDIT) + { + char* value; + HWND hEdit; + NMTVDISPINFO* info = (NMTVDISPINFO*)msg_info; + + if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT")) + { + *result = TRUE; /* prevent the change */ + return 1; + } + + hEdit = (HWND)SendMessage(ih->handle, TVM_GETEDITCONTROL, 0, 0); + + /* save the edit box. */ + iupwinHandleAdd(ih, hEdit); + iupAttribSetStr(ih, "_IUPWIN_EDITBOX", (char*)hEdit); + + /* subclass the edit box. */ + IupSetCallback(ih, "_IUPWIN_EDITOLDPROC_CB", (Icallback)GetWindowLongPtr(hEdit, GWLP_WNDPROC)); + SetWindowLongPtr(hEdit, GWLP_WNDPROC, (LONG_PTR)winTreeEditWinProc); + + value = iupAttribGetStr(ih, "RENAMECARET"); + if (value) + winTreeSetRenameCaretPos(hEdit, value); + + value = iupAttribGetStr(ih, "RENAMESELECTION"); + if (value) + winTreeSetRenameSelectionPos(hEdit, value); + + { + winTreeItemData* itemData; + TVITEM item; + item.hItem = info->item.hItem; + item.mask = TVIF_HANDLE | TVIF_PARAM; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + iupAttribSetStr(ih, "_IUPWIN_EDIT_DATA", (char*)itemData); + + if (itemData->hFont) + SendMessage(hEdit, WM_SETFONT, (WPARAM)itemData->hFont, MAKELPARAM(TRUE,0)); + } + } + else if(msg_info->code == TVN_ENDLABELEDIT) + { + NMTVDISPINFO* info = (NMTVDISPINFO*)msg_info; + + iupAttribSetStr(ih, "_IUPWIN_EDITBOX", NULL); + + if (info->item.pszText) + { + IFnis cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB"); + if (cbRename) + { + if (cbRename(ih, winTreeGetNodeId(ih, info->item.hItem), info->item.pszText) == IUP_IGNORE) + { + *result = FALSE; + return 1; + } + } + + *result = TRUE; + return 1; + } + } + else if(msg_info->code == TVN_BEGINDRAG) + { + if (ih->data->show_dragdrop) + { + NMTREEVIEW* pNMTreeView = (NMTREEVIEW*)msg_info; + HTREEITEM hItemDrag = pNMTreeView->itemNew.hItem; + HIMAGELIST dragImageList; + + /* store the drag-and-drop item */ + iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", (char*)hItemDrag); + + /* get the image list for dragging */ + dragImageList = (HIMAGELIST)SendMessage(ih->handle, TVM_CREATEDRAGIMAGE, 0, (LPARAM)hItemDrag); + if (dragImageList) + { + POINT pt = pNMTreeView->ptDrag; + ImageList_BeginDrag(dragImageList, 0, 0, 0); + + ClientToScreen(ih->handle, &pt); + ImageList_DragEnter(NULL, pt.x, pt.y); + + iupAttribSetStr(ih, "_IUPTREE_DRAGIMAGELIST", (char*)dragImageList); + } + + ShowCursor(FALSE); + SetCapture(ih->handle); /* drag only inside the tree */ + } + } + else if(msg_info->code == NM_DBLCLK) + { + HTREEITEM hItemFocus = winTreeGetFocusNode(ih); + TVITEM item; + winTreeItemData* itemData; + + /* Get Children: branch or leaf */ + item.mask = TVIF_HANDLE|TVIF_PARAM; + item.hItem = hItemFocus; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + if (itemData->kind == ITREE_LEAF) + { + IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB"); + if(cbExecuteLeaf) + cbExecuteLeaf(ih, winTreeGetNodeId(ih, hItemFocus)); + } + } + else if(msg_info->code == TVN_ITEMEXPANDING) + { + /* mouse click by user: click on the "+" sign or double click on the selected node */ + NMTREEVIEW* tree_info = (NMTREEVIEW*)msg_info; + HTREEITEM hItem = tree_info->itemNew.hItem; + + if (winTreeCallBranchLeafCb(ih, hItem) != IUP_IGNORE) + { + TVITEM item; + winTreeItemData* itemData = (winTreeItemData*)tree_info->itemNew.lParam; + + if (tree_info->action == TVE_EXPAND) + item.iSelectedImage = item.iImage = (itemData->image_expanded!=-1)? itemData->image_expanded: (int)ih->data->def_image_expanded; + else + item.iSelectedImage = item.iImage = (itemData->image!=-1)? itemData->image: (int)ih->data->def_image_collapsed; + + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; + SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item); + } + else + { + *result = TRUE; /* prevent the change */ + return 1; + } + } + else if(msg_info->code == NM_RCLICK) + { + HTREEITEM hItem = winTreeFindNodePointed(ih); + IFni cbRightClick = (IFni)IupGetCallback(ih, "RIGHTCLICK_CB"); + if (cbRightClick) + cbRightClick(ih, winTreeGetNodeId(ih, hItem)); + } + else if (msg_info->code == NM_CUSTOMDRAW) + { + NMTVCUSTOMDRAW *customdraw = (NMTVCUSTOMDRAW*)msg_info; + + if (customdraw->nmcd.dwDrawStage == CDDS_PREPAINT) + { + *result = CDRF_NOTIFYPOSTPAINT|CDRF_NOTIFYITEMDRAW; + return 1; + } + + if (customdraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) + { + TVITEM item; + winTreeItemData* itemData; + HTREEITEM hItem = (HTREEITEM)customdraw->nmcd.dwItemSpec; + + item.hItem = hItem; + item.mask = TVIF_HANDLE | TVIF_PARAM; + SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item); + itemData = (winTreeItemData*)item.lParam; + + if (winTreeIsItemSelected(ih, hItem)) + customdraw->clrText = winTreeInvertColor(itemData->color); + else + customdraw->clrText = itemData->color; + + *result = CDRF_NOTIFYSUBITEMDRAW|CDRF_NOTIFYPOSTPAINT; + + if (itemData->hFont) + { + SelectObject(customdraw->nmcd.hdc, itemData->hFont); + *result |= CDRF_NEWFONT; + } + + return 1; + } + } + + return 0; /* allow the default processsing */ +} + +static int winTreeConvertXYToPos(Ihandle* ih, int x, int y) +{ + TVHITTESTINFO info; + HTREEITEM hItem; + info.pt.x = x; + info.pt.y = y; + hItem = (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)&info); + if (hItem) + return winTreeGetNodeId(ih, hItem); + return -1; +} + + +/*******************************************************************************************/ + +static void winTreeUnMapMethod(Ihandle* ih) +{ + Iarray* bmp_array; + HIMAGELIST image_list; + + HTREEITEM itemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0); + winTreeDelNodeData(ih, itemRoot); + + image_list = (HIMAGELIST)SendMessage(ih->handle, TVM_GETIMAGELIST, TVSIL_NORMAL, 0); + if (image_list) + ImageList_Destroy(image_list); + + bmp_array = (Iarray*)iupAttribGet(ih, "_IUPWIN_BMPARRAY"); + if (bmp_array) + iupArrayDestroy(bmp_array); + + iupdrvBaseUnMapMethod(ih); +} + +static int winTreeMapMethod(Ihandle* ih) +{ + DWORD dwStyle = WS_CHILD | WS_BORDER | TVS_SHOWSELALWAYS; + + /* can be set only on the Tree View creation */ + + if (!ih->data->show_dragdrop) + dwStyle |= TVS_DISABLEDRAGDROP; + + if (ih->data->show_rename) + dwStyle |= TVS_EDITLABELS; + + if (!iupAttribGetBoolean(ih, "HIDELINES")) + dwStyle |= TVS_HASLINES; + + if (!iupAttribGetBoolean(ih, "HIDEBUTTONS")) + dwStyle |= TVS_HASBUTTONS; + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + dwStyle |= WS_TABSTOP; + + if (!ih->parent) + return IUP_ERROR; + + if (!iupwinCreateWindowEx(ih, WC_TREEVIEW, 0, dwStyle)) + return IUP_ERROR; + + IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winTreeProc); + IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winTreeWmNotify); + + /* Force background update before setting the images */ + { + char* value = iupAttribGet(ih, "BGCOLOR"); + if (value) + { + winTreeSetBgColorAttrib(ih, value); + iupAttribSetStr(ih, "BGCOLOR", NULL); + } + else if (iupwinGetSystemMajorVersion()<6) /* force background in XP because of the editbox background */ + winTreeSetBgColorAttrib(ih, IupGetGlobal("TXTBGCOLOR")); + } + + /* Initialize the default images */ + ih->data->def_image_leaf = (void*)winTreeGetImageIndex(ih, "IMGLEAF"); + ih->data->def_image_collapsed = (void*)winTreeGetImageIndex(ih, "IMGCOLLAPSED"); + ih->data->def_image_expanded = (void*)winTreeGetImageIndex(ih, "IMGEXPANDED"); + + /* Add the Root Node */ + winTreeAddRootNode(ih); + + /* configure for DRAG&DROP of files */ + if (IupGetCallback(ih, "DROPFILES_CB")) + iupAttribSetStr(ih, "DRAGDROP", "YES"); + + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)winTreeConvertXYToPos); + + return IUP_NOERROR; +} + +void iupdrvTreeInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = winTreeMapMethod; + ic->UnMap = winTreeUnMapMethod; + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", winTreeGetBgColorAttrib, winTreeSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, winTreeSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT); + + /* IupTree Attributes - GENERAL */ + iupClassRegisterAttribute(ic, "EXPANDALL", NULL, winTreeSetExpandAllAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INDENTATION", winTreeGetIndentationAttrib, winTreeSetIndentationAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "COUNT", winTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPACING", iupTreeGetSpacingAttrib, winTreeSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "TOPITEM", NULL, winTreeSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + + /* IupTree Attributes - IMAGES */ + iupClassRegisterAttributeId(ic, "IMAGE", NULL, winTreeSetImageAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "IMAGEEXPANDED", NULL, winTreeSetImageExpandedAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "IMAGELEAF", NULL, winTreeSetImageLeafAttrib, IUPAF_SAMEASSYSTEM, "IMGLEAF", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGEBRANCHCOLLAPSED", NULL, winTreeSetImageBranchCollapsedAttrib, IUPAF_SAMEASSYSTEM, "IMGCOLLAPSED", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGEBRANCHEXPANDED", NULL, winTreeSetImageBranchExpandedAttrib, IUPAF_SAMEASSYSTEM, "IMGEXPANDED", IUPAF_NO_INHERIT); + + /* IupTree Attributes - NODES */ + iupClassRegisterAttributeId(ic, "STATE", winTreeGetStateAttrib, winTreeSetStateAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "DEPTH", winTreeGetDepthAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "KIND", winTreeGetKindAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "PARENT", winTreeGetParentAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "NAME", winTreeGetTitleAttrib, winTreeSetTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLE", winTreeGetTitleAttrib, winTreeSetTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "CHILDCOUNT", winTreeGetChildCountAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "USERDATA", winTreeGetUserDataAttrib, winTreeSetUserDataAttrib, IUPAF_NO_STRING|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "COLOR", winTreeGetColorAttrib, winTreeSetColorAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLEFONT", winTreeGetTitleFontAttrib, winTreeSetTitleFontAttrib, IUPAF_NO_INHERIT); + + /* IupTree Attributes - MARKS */ + iupClassRegisterAttributeId(ic, "MARKED", winTreeGetMarkedAttrib, winTreeSetMarkedAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARK", NULL, winTreeSetMarkAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "STARTING", NULL, winTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARKSTART", NULL, winTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute (ic, "VALUE", winTreeGetValueAttrib, winTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupTree Attributes - ACTION */ + iupClassRegisterAttributeId(ic, "DELNODE", NULL, winTreeSetDelNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "RENAME", NULL, winTreeSetRenameAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "MOVENODE", NULL, winTreeSetMoveNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "COPYNODE", NULL, winTreeSetCopyNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "FINDUSERDATA", winTreeGetFindUserDataAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); +} diff --git a/iup/src/win/iupwin_val.c b/iup/src/win/iupwin_val.c new file mode 100755 index 0000000..706c612 --- /dev/null +++ b/iup/src/win/iupwin_val.c @@ -0,0 +1,315 @@ +/** \file + * \brief Valuator Control + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> +#include <commctrl.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_val.h" +#include "iup_drv.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" +#include "iupwin_draw.h" + + +#ifndef SHRT_MAX +#define SHRT_MAX 32767 +#endif + +void iupdrvValGetMinSize(Ihandle* ih, int *w, int *h) +{ + int ticks_size = 0; + if (iupAttribGetInt(ih, "SHOWTICKS")) + { + char* tickspos = iupAttribGetStr(ih, "TICKSPOS"); + if(iupStrEqualNoCase(tickspos, "BOTH")) + ticks_size = 2*8; + else + ticks_size = 8; + } + + if (ih->data->type == IVAL_HORIZONTAL) + { + *w = 35; + *h = 30+ticks_size; + } + else + { + *w = 30+ticks_size; + *h = 35; + } +} + +static int winValSetStepAttrib(Ihandle* ih, const char* value) +{ + int linesize; + ih->data->step = atof(value); + linesize = (int)(ih->data->step*SHRT_MAX); + SendMessage(ih->handle, TBM_SETLINESIZE, 0, linesize); + return 0; /* do not store value in hash table */ +} + +static int winValSetPageStepAttrib(Ihandle* ih, const char* value) +{ + int pagesize; + ih->data->pagestep = atof(value); + pagesize = (int)(ih->data->pagestep*SHRT_MAX); + SendMessage(ih->handle, TBM_SETPAGESIZE, 0, pagesize); + return 0; /* do not store value in hash table */ +} + +static int winValSetShowTicksAttrib(Ihandle* ih, const char* value) +{ + int tick_freq, show_ticks; + + if (!ih->data->show_ticks) /* can only set if already not zero */ + return 0; + + show_ticks = atoi(value); + if (show_ticks<2) show_ticks=2; + ih->data->show_ticks = show_ticks; + + /* Defines the interval frequency for tick marks */ + tick_freq = SHRT_MAX/(show_ticks-1); + SendMessage(ih->handle, TBM_SETTICFREQ, tick_freq, 0); + return 0; +} + +static int winValSetValueAttrib(Ihandle* ih, const char* value) +{ + int ival; + + ih->data->val = atof(value); + iupValCropValue(ih); + + ival = (int)(((ih->data->val-ih->data->vmin)/(ih->data->vmax - ih->data->vmin))*SHRT_MAX); + if (ih->data->inverted) + ival = SHRT_MAX-ival; + + SendMessage(ih->handle, TBM_SETPOS, TRUE, ival); + return 0; /* do not store value in hash table */ +} + + +/*********************************************************************************************/ + + +static int winValCtlColor(Ihandle* ih, HDC hdc, LRESULT *result) +{ + COLORREF cr; + if (iupwinGetParentBgColor(ih, &cr)) + { + SetDCBrushColor(hdc, cr); + *result = (LRESULT)GetStockObject(DC_BRUSH); + return 1; + } + return 0; +} + +static int winValCustomScroll(Ihandle* ih, int msg) +{ + double old_val = ih->data->val; + int ival; + IFn cb; + + ival = (int)SendMessage(ih->handle, TBM_GETPOS, 0, 0); + if (ih->data->inverted) + ival = SHRT_MAX-ival; + + ih->data->val = (((double)ival/(double)SHRT_MAX)*(ih->data->vmax - ih->data->vmin)) + ih->data->vmin; + iupValCropValue(ih); + + cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB"); + if (cb) + { + if (ih->data->val == old_val) + return 0; + + cb(ih); + } + else + { + IFnd cb_old = NULL; + switch (msg) + { + case TB_BOTTOM: + case TB_TOP: + case TB_LINEDOWN: + case TB_LINEUP: + case TB_PAGEDOWN: + case TB_PAGEUP: + { + cb_old = (IFnd) IupGetCallback(ih, "BUTTON_PRESS_CB"); + break; + } + case TB_THUMBPOSITION: + { + cb_old = (IFnd) IupGetCallback(ih, "BUTTON_RELEASE_CB"); + break; + } + case TB_THUMBTRACK: + { + cb_old = (IFnd) IupGetCallback(ih, "MOUSEMOVE_CB"); + break; + } + } + if (cb_old) + cb_old(ih, ih->data->val); + } + + return 0; /* not used */ +} + +static void winValIncPageValue(Ihandle *ih, int dir) +{ + int pagesize, ival; + pagesize = (int)(ih->data->pagestep*SHRT_MAX); + + ival = (int)SendMessage(ih->handle, TBM_GETPOS, 0, 0); + ival += dir*pagesize; + if (ival < 0) ival = 0; + if (ival > SHRT_MAX) ival = SHRT_MAX; + SendMessage(ih->handle, TBM_SETPOS, TRUE, ival); + + winValCustomScroll(ih, 0); +} + +static int winValProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + (void)lp; + + switch (msg) + { + case WM_ERASEBKGND: + { + RECT rect; + HDC hDC = (HDC)wp; + GetClientRect(ih->handle, &rect); + iupwinDrawParentBackground(ih, hDC, &rect); + /* return non zero value */ + *result = 1; + return 1; + } + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + { + if (iupwinBaseProc(ih, msg, wp, lp, result)==1) + return 1; + + if (GetKeyState(VK_CONTROL) & 0x8000) /* handle Ctrl+Arrows */ + { + if (wp == VK_UP || wp == VK_LEFT) + { + winValIncPageValue(ih, -1); + *result = 0; + return 1; + } + if (wp == VK_RIGHT || wp == VK_DOWN) + { + winValIncPageValue(ih, 1); + *result = 0; + return 1; + } + } + return 0; + } + } + + return iupwinBaseProc(ih, msg, wp, lp, result); +} + + +/*********************************************************************************************/ + + +static int winValMapMethod(Ihandle* ih) +{ + DWORD dwStyle = WS_CHILD | TBS_AUTOTICKS; + int show_ticks; + + if (!ih->parent) + return IUP_ERROR; + + /* Track bar Orientation */ + if (ih->data->type == IVAL_HORIZONTAL) + dwStyle |= TBS_HORZ; + else + dwStyle |= TBS_VERT; + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + dwStyle |= WS_TABSTOP; + + /* Track bar Ticks */ + show_ticks = iupAttribGetInt(ih, "SHOWTICKS"); + if (!show_ticks) + { + dwStyle |= TBS_NOTICKS; /* No show_ticks */ + } + else + { + char* tickspos; + + if (show_ticks<2) show_ticks=2; + ih->data->show_ticks = show_ticks; /* non zero value, can be changed later, but not to zero */ + + /* Defines the position of tick marks */ + tickspos = iupAttribGetStr(ih, "TICKSPOS"); + if(iupStrEqualNoCase(tickspos, "BOTH")) + dwStyle |= TBS_BOTH; + else if(iupStrEqualNoCase(tickspos, "REVERSE")) + dwStyle |= TBS_BOTTOM; /* same as TBS_RIGHT */ + else /* NORMAL */ + dwStyle |= TBS_TOP; /* same as TBS_LEFT */ + } + + if (!iupwinCreateWindowEx(ih, TRACKBAR_CLASS, 0, dwStyle)) + return IUP_ERROR; + + /* Process Keyboard */ + IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winValProc); + + /* Process Val Scroll commands */ + IupSetCallback(ih, "_IUPWIN_CUSTOMSCROLL_CB", (Icallback)winValCustomScroll); + + /* Process background color */ + IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winValCtlColor); + + /* configure the native range */ + SendMessage(ih->handle, TBM_SETRANGEMIN, FALSE, 0); + SendMessage(ih->handle, TBM_SETRANGEMAX, FALSE, SHRT_MAX); + + if (ih->data->inverted) + SendMessage(ih->handle, TBM_SETPOS, FALSE, SHRT_MAX); /* default initial position is at MIN */ + + return IUP_NOERROR; +} + +void iupdrvValInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = winValMapMethod; + + /* IupVal only */ + iupClassRegisterAttribute(ic, "VALUE", iupValGetValueAttrib, winValSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWTICKS", iupValGetShowTicksAttrib, winValSetShowTicksAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "PAGESTEP", iupValGetPageStepAttrib, winValSetPageStepAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "STEP", iupValGetStepAttrib, winValSetStepAttrib, "0.01", NULL, IUPAF_NO_INHERIT); /* force new default value */ + + iupClassRegisterAttribute(ic, "TICKSPOS", NULL, NULL, "NORMAL", NULL, IUPAF_NOT_MAPPED); +} diff --git a/iup/src/win/iupwindows_help.c b/iup/src/win/iupwindows_help.c new file mode 100755 index 0000000..f3a06b6 --- /dev/null +++ b/iup/src/win/iupwindows_help.c @@ -0,0 +1,32 @@ +/** \file + * \brief Windows Driver IupHelp + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> + +#include <windows.h> +#include <shellapi.h> + +#include "iup.h" + +int IupHelp(const char* url) +{ + int err = (int)ShellExecute(GetDesktopWindow(), "open", url, NULL, NULL, SW_SHOWNORMAL); + if (err <= 32) + { + switch (err) + { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + return -2; /* File not found */ + break; + default: + return -1; /* Generic error */ + break; + } + } + return 1; +} diff --git a/iup/src/win/iupwindows_info.c b/iup/src/win/iupwindows_info.c new file mode 100755 index 0000000..982c980 --- /dev/null +++ b/iup/src/win/iupwindows_info.c @@ -0,0 +1,212 @@ +/** \file + * \brief Windows System Information + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +/* This module should depend only on IUP core headers + and Windows system headers. */ + +#include <windows.h> + +#include "iup_str.h" +#include "iup_drvinfo.h" + + +int iupdrvMakeDirectory(const char* name) +{ + if (CreateDirectory(name, NULL)) + return 1; + else + return 0; +} + +int iupdrvIsFile(const char* name) +{ + DWORD attrib = GetFileAttributes(name); + if (attrib == INVALID_FILE_ATTRIBUTES) + return 0; + if (attrib & FILE_ATTRIBUTE_DIRECTORY) + return 0; + return 1; +} + +int iupdrvIsDirectory(const char* name) +{ + DWORD attrib = GetFileAttributes(name); + if (attrib == INVALID_FILE_ATTRIBUTES) + return 0; + if (attrib & FILE_ATTRIBUTE_DIRECTORY) + return 1; + return 0; +} + +char* iupdrvGetCurrentDirectory(void) +{ + char* cur_dir; + int len = GetCurrentDirectory(0, NULL); + if (len == 0) return NULL; + + cur_dir = malloc(len+2); + GetCurrentDirectory(len+1, cur_dir); + cur_dir[len] = '\\'; + cur_dir[len+1] = 0; + return cur_dir; +} + +int iupdrvSetCurrentDirectory(const char* dir) +{ + return SetCurrentDirectory(dir); +} + +int iupdrvGetWindowDecor(void* wnd, int *border, int *caption) +{ + WINDOWINFO wi; + wi.cbSize = sizeof(WINDOWINFO); + GetWindowInfo((HWND)wnd, &wi); + + *border = wi.cxWindowBorders; + + if (wi.rcClient.bottom == wi.rcClient.top) + *caption = wi.rcClient.bottom - wi.cyWindowBorders; + else + { + /* caption = window height - top border - client height */ + *caption = (wi.rcWindow.bottom-wi.rcWindow.top) - 2*wi.cyWindowBorders - (wi.rcClient.bottom-wi.rcClient.top); + } + + return 1; +} + +void iupdrvGetScreenSize(int *width, int *height) +{ + RECT area; + SystemParametersInfo(SPI_GETWORKAREA, 0, &area, 0); + *width = (int)(area.right - area.left); + *height = (int)(area.bottom - area.top); +} + +void iupdrvGetFullSize(int *width, int *height) +{ + RECT rect; + GetWindowRect(GetDesktopWindow(), &rect); + *width = rect.right - rect.left; + *height = rect.bottom - rect.top; +} + +int iupdrvGetScreenDepth(void) +{ + int bpp; + HDC hDCDisplay = GetDC(NULL); + bpp = GetDeviceCaps(hDCDisplay, BITSPIXEL); + ReleaseDC(NULL, hDCDisplay); + return bpp; +} + +void iupdrvGetCursorPos(int *x, int *y) +{ + POINT CursorPoint; + GetCursorPos(&CursorPoint); + *x = (int)CursorPoint.x; + *y = (int)CursorPoint.y; +} + +void iupdrvGetKeyState(char* key) +{ + if (GetAsyncKeyState(VK_SHIFT) & 0x8000) + key[0] = 'S'; + else + key[0] = ' '; + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + key[1] = 'C'; + else + key[1] = ' '; + if (GetAsyncKeyState(VK_MENU) & 0x8000) + key[2] = 'A'; + else + key[2] = ' '; + if ((GetAsyncKeyState(VK_LWIN) & 0x8000) || (GetAsyncKeyState(VK_RWIN) & 0x8000)) + key[3] = 'Y'; + else + key[3] = ' '; + + key[4] = 0; +} + +char *iupdrvGetSystemName(void) +{ + OSVERSIONINFO osvi; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + + if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + if (osvi.dwMajorVersion <= 4) + return "WinNT"; + + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) + return "Win2K"; + + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion > 0) + return "WinXP"; + + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) + return "Vista"; + + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion > 0) + return "Win7"; + } + + return "Windows"; +} + +char *iupdrvGetSystemVersion(void) +{ + char *str = iupStrGetMemory(256); + OSVERSIONINFOEX osvi; + SYSTEM_INFO si; + + ZeroMemory(&si, sizeof(SYSTEM_INFO)); + GetSystemInfo(&si); + + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + GetVersionEx((OSVERSIONINFO*)&osvi); + + sprintf(str, "%d.%d.%d", (int)osvi.dwMajorVersion, (int)osvi.dwMinorVersion, (int)osvi.dwBuildNumber); + + /* Display service pack (if any). */ + if (osvi.szCSDVersion && osvi.szCSDVersion[0]!=0) + { + strcat(str, " "); + strcat(str, osvi.szCSDVersion); + } + + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) + strcat(str, " (IA64)"); + else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + strcat(str, " (x64)"); + else + strcat(str, " (x86)"); + + return str; +} + +char *iupdrvGetComputerName(void) +{ + DWORD size = MAX_COMPUTERNAME_LENGTH + 1; + char* str = iupStrGetMemory(size); + GetComputerName((LPTSTR)str, &size); + return str; +} + +char *iupdrvGetUserName(void) +{ + DWORD size = 256; + char* str = iupStrGetMemory(size); + GetUserName((LPTSTR)str, &size); + return (char*)str; +} diff --git a/iup/src/win/iupwindows_main.c b/iup/src/win/iupwindows_main.c new file mode 100755 index 0000000..ea7e2ae --- /dev/null +++ b/iup/src/win/iupwindows_main.c @@ -0,0 +1,66 @@ +/** \file + * \brief Windows Driver WinMain + * + * See Copyright Notice in "iup.h" + */ + +#include <windows.h> + +#include <stdlib.h> /* declaration of __argc and __argv */ + +#include "iup.h" + + +#ifdef __WATCOMC__ /* force Watcom to link this module, called from IupOpen */ +void iupwinMainDummy(void) +{ + return; +} +#else +extern int main(int, char **); +#endif + +/* save this handle in DllMain only, use to load resources from the DLL. */ +HINSTANCE iupwin_dll_hinstance = 0; + +#ifdef IUP_DLL +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + (void)fdwReason; + (void)lpvReserved; + + iupwin_dll_hinstance = hinstDLL; + + return TRUE; +} +#else +/* this module is always linked in the makefile, + But it must not define WinMain if building the DLL */ +int PASCAL WinMain (HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int ncmdshow) +{ + (void)hinst; /* NOT used */ + (void)hprev; + (void)cmdline; + (void)ncmdshow; + + /* WinMain is NOT called for Console applications */ + +#ifdef __WATCOMC__ + { + extern int _argc; + extern char** _argv; + return IupMain(_argc, _argv); + } +#else + { + /* this seems to work for all the compilers we tested, except Watcom compilers */ + /* These are declared in <stdlib.h>, except for Cygwin. */ +#ifdef __GNUC__ + extern int __argc; + extern char** __argv; +#endif + return main(__argc, __argv); + } +#endif +} +#endif |