summaryrefslogtreecommitdiff
path: root/iup/src/win
diff options
context:
space:
mode:
authorPixel <pixel@nobis-crew.org>2009-11-04 11:56:41 -0800
committerPixel <pixel@nobis-crew.org>2009-11-04 11:59:33 -0800
commitd577d991b97ae2b5ee1af23641bcffc3f83af5b2 (patch)
tree590639d50205d1bcfaff2a7d2dc6ebf3f373c7ed /iup/src/win
Initial import. Contains the im, cd and iup librairies, and a "working" Makefile for them under linux.
Diffstat (limited to 'iup/src/win')
-rwxr-xr-xiup/src/win/iupwin_brush.c62
-rwxr-xr-xiup/src/win/iupwin_brush.h26
-rwxr-xr-xiup/src/win/iupwin_button.c715
-rwxr-xr-xiup/src/win/iupwin_canvas.c724
-rwxr-xr-xiup/src/win/iupwin_clipboard.c190
-rwxr-xr-xiup/src/win/iupwin_colordlg.c133
-rwxr-xr-xiup/src/win/iupwin_common.c865
-rwxr-xr-xiup/src/win/iupwin_dialog.c1439
-rwxr-xr-xiup/src/win/iupwin_draw.c328
-rwxr-xr-xiup/src/win/iupwin_draw.h47
-rwxr-xr-xiup/src/win/iupwin_drv.h113
-rwxr-xr-xiup/src/win/iupwin_filedlg.c580
-rwxr-xr-xiup/src/win/iupwin_focus.c62
-rwxr-xr-xiup/src/win/iupwin_font.c342
-rwxr-xr-xiup/src/win/iupwin_fontdlg.c160
-rwxr-xr-xiup/src/win/iupwin_frame.c203
-rwxr-xr-xiup/src/win/iupwin_globalattrib.c243
-rwxr-xr-xiup/src/win/iupwin_handle.c56
-rwxr-xr-xiup/src/win/iupwin_handle.h28
-rwxr-xr-xiup/src/win/iupwin_image.c668
-rwxr-xr-xiup/src/win/iupwin_info.c277
-rwxr-xr-xiup/src/win/iupwin_info.h29
-rwxr-xr-xiup/src/win/iupwin_key.c348
-rwxr-xr-xiup/src/win/iupwin_label.c339
-rwxr-xr-xiup/src/win/iupwin_list.c1460
-rwxr-xr-xiup/src/win/iupwin_loop.c135
-rwxr-xr-xiup/src/win/iupwin_menu.c667
-rwxr-xr-xiup/src/win/iupwin_messagedlg.c105
-rwxr-xr-xiup/src/win/iupwin_open.c124
-rwxr-xr-xiup/src/win/iupwin_progressbar.c164
-rwxr-xr-xiup/src/win/iupwin_tabs.c680
-rwxr-xr-xiup/src/win/iupwin_text.c1993
-rwxr-xr-xiup/src/win/iupwin_timer.c88
-rwxr-xr-xiup/src/win/iupwin_tips.c191
-rwxr-xr-xiup/src/win/iupwin_toggle.c693
-rwxr-xr-xiup/src/win/iupwin_tree.c2542
-rwxr-xr-xiup/src/win/iupwin_val.c315
-rwxr-xr-xiup/src/win/iupwindows_help.c32
-rwxr-xr-xiup/src/win/iupwindows_info.c212
-rwxr-xr-xiup/src/win/iupwindows_main.c66
40 files changed, 17444 insertions, 0 deletions
diff --git a/iup/src/win/iupwin_brush.c b/iup/src/win/iupwin_brush.c
new file mode 100755
index 0000000..228e6d4
--- /dev/null
+++ b/iup/src/win/iupwin_brush.c
@@ -0,0 +1,62 @@
+/** \file
+ * \brief Windows Brush Cache
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <windows.h>
+
+#include "iup.h"
+#include "iup_array.h"
+
+#include "iupwin_brush.h"
+
+
+typedef struct _IwinBrush
+{
+ HBRUSH hbrush;
+ COLORREF color;
+} IwinBrush;
+
+static Iarray* win_brushes = NULL;
+
+HBRUSH iupwinBrushGet(COLORREF color)
+{
+ int i, count = iupArrayCount(win_brushes);
+
+ /* If a brush with the desired color already exists... */
+ IwinBrush* brushes = (IwinBrush*)iupArrayGetData(win_brushes);
+ for (i = 0; i < count; i++)
+ {
+ if (brushes[i].color == color)
+ return brushes[i].hbrush;
+ }
+
+ /* If it doesn't exist, it should be created... */
+ brushes = (IwinBrush*)iupArrayInc(win_brushes);
+
+ brushes[i].color = color;
+ brushes[i].hbrush = CreateSolidBrush(color);
+
+ return brushes[i].hbrush;
+}
+
+void iupwinBrushInit(void)
+{
+ win_brushes = iupArrayCreate(50, sizeof(IwinBrush));
+}
+
+void iupwinBrushFinish(void)
+{
+ int i, count = iupArrayCount(win_brushes);
+ IwinBrush* brushes = (IwinBrush*)iupArrayGetData(win_brushes);
+ for (i = 0; i < count; i++)
+ {
+ DeleteObject(brushes[i].hbrush);
+ brushes[i].hbrush = NULL;
+ }
+ iupArrayDestroy(win_brushes);
+}
diff --git a/iup/src/win/iupwin_brush.h b/iup/src/win/iupwin_brush.h
new file mode 100755
index 0000000..463f323
--- /dev/null
+++ b/iup/src/win/iupwin_brush.h
@@ -0,0 +1,26 @@
+/** \file
+ * \brief Windows Brush Cache
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUPWIN_BRUSH_H
+#define __IUPWIN_BRUSH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* returns a brush from the brush cache. */
+HBRUSH iupwinBrushGet(COLORREF c);
+
+/* initializes the brush cache */
+void iupwinBrushInit(void);
+void iupwinBrushFinish(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/win/iupwin_button.c b/iup/src/win/iupwin_button.c
new file mode 100755
index 0000000..7f780e3
--- /dev/null
+++ b/iup/src/win/iupwin_button.c
@@ -0,0 +1,715 @@
+/** \file
+ * \brief Button Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_button.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_image.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_draw.h"
+
+
+#ifndef CDIS_SHOWKEYBOARDCUES
+#define CDIS_SHOWKEYBOARDCUES 0x0200 /* it is defined only when _WIN32_WINNT >= 0x0501 */
+#endif
+
+
+static int winButtonGetBorder(void)
+{
+ return 4;
+}
+
+void iupdrvButtonAddBorders(int *x, int *y)
+{
+ int border_size = winButtonGetBorder()*2;
+ (*x) += border_size;
+ (*y) += border_size;
+}
+
+/****************************************************************/
+
+static int winButtonCalcAlignPosX(int horiz_alignment, int rect_width, int width, int xpad, int shift)
+{
+ int x;
+
+ if (horiz_alignment == IUP_ALIGN_ARIGHT)
+ x = rect_width - (width + 2*xpad);
+ else if (horiz_alignment == IUP_ALIGN_ACENTER)
+ x = (rect_width - (width + 2*xpad))/2;
+ else /* ALEFT */
+ x = 0;
+
+ x += xpad;
+
+ if (shift)
+ x++;
+
+ return x;
+}
+
+static int winButtonCalcAlignPosY(int vert_alignment, int rect_height, int height, int ypad, int shift)
+{
+ int y;
+
+ if (vert_alignment == IUP_ALIGN_ABOTTOM)
+ y = rect_height - (height + 2*ypad);
+ else if (vert_alignment == IUP_ALIGN_ATOP)
+ y = 0;
+ else /* ACENTER */
+ y = (rect_height - (height + 2*ypad))/2;
+
+ y += ypad;
+
+ if (shift)
+ y++;
+
+ return y;
+}
+
+static HBITMAP winButtonGetBitmap(Ihandle* ih, UINT itemState, int *shift, int *w, int *h, int *bpp, HBITMAP *hMask)
+{
+ char *name;
+ int make_inactive = 0;
+ HBITMAP hBitmap;
+ *hMask = NULL;
+
+ if (itemState & ODS_DISABLED)
+ {
+ name = iupAttribGet(ih, "IMINACTIVE");
+ if (!name)
+ {
+ name = iupAttribGet(ih, "IMAGE");
+ make_inactive = 1;
+ }
+ }
+ else
+ {
+ name = iupAttribGet(ih, "IMPRESS");
+ if (itemState & ODS_SELECTED && name)
+ {
+ if (shift && !iupAttribGetStr(ih, "IMPRESSBORDER"))
+ *shift = 0;
+ }
+ else
+ name = iupAttribGet(ih, "IMAGE");
+ }
+
+ hBitmap = iupImageGetImage(name, ih, make_inactive);
+
+ /* must use this info, since image can be a driver image loaded from resources */
+ iupdrvImageGetInfo(hBitmap, w, h, bpp);
+
+ if (*bpp == 8)
+ *hMask = iupdrvImageCreateMask(IupGetHandle(name));
+
+ return hBitmap;
+}
+
+static void winButtonDrawImageText(Ihandle* ih, HDC hDC, int rect_width, int rect_height, int border, UINT itemState)
+{
+ int xpad = ih->data->horiz_padding + border,
+ ypad = ih->data->vert_padding + border;
+ int x, y, width, height,
+ txt_x, txt_y, txt_width, txt_height,
+ img_x, img_y, img_width, img_height,
+ bpp, shift = 0;
+ HFONT hFont = (HFONT)iupwinGetHFontAttrib(ih);
+ HBITMAP hBitmap, hMask;
+ COLORREF fgcolor;
+
+ char* title = iupdrvBaseGetTitleAttrib(ih);
+ char* str = iupStrProcessMnemonic(title, NULL, 0); /* remove & */
+ iupdrvFontGetMultiLineStringSize(ih, str, &txt_width, &txt_height);
+ if (str && str!=title) free(str);
+
+ if (itemState & ODS_DISABLED)
+ fgcolor = GetSysColor(COLOR_GRAYTEXT);
+ else
+ fgcolor = ih->data->fgcolor;
+
+ hBitmap = winButtonGetBitmap(ih, itemState, NULL, &img_width, &img_height, &bpp, &hMask);
+ if (!hBitmap)
+ return;
+
+ if (ih->data->img_position == IUP_IMGPOS_RIGHT ||
+ ih->data->img_position == IUP_IMGPOS_LEFT)
+ {
+ width = img_width + txt_width + ih->data->spacing;
+ height = iupMAX(img_height, txt_height);
+ }
+ else
+ {
+ width = iupMAX(img_width, txt_width);
+ height = img_height + txt_height + ih->data->spacing;
+ }
+
+ if (itemState & ODS_SELECTED && !iupwin_comctl32ver6)
+ shift = 1;
+
+ x = winButtonCalcAlignPosX(ih->data->horiz_alignment, rect_width, width, xpad, shift);
+ y = winButtonCalcAlignPosY(ih->data->vert_alignment, rect_height, height, ypad, shift);
+
+ switch(ih->data->img_position)
+ {
+ case IUP_IMGPOS_TOP:
+ img_y = y;
+ txt_y = y + img_height + ih->data->spacing;
+ if (img_width > txt_width)
+ {
+ img_x = x;
+ txt_x = x + (img_width-txt_width)/2;
+ }
+ else
+ {
+ img_x = x + (txt_width-img_width)/2;
+ txt_x = x;
+ }
+ break;
+ case IUP_IMGPOS_BOTTOM:
+ img_y = y + txt_height + ih->data->spacing;
+ txt_y = y;
+ if (img_width > txt_width)
+ {
+ img_x = x;
+ txt_x = x + (img_width-txt_width)/2;
+ }
+ else
+ {
+ img_x = x + (txt_width-img_width)/2;
+ txt_x = x;
+ }
+ break;
+ case IUP_IMGPOS_RIGHT:
+ img_x = x + txt_width + ih->data->spacing;
+ txt_x = x;
+ if (img_height > txt_height)
+ {
+ img_y = y;
+ txt_y = y + (img_height-txt_height)/2;
+ }
+ else
+ {
+ img_y = y + (txt_height-img_height)/2;
+ txt_y = y;
+ }
+ break;
+ default: /* IUP_IMGPOS_LEFT */
+ img_x = x;
+ txt_x = x + img_width + ih->data->spacing;
+ if (img_height > txt_height)
+ {
+ img_y = y;
+ txt_y = y + (img_height-txt_height)/2;
+ }
+ else
+ {
+ img_y = y + (txt_height-img_height)/2;
+ txt_y = y;
+ }
+ break;
+ }
+
+ iupwinDrawBitmap(hDC, hBitmap, hMask, img_x, img_y, img_width, img_height, bpp);
+ iupwinDrawText(hDC, title, txt_x, txt_y, txt_width, txt_height, hFont, fgcolor, 0);
+
+ if (hMask)
+ DeleteObject(hMask);
+}
+
+static void winButtonDrawImage(Ihandle* ih, HDC hDC, int rect_width, int rect_height, int border, UINT itemState)
+{
+ int xpad = ih->data->horiz_padding + border,
+ ypad = ih->data->vert_padding + border;
+ int x, y, width, height, bpp, shift = 0;
+ HBITMAP hBitmap, hMask;
+
+ if (itemState & ODS_SELECTED && !iupwin_comctl32ver6)
+ shift = 1;
+
+ hBitmap = winButtonGetBitmap(ih, itemState, &shift, &width, &height, &bpp, &hMask);
+ if (!hBitmap)
+ return;
+
+ x = winButtonCalcAlignPosX(ih->data->horiz_alignment, rect_width, width, xpad, shift);
+ y = winButtonCalcAlignPosY(ih->data->vert_alignment, rect_height, height, ypad, shift);
+
+ iupwinDrawBitmap(hDC, hBitmap, hMask, x, y, width, height, bpp);
+
+ if (hMask)
+ DeleteObject(hMask);
+}
+
+static void winButtonDrawText(Ihandle* ih, HDC hDC, int rect_width, int rect_height, int border, UINT itemState)
+{
+ int xpad = ih->data->horiz_padding + border,
+ ypad = ih->data->vert_padding + border;
+ int x, y, width, height, shift = 0;
+ COLORREF fgcolor;
+
+ char* title = iupdrvBaseGetTitleAttrib(ih);
+ if (title)
+ {
+ HFONT hFont = (HFONT)iupwinGetHFontAttrib(ih);
+ char* str = iupStrProcessMnemonic(title, NULL, 0); /* remove & */
+ iupdrvFontGetMultiLineStringSize(ih, str, &width, &height);
+ if (str && str!=title) free(str);
+
+ if (itemState & ODS_DISABLED)
+ fgcolor = GetSysColor(COLOR_GRAYTEXT);
+ else
+ fgcolor = ih->data->fgcolor;
+
+ if (itemState & ODS_SELECTED && !iupwin_comctl32ver6)
+ shift = 1;
+
+ x = winButtonCalcAlignPosX(ih->data->horiz_alignment, rect_width, width, xpad, shift);
+ y = winButtonCalcAlignPosY(ih->data->vert_alignment, rect_height, height, ypad, shift);
+
+ iupwinDrawText(hDC, title, x, y, width, height, hFont, fgcolor, 0);
+ }
+ else
+ {
+ /* fill with the background color if defined at the element */
+ char* bgcolor = iupAttribGet(ih, "BGCOLOR");
+ if (bgcolor)
+ {
+ RECT rect;
+ unsigned char r=0, g=0, b=0;
+ iupStrToRGB(bgcolor, &r, &g, &b);
+ SetDCBrushColor(hDC, RGB(r,g,b));
+ rect.left = xpad;
+ rect.top = ypad;
+ rect.right = rect_width - xpad;
+ rect.bottom = rect_height - ypad;
+ FillRect(hDC, &rect, (HBRUSH)GetStockObject(DC_BRUSH));
+ }
+ }
+}
+
+static void winButtonDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem)
+{
+ iupwinBitmapDC bmpDC;
+ int border, draw_border;
+ int width = drawitem->rcItem.right - drawitem->rcItem.left;
+ int height = drawitem->rcItem.bottom - drawitem->rcItem.top;
+
+ HDC hDC = iupwinDrawCreateBitmapDC(&bmpDC, drawitem->hDC, width, height);
+
+ iupwinDrawParentBackground(ih, hDC, &drawitem->rcItem);
+
+ if ((drawitem->itemState & ODS_FOCUS) && !(drawitem->itemState & ODS_HOTLIGHT))
+ drawitem->itemState |= ODS_DEFAULT;
+
+ border = winButtonGetBorder();
+
+ if (ih->data->type & IUP_BUTTON_IMAGE && iupAttribGet(ih, "IMPRESS") && !iupAttribGetStr(ih, "IMPRESSBORDER"))
+ draw_border = 0;
+ else
+ {
+ if (iupAttribGetBoolean(ih, "FLAT"))
+ {
+ if (drawitem->itemState & ODS_HOTLIGHT || iupAttribGet(ih, "_IUPWINBUT_ENTERWIN"))
+ draw_border = 1;
+ else
+ draw_border = 0;
+ }
+ else
+ draw_border = 1;
+ }
+
+ if (draw_border)
+ iupwinDrawButtonBorder(ih->handle, hDC, &drawitem->rcItem, drawitem->itemState);
+
+ if (ih->data->type == IUP_BUTTON_IMAGE)
+ winButtonDrawImage(ih, hDC, width, height, border, drawitem->itemState);
+ else if (ih->data->type == IUP_BUTTON_TEXT)
+ winButtonDrawText(ih, hDC, width, height, border, drawitem->itemState);
+ else /* both */
+ winButtonDrawImageText(ih, hDC, width, height, border, drawitem->itemState);
+
+ if (drawitem->itemState & ODS_FOCUS)
+ {
+ border--;
+ iupdrvDrawFocusRect(ih, hDC, border, border, width-2*border, height-2*border);
+ }
+
+ iupwinDrawDestroyBitmapDC(&bmpDC);
+}
+
+
+/***********************************************************************************************/
+
+
+static int winButtonSetImageAttrib(Ihandle* ih, const char* value)
+{
+ (void)value;
+ if (ih->data->type != IUP_BUTTON_TEXT)
+ {
+ iupdrvDisplayUpdate(ih);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int winButtonSetImInactiveAttrib(Ihandle* ih, const char* value)
+{
+ (void)value;
+ if (ih->data->type != IUP_BUTTON_TEXT)
+ {
+ iupdrvDisplayUpdate(ih);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int winButtonSetImPressAttrib(Ihandle* ih, const char* value)
+{
+ (void)value;
+ if (ih->data->type != IUP_BUTTON_TEXT)
+ {
+ iupdrvDisplayUpdate(ih);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int winButtonSetActiveAttrib(Ihandle* ih, const char* value)
+{
+ /* redraw IMINACTIVE image if any */
+ if (ih->data->type != IUP_BUTTON_TEXT)
+ iupdrvDisplayUpdate(ih);
+
+ return iupBaseSetActiveAttrib(ih, value);
+}
+
+static int winButtonSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ char value1[30]="", value2[30]="";
+
+ iupStrToStrStr(value, value1, value2, ':');
+
+ if (iupStrEqualNoCase(value1, "ARIGHT"))
+ ih->data->horiz_alignment = IUP_ALIGN_ARIGHT;
+ else if (iupStrEqualNoCase(value1, "ALEFT"))
+ ih->data->horiz_alignment = IUP_ALIGN_ALEFT;
+ else /* "ACENTER" */
+ ih->data->horiz_alignment = IUP_ALIGN_ACENTER;
+
+ if (iupStrEqualNoCase(value2, "ABOTTOM"))
+ ih->data->vert_alignment = IUP_ALIGN_ABOTTOM;
+ else if (iupStrEqualNoCase(value2, "ATOP"))
+ ih->data->vert_alignment = IUP_ALIGN_ATOP;
+ else /* "ACENTER" */
+ ih->data->vert_alignment = IUP_ALIGN_ACENTER;
+
+ iupdrvDisplayRedraw(ih);
+
+ return 1;
+}
+
+static char* winButtonGetAlignmentAttrib(Ihandle *ih)
+{
+ char* horiz_align2str[3] = {"ALEFT", "ACENTER", "ARIGHT"};
+ char* vert_align2str[3] = {"ATOP", "ACENTER", "ABOTTOM"};
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%s:%s", horiz_align2str[ih->data->horiz_alignment], vert_align2str[ih->data->vert_alignment]);
+ return str;
+}
+
+static int winButtonSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+ if (ih->handle)
+ iupdrvDisplayRedraw(ih);
+ return 0;
+}
+
+static int winButtonSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ /* update internal image cache for controls that have the IMAGE attribute */
+ if (ih->data->type != IUP_BUTTON_TEXT)
+ {
+ iupAttribSetStr(ih, "BGCOLOR", value);
+ iupImageUpdateParent(ih);
+ iupdrvDisplayRedraw(ih);
+ }
+ return 1;
+}
+
+static char* winButtonGetBgColorAttrib(Ihandle* ih)
+{
+ /* the most important use of this is to provide
+ the correct background for images */
+ if (iupwin_comctl32ver6 && !iupAttribGet(ih, "IMPRESS"))
+ {
+ COLORREF cr;
+ if (iupwinDrawGetThemeButtonBgColor(ih->handle, &cr))
+ {
+ char* str = iupStrGetMemory(20);
+ sprintf(str, "%d %d %d", (int)GetRValue(cr), (int)GetGValue(cr), (int)GetBValue(cr));
+ return str;
+ }
+ }
+
+ if (iupAttribGet(ih, "IMPRESS"))
+ return iupBaseNativeParentGetBgColorAttrib(ih);
+ else
+ return NULL;
+}
+
+static int winButtonSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ ih->data->fgcolor = RGB(r,g,b);
+ iupdrvDisplayRedraw(ih);
+ }
+ return 1;
+}
+
+/****************************************************************************************/
+
+static int winButtonProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ if (ih->data->type != IUP_BUTTON_TEXT)
+ {
+ /* redraw IMPRESS image if any */
+ if ((msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) && iupAttribGet(ih, "IMPRESS"))
+ iupdrvDisplayRedraw(ih);
+ }
+
+ switch (msg)
+ {
+ case WM_XBUTTONDBLCLK:
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_XBUTTONDOWN:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ {
+ iupwinButtonDown(ih, msg, wp, lp);
+ break;
+ }
+ case WM_XBUTTONUP:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ {
+ iupwinButtonUp(ih, msg, wp, lp);
+
+ /* BN_CLICKED will NOT be notified when not receiving the focus */
+ if (msg==WM_LBUTTONUP && !iupAttribGetBoolean(ih, "FOCUSONCLICK"))
+ {
+ Icallback cb = IupGetCallback(ih, "ACTION");
+ if (cb && cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ break;
+ }
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ if (wp==VK_RETURN)
+ {
+ /* enter activates the button */
+ iupdrvActivate(ih);
+
+ *result = 0;
+ return 1; /* abort default processing, or the default button will be activated,
+ in this case even if there is a default button, this button must be activated instead. */
+ }
+ break;
+ case WM_MOUSELEAVE:
+ if (!iupwin_comctl32ver6)
+ {
+ iupAttribSetStr(ih, "_IUPWINBUT_ENTERWIN", NULL);
+ iupdrvDisplayRedraw(ih);
+ }
+ break;
+ case WM_MOUSEMOVE:
+ if (!iupwin_comctl32ver6)
+ {
+ if (!iupAttribGet(ih, "_IUPWINBUT_ENTERWIN"))
+ {
+ iupAttribSetStr(ih, "_IUPWINBUT_ENTERWIN", "1");
+ iupdrvDisplayRedraw(ih);
+ }
+ }
+ break;
+ case WM_SETFOCUS:
+ {
+ HWND previous = (HWND)wp;
+ if (!iupAttribGetBoolean(ih, "FOCUSONCLICK") && wp && iupAttribGet(ih, "_IUPWIN_ENTERWIN"))
+ {
+ SetFocus(previous);
+ *result = 0;
+ return 1;
+ }
+ }
+ break;
+ }
+
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+static int winButtonWmNotify(Ihandle* ih, NMHDR* msg_info, int *result)
+{
+ if (msg_info->code == NM_CUSTOMDRAW)
+ {
+ NMCUSTOMDRAW *customdraw = (NMCUSTOMDRAW*)msg_info;
+
+ if (customdraw->dwDrawStage==CDDS_PREERASE)
+ {
+ DRAWITEMSTRUCT drawitem;
+ drawitem.itemState = 0;
+
+ if (customdraw->uItemState & CDIS_DISABLED)
+ drawitem.itemState |= ODS_DISABLED;
+ else if (customdraw->uItemState & CDIS_SELECTED)
+ drawitem.itemState |= ODS_SELECTED;
+ else if (customdraw->uItemState & CDIS_HOT)
+ drawitem.itemState |= ODS_HOTLIGHT;
+ else if (customdraw->uItemState & CDIS_DEFAULT)
+ drawitem.itemState |= ODS_DEFAULT;
+
+ if (customdraw->uItemState & CDIS_FOCUS && (customdraw->uItemState & CDIS_SHOWKEYBOARDCUES))
+ drawitem.itemState |= ODS_FOCUS;
+
+ drawitem.hDC = customdraw->hdc;
+ drawitem.rcItem = customdraw->rc;
+
+ winButtonDrawItem(ih, (void*)&drawitem); /* Simulate a WM_DRAWITEM */
+
+ *result = CDRF_SKIPDEFAULT;
+ return 1;
+ }
+ }
+
+ return 0; /* result not used */
+}
+
+static int winButtonWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp)
+{
+ int cmd = HIWORD(wp);
+ switch (cmd)
+ {
+ case BN_DOUBLECLICKED:
+ case BN_CLICKED:
+ {
+ Icallback cb = IupGetCallback(ih, "ACTION");
+ if (cb && cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+ }
+ }
+
+ (void)lp;
+ return 0; /* not used */
+}
+
+static int winButtonMapMethod(Ihandle* ih)
+{
+ char* value;
+ DWORD dwStyle = WS_CHILD |
+ BS_NOTIFY; /* necessary because of the base messages */
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ /* Buttons with the BS_PUSHBUTTON style do NOT use the returned brush in WM_CTLCOLORBTN.
+ Buttons with these styles are always drawn with the default system colors.
+ So FGCOLOR and BGCOLOR do NOT work.
+ The BS_FLAT style does NOT completely remove the borders. With XP styles is ignored. So FLAT do NOT work.
+ BCM_SETTEXTMARGIN is not working.
+ Buttons with images and with XP styles do NOT draw the focus feedback.
+ Can NOT remove the borders when using IMPRESS.
+ So IUP will draw its own button,
+ but uses the Windows functions to draw text and images in native format. */
+ if (iupwin_comctl32ver6)
+ dwStyle |= BS_PUSHBUTTON; /* it will be an ownerdraw because we use NM_CUSTOMDRAW */
+ else
+ dwStyle |= BS_OWNERDRAW;
+
+ value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ {
+ ih->data->type = IUP_BUTTON_IMAGE;
+
+ value = iupAttribGet(ih, "TITLE");
+ if (value)
+ ih->data->type |= IUP_BUTTON_TEXT;
+ }
+ else
+ ih->data->type = IUP_BUTTON_TEXT;
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ dwStyle |= WS_TABSTOP;
+
+ if (!iupwinCreateWindowEx(ih, "BUTTON", 0, dwStyle))
+ return IUP_ERROR;
+
+ /* Process WM_COMMAND */
+ IupSetCallback(ih, "_IUPWIN_COMMAND_CB", (Icallback)winButtonWmCommand);
+
+ /* Process BUTTON_CB */
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winButtonProc);
+
+ if (iupwin_comctl32ver6)
+ IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winButtonWmNotify); /* Process WM_NOTIFY */
+ else
+ IupSetCallback(ih, "_IUPWIN_DRAWITEM_CB", (Icallback)winButtonDrawItem); /* Process WM_DRAWITEM */
+
+ return IUP_NOERROR;
+}
+
+void iupdrvButtonInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winButtonMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, winButtonSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", winButtonGetBgColorAttrib, winButtonSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, winButtonSetFgColorAttrib, "DLGFGCOLOR", NULL, IUPAF_NOT_MAPPED); /* force the new default value */
+ iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, iupdrvBaseSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupButton only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", winButtonGetAlignmentAttrib, winButtonSetAlignmentAttrib, "ACENTER:ACENTER", NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, winButtonSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, winButtonSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMPRESS", NULL, winButtonSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FOCUSONCLICK", NULL, NULL, "YES", NULL, IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "PADDING", iupButtonGetPaddingAttrib, winButtonSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+}
diff --git a/iup/src/win/iupwin_canvas.c b/iup/src/win/iupwin_canvas.c
new file mode 100755
index 0000000..bb88b8a
--- /dev/null
+++ b/iup/src/win/iupwin_canvas.c
@@ -0,0 +1,724 @@
+/** \file
+ * \brief Canvas Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <limits.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_canvas.h"
+#include "iup_key.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_brush.h"
+
+
+static void winCanvasSetScrollInfo(HWND hWnd, int imin, int imax, int ipos, int ipage, int flag)
+{
+ SCROLLINFO scrollinfo;
+ scrollinfo.cbSize = sizeof(SCROLLINFO);
+ scrollinfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ scrollinfo.nPage = ipage;
+ scrollinfo.nPos = ipos;
+ scrollinfo.nMax = imax;
+ scrollinfo.nMin = imin;
+ SetScrollInfo(hWnd, flag, &scrollinfo, TRUE);
+}
+
+static int winCanvasSetBgColorAttrib(Ihandle *ih, const char *value)
+{
+ (void)value;
+ iupdrvDisplayUpdate(ih);
+ return 1;
+}
+
+static int winCanvasSetDXAttrib(Ihandle *ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_HORIZ)
+ {
+ double posx, xmin, xmax;
+ float dx;
+ int iposx, ipagex;
+
+ if (!iupStrToFloat(value, &dx))
+ return 1;
+
+ xmin = iupAttribGetFloat(ih, "XMIN");
+ xmax = iupAttribGetFloat(ih, "XMAX");
+ posx = ih->data->posx;
+
+ iupCanvasCalcScrollIntPos(xmin, xmax, dx, posx,
+ IUP_SB_MIN, IUP_SB_MAX, &ipagex, &iposx);
+
+ if (dx >= (xmax-xmin))
+ {
+ if (iupAttribGetBoolean(ih, "XAUTOHIDE"))
+ ShowScrollBar(ih->handle, SB_HORZ, FALSE);
+ else
+ EnableScrollBar(ih->handle, SB_HORZ, ESB_DISABLE_BOTH);
+ return 1;
+ }
+ else
+ {
+ ShowScrollBar(ih->handle, SB_HORZ, TRUE);
+ EnableScrollBar(ih->handle, SB_HORZ, ESB_ENABLE_BOTH);
+ }
+
+ winCanvasSetScrollInfo(ih->handle, IUP_SB_MIN, IUP_SB_MAX, iposx, ipagex, SB_HORZ);
+
+ /* update position because it could be corrected */
+ iupCanvasCalcScrollRealPos(xmin, xmax, &posx,
+ IUP_SB_MIN, IUP_SB_MAX, ipagex, &iposx);
+
+ ih->data->posx = (float)posx;
+ }
+ return 1;
+}
+
+static int winCanvasSetPosXAttrib(Ihandle *ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_HORIZ)
+ {
+ double xmin, xmax, dx;
+ float posx;
+ int iposx, ipagex;
+
+ if (!iupStrToFloat(value, &posx))
+ return 1;
+
+ xmin = iupAttribGetFloat(ih, "XMIN");
+ xmax = iupAttribGetFloat(ih, "XMAX");
+ dx = iupAttribGetFloat(ih, "DX");
+
+ if (posx < xmin) posx = (float)xmin;
+ if (posx > (xmax - dx)) posx = (float)(xmax - dx);
+ ih->data->posx = posx;
+
+ iupCanvasCalcScrollIntPos(xmin, xmax, dx, posx,
+ IUP_SB_MIN, IUP_SB_MAX, &ipagex, &iposx);
+
+ SetScrollPos(ih->handle,SB_HORZ,iposx,TRUE);
+ }
+ return 1;
+}
+
+static int winCanvasSetDYAttrib(Ihandle *ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ double posy, ymin, ymax;
+ float dy;
+ int iposy, ipagey;
+
+ if (!iupStrToFloat(value, &dy))
+ return 1;
+
+ ymin = iupAttribGetFloat(ih, "YMIN");
+ ymax = iupAttribGetFloat(ih, "YMAX");
+ posy = ih->data->posy;
+
+ iupCanvasCalcScrollIntPos(ymin, ymax, dy, posy,
+ IUP_SB_MIN, IUP_SB_MAX, &ipagey, &iposy);
+
+ if (dy >= (ymax-ymin))
+ {
+ if (iupAttribGetBoolean(ih, "YAUTOHIDE"))
+ ShowScrollBar(ih->handle, SB_VERT, FALSE);
+ else
+ EnableScrollBar(ih->handle, SB_VERT, ESB_DISABLE_BOTH);
+ return 1;
+ }
+ else
+ {
+ ShowScrollBar(ih->handle, SB_VERT, TRUE);
+ EnableScrollBar(ih->handle, SB_VERT, ESB_ENABLE_BOTH);
+ }
+
+ winCanvasSetScrollInfo(ih->handle, IUP_SB_MIN, IUP_SB_MAX, iposy, ipagey, SB_VERT);
+
+ /* update position because it could be corrected */
+ iupCanvasCalcScrollRealPos(ymin, ymax, &posy,
+ IUP_SB_MIN, IUP_SB_MAX, ipagey, &iposy);
+
+ ih->data->posy = (float)posy;
+ }
+ return 1;
+}
+
+static int winCanvasSetPosYAttrib(Ihandle *ih, const char *value)
+{
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ double ymin, ymax, dy;
+ float posy;
+ int iposy, ipagey;
+
+ if (!iupStrToFloat(value, &posy))
+ return 1;
+
+ ymin = iupAttribGetFloat(ih, "YMIN");
+ ymax = iupAttribGetFloat(ih, "YMAX");
+ dy = iupAttribGetFloat(ih, "DY");
+
+ if (posy < ymin) posy = (float)ymin;
+ if (posy > (ymax - dy)) posy = (float)(ymax - dy);
+ ih->data->posy = posy;
+
+ iupCanvasCalcScrollIntPos(ymin, ymax, dy, posy,
+ IUP_SB_MIN, IUP_SB_MAX, &ipagey, &iposy);
+
+ SetScrollPos(ih->handle,SB_VERT,iposy,TRUE);
+ }
+ return 1;
+}
+
+static void winCanvasGetScrollInfo(HWND hWnd, int *ipos, int *ipage, int flag, int track)
+{
+ SCROLLINFO scrollinfo;
+ scrollinfo.cbSize = sizeof(SCROLLINFO);
+ if (track)
+ scrollinfo.fMask = SIF_PAGE | SIF_TRACKPOS;
+ else
+ scrollinfo.fMask = SIF_PAGE | SIF_POS;
+ GetScrollInfo(hWnd, flag, &scrollinfo);
+ *ipage = scrollinfo.nPage;
+ if (track)
+ *ipos = scrollinfo.nTrackPos;
+ else
+ *ipos = scrollinfo.nPos;
+}
+
+static void winCanvasUpdateHorScroll(Ihandle* ih, WORD winop)
+{
+ IFniff cb;
+ double xmin, xmax, posx, linex;
+ int ipagex, iposx, ilinex, op;
+
+ /* unused */
+ if (winop == SB_TOP ||
+ winop == SB_BOTTOM ||
+ winop == SB_ENDSCROLL)
+ return;
+
+ xmax = iupAttribGetFloat(ih,"XMAX");
+ xmin = iupAttribGetFloat(ih,"XMIN");
+
+ winCanvasGetScrollInfo(ih->handle, &iposx, &ipagex, SB_HORZ, winop==SB_THUMBTRACK? 1: 0);
+
+ if (!iupAttribGet(ih,"LINEX"))
+ {
+ ilinex = ipagex/10;
+ if (!ilinex)
+ ilinex = 1;
+ }
+ else
+ {
+ /* line and page convertions are the same */
+ linex = iupAttribGetFloat(ih,"LINEX");
+ iupCanvasCalcScrollIntPos(xmin, xmax, linex, 0,
+ IUP_SB_MIN, IUP_SB_MAX, &ilinex, NULL);
+ }
+
+ switch (winop)
+ {
+ case SB_LINEDOWN:
+ iposx = iposx + ilinex;
+ op = IUP_SBRIGHT;
+ break;
+ case SB_LINEUP:
+ iposx = iposx - ilinex;
+ op = IUP_SBLEFT;
+ break;
+ case SB_PAGEDOWN:
+ iposx = iposx + ipagex;
+ op = IUP_SBPGRIGHT;
+ break;
+ case SB_PAGEUP:
+ iposx = iposx - ipagex;
+ op = IUP_SBPGLEFT;
+ break;
+ case SB_THUMBTRACK:
+ op = IUP_SBDRAGH;
+ break;
+ case SB_THUMBPOSITION:
+ op = IUP_SBPOSH;
+ break;
+ default:
+ return;
+ }
+
+ iupCanvasCalcScrollRealPos(xmin, xmax, &posx,
+ IUP_SB_MIN, IUP_SB_MAX, ipagex, &iposx);
+
+ SetScrollPos(ih->handle,SB_HORZ,iposx,TRUE);
+ ih->data->posx = (float)posx;
+
+ cb = (IFniff)IupGetCallback(ih,"SCROLL_CB");
+ if (cb)
+ cb(ih,op,(float)posx,ih->data->posy);
+ else
+ {
+ IFnff cb = (IFnff)IupGetCallback(ih,"ACTION");
+ if (cb)
+ cb (ih, (float)posx, ih->data->posy);
+ }
+}
+
+static void winCanvasUpdateVerScroll(Ihandle* ih, WORD winop)
+{
+ IFniff cb;
+ double ymin, ymax, posy, liney;
+ int ipagey, iposy, iliney, op;
+
+ /* unused */
+ if (winop == SB_TOP ||
+ winop == SB_BOTTOM ||
+ winop == SB_ENDSCROLL)
+ return;
+
+ ymax = iupAttribGetFloat(ih,"YMAX");
+ ymin = iupAttribGetFloat(ih,"YMIN");
+
+ winCanvasGetScrollInfo(ih->handle, &iposy, &ipagey, SB_VERT, winop==SB_THUMBTRACK? 1: 0);
+
+ if (!iupAttribGet(ih, "LINEY"))
+ {
+ iliney = ipagey/10;
+ if (!iliney)
+ iliney = 1;
+ }
+ else
+ {
+ /* line and page convertions are the same */
+ liney = iupAttribGetFloat(ih,"LINEY");
+ iupCanvasCalcScrollIntPos(ymin, ymax, liney, 0,
+ IUP_SB_MIN, IUP_SB_MAX, &iliney, NULL);
+ }
+
+ switch (winop)
+ {
+ case SB_LINEDOWN:
+ iposy = iposy + iliney;
+ op = IUP_SBDN;
+ break;
+ case SB_LINEUP:
+ iposy = iposy - iliney;
+ op = IUP_SBUP;
+ break;
+ case SB_PAGEDOWN:
+ iposy = iposy + ipagey;
+ op = IUP_SBPGDN;
+ break;
+ case SB_PAGEUP:
+ iposy = iposy - ipagey;
+ op = IUP_SBPGUP;
+ break;
+ case SB_THUMBTRACK:
+ op = IUP_SBDRAGV;
+ break;
+ case SB_THUMBPOSITION:
+ op = IUP_SBPOSV;
+ break;
+ default:
+ return;
+ }
+
+ iupCanvasCalcScrollRealPos(ymin, ymax, &posy,
+ IUP_SB_MIN, IUP_SB_MAX, ipagey, &iposy);
+
+ SetScrollPos(ih->handle,SB_VERT,iposy,TRUE);
+ ih->data->posy = (float)posy;
+
+ cb = (IFniff)IupGetCallback(ih,"SCROLL_CB");
+ if (cb)
+ cb(ih, op, ih->data->posx,(float)posy);
+ else
+ {
+ IFnff cb = (IFnff)IupGetCallback(ih,"ACTION");
+ if (cb)
+ cb (ih, ih->data->posx, (float)posy);
+ }
+}
+
+static int winCanvasProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ switch (msg)
+ {
+ case WM_ERASEBKGND:
+ /* only paint background if ACTION is not defined */
+ if (!IupGetCallback(ih, "ACTION"))
+ {
+ RECT rect;
+ HDC hdc = (HDC)wp;
+ COLORREF color;
+ iupwinGetColorRef(ih, "BGCOLOR", &color);
+ GetClientRect(ih->handle, &rect);
+ FillRect(hdc, &rect, iupwinBrushGet(color));
+ }
+ /* always return non zero value */
+ *result = 1;
+ return 1;
+ case WM_PAINT:
+ {
+ IFnff cb = (IFnff)IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(ih->handle, &ps);
+ iupAttribSetStr(ih, "HDC_WMPAINT", (char*)&hdc);
+ iupAttribSetStrf(ih, "CLIPRECT", "%d %d %d %d", ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right-ps.rcPaint.left, ps.rcPaint.bottom-ps.rcPaint.top);
+
+ cb(ih, ih->data->posx, ih->data->posy);
+
+ iupAttribSetStr(ih, "CLIPRECT", NULL);
+ iupAttribSetStr(ih, "HDC_WMPAINT", NULL);
+ EndPaint(ih->handle, &ps);
+ }
+ break;
+ }
+ case WM_SIZE:
+ {
+ IFnii cb = (IFnii)IupGetCallback(ih, "RESIZE_CB");
+ if (cb)
+ {
+ RECT rect;
+ GetClientRect(ih->handle, &rect);
+ cb(ih, rect.right-rect.left, rect.bottom-rect.top);
+ /* w=LOWORD (lp), h=HIWORD(lp) can not be used because and invalid size
+ at the first time of WM_SIZE with scroolbars. */
+ }
+ *result = 0;
+ return 1;
+ }
+ case WM_GETDLGCODE:
+ /* avoid beeps when keys are pressed */
+ *result = DLGC_WANTCHARS|DLGC_WANTARROWS;
+ return 1;
+ case WM_MOUSEWHEEL:
+ {
+ IFnfiis cb = (IFnfiis)IupGetCallback(ih, "WHEEL_CB");
+ short delta = (short)HIWORD(wp);
+ if (cb)
+ {
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+ POINT p;
+ p.x = LOWORD(lp); p.y = HIWORD(lp);
+ ScreenToClient(ih->handle, &p);
+
+ iupwinButtonKeySetStatus(LOWORD(wp), status, 0);
+
+ cb(ih, (float)delta/120.0f, p.x, p.y, status);
+ }
+ else
+ {
+ if (ih->data->sb & IUP_SB_VERT)
+ {
+ int i, winop = delta>0? SB_LINEUP: SB_LINEDOWN;
+ delta = (short)abs(delta/120);
+ for (i=0; i < delta; i++)
+ SendMessage(ih->handle, WM_VSCROLL, MAKELONG(winop, 0), 0);
+ }
+ }
+
+ *result = 0;
+ return 1;
+ }
+ case WM_XBUTTONDBLCLK:
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_XBUTTONDOWN:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ {
+ /* Force focus on canvas click */
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ SetFocus(ih->handle);
+
+ SetCapture(ih->handle);
+
+ if (iupwinButtonDown(ih, msg, wp, lp))
+ {
+ /* refresh the cursor, it could have been changed in BUTTON_CB */
+ SendMessage(ih->handle, WM_SETCURSOR, (WPARAM)ih->handle, MAKELPARAM(1,WM_MOUSEMOVE));
+ }
+
+ if (msg==WM_XBUTTONDOWN || msg==WM_XBUTTONDBLCLK)
+ *result = 1;
+ else
+ *result = 0;
+ return 1;
+ }
+ case WM_MOUSEMOVE:
+ {
+ if (iupwinMouseMove(ih, msg, wp, lp))
+ {
+ /* refresh the cursor, it could have been changed in MOTION_CB */
+ SendMessage(ih->handle, WM_SETCURSOR, (WPARAM)ih->handle, MAKELPARAM(1,WM_MOUSEMOVE));
+ }
+
+ break; /* let iupwinBaseProc process enter/leavewin */
+ }
+ case WM_XBUTTONUP:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ {
+ ReleaseCapture();
+
+ if (iupwinButtonUp(ih, msg, wp, lp))
+ {
+ /* refresh the cursor, it could have been changed in BUTTON_CB */
+ SendMessage(ih->handle, WM_SETCURSOR, (WPARAM)ih->handle, MAKELPARAM(1,WM_MOUSEMOVE));
+ }
+
+ *result = 0;
+ if (msg==WM_XBUTTONUP)
+ *result = 1;
+ return 1;
+ }
+ case WM_KILLFOCUS:
+ {
+ if (GetCapture() == ih->handle)
+ ReleaseCapture();
+ break;
+ }
+ case WM_SETCURSOR:
+ {
+ if (ih->handle == (HWND)wp && LOWORD(lp)==HTCLIENT)
+ {
+ HCURSOR hCur = (HCURSOR)iupAttribGet(ih, "_IUPWIN_HCURSOR");
+ if (hCur)
+ {
+ SetCursor(hCur);
+ *result = 1;
+ return 1;
+ }
+ else if (iupAttribGet(ih, "CURSOR"))
+ {
+ SetCursor(NULL);
+ *result = 1;
+ return 1;
+ }
+ }
+ break;
+ }
+ case WM_INITMENU:
+ /* abort capture if a menu is opened */
+ ReleaseCapture();
+ break;
+ case WM_VSCROLL:
+ winCanvasUpdateVerScroll(ih, LOWORD(wp));
+ *result = 0;
+ return 1;
+ case WM_HSCROLL:
+ winCanvasUpdateHorScroll(ih, LOWORD(wp));
+ *result = 0;
+ return 1;
+ }
+
+ /* can be a container */
+ if (ih->firstchild)
+ return iupwinBaseContainerProc(ih, msg, wp, lp, result);
+ else
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+static void winCanvasRegisterClass(void)
+{
+ WNDCLASS wndclass;
+ ZeroMemory(&wndclass, sizeof(WNDCLASS));
+
+ wndclass.hInstance = iupwin_hinstance;
+ wndclass.lpszClassName = "IupCanvas";
+ wndclass.lpfnWndProc = (WNDPROC)iupwinBaseWinProc;
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; /* using CS_OWNDC will minimize the work of cdActivate in the CD library */
+ wndclass.hbrBackground = NULL; /* remove the background to optimize redraw */
+
+ RegisterClass(&wndclass);
+}
+
+static int winCanvasMapMethod(Ihandle* ih)
+{
+ CLIENTCREATESTRUCT clientstruct;
+ void *clientdata = NULL;
+ char *classname;
+ DWORD dwStyle = WS_CHILD, dwExStyle = 0;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (ih->iclass->is_interactive)
+ {
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ dwStyle |= WS_TABSTOP;
+ }
+
+ if (ih->firstchild) /* can be a container */
+ {
+ dwStyle |= WS_CLIPSIBLINGS;
+
+ if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED"))
+ dwExStyle |= WS_EX_COMPOSITED;
+ else
+ dwStyle |= WS_CLIPCHILDREN;
+ }
+
+ if (iupAttribGetBoolean(ih, "MDICLIENT"))
+ {
+ /* creating a MDI Client that will be inside the MDI Frame,
+ it will work as parent of all MDI children */
+ Ihandle *winmenu = IupGetAttributeHandle(ih, "MDIMENU");
+
+ classname = "mdiclient";
+
+ iupAttribSetStr(ih, "BORDER", "NO");
+
+ iupAttribSetStr(IupGetDialog(ih), "MDICLIENT_HANDLE", (char*)ih);
+
+ clientdata = &clientstruct;
+ clientstruct.hWindowMenu = winmenu? winmenu->handle: NULL;
+
+ /* The system increments the identifier
+ for each additional MDI child window the application creates,
+ and reassigns identifiers when the application
+ destroys a window to keep the range of identifiers contiguous. */
+ clientstruct.idFirstChild = IUP_MDICHILD_START;
+ }
+ else
+ classname = "IupCanvas";
+
+ if (iupAttribGetBoolean(ih, "BORDER"))
+ dwStyle |= WS_BORDER;
+
+ ih->data->sb = iupBaseGetScrollbar(ih);
+ if (ih->data->sb & IUP_SB_HORIZ)
+ dwStyle |= WS_HSCROLL;
+ if (ih->data->sb & IUP_SB_VERT)
+ dwStyle |= WS_VSCROLL;
+
+ ih->serial = iupDialogGetChildId(ih);
+
+ ih->handle = CreateWindowEx(dwExStyle,/* extended style */
+ classname, /* window class */
+ NULL, /* title */
+ dwStyle, /* window style */
+ 0, /* x-position */
+ 0, /* y-position */
+ 10, /* default width to avoid 0 */
+ 10, /* default height to avoid 0 */
+ iupChildTreeGetNativeParentHandle(ih), /* window parent */
+ (HMENU)ih->serial, /* child identifier */
+ iupwin_hinstance, /* instance of app. */
+ clientdata);
+
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ /* associate HWND with Ihandle*, all Win32 controls must call this. */
+ iupwinHandleSet(ih);
+
+ IupSetCallback(ih, "_IUPWIN_OLDPROC_CB", (Icallback)DefWindowProc);
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winCanvasProc);
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ return IUP_NOERROR;
+}
+
+static void winCanvasMDICloseChildren(Ihandle* client)
+{
+ HWND hWndChild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0);
+
+ /* As long as the MDI client has a child, close it */
+ while (hWndChild)
+ {
+ Ihandle* child = iupwinHandleGet(hWndChild);
+ if (iupObjectCheck(child) && iupAttribGetBoolean(child, "MDICHILD"))
+ IupDestroy(child);
+
+ hWndChild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0);
+ }
+}
+
+static void winCanvasUnMapMethod(Ihandle* ih)
+{
+ if (iupAttribGetBoolean(ih, "MDICLIENT"))
+ {
+ /* hide the MDI client window to avoid multiple re-paints */
+ ShowWindow(ih->handle, SW_HIDE);
+
+ /* must destroy all MDI Children */
+ winCanvasMDICloseChildren(ih);
+
+ DestroyWindow(ih->handle);
+
+ /* mdiclient class is not a IUP class, must return here */
+ return;
+ }
+
+ /* remove the association before destroying */
+ iupwinHandleRemove(ih);
+
+ /* remove from parent and destroys window */
+ SetParent(ih->handle, NULL);
+ DestroyWindow(ih->handle);
+}
+
+static void winCanvasReleaseMethod(Iclass* ic)
+{
+ (void)ic;
+ if (iupwinClassExist("IupCanvas"))
+ UnregisterClass("IupCanvas", iupwin_hinstance);
+}
+
+void iupdrvCanvasInitClass(Iclass* ic)
+{
+ if (!iupwinClassExist("IupCanvas"))
+ winCanvasRegisterClass();
+
+ /* Driver Dependent Class functions */
+ ic->Map = winCanvasMapMethod;
+ ic->UnMap = winCanvasUnMapMethod;
+ ic->Release = winCanvasReleaseMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winCanvasSetBgColorAttrib, "255 255 255", NULL, IUPAF_DEFAULT); /* force new default value */
+
+ /* IupCanvas only */
+ iupClassRegisterAttribute(ic, "DRAWSIZE", iupdrvBaseGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "DX", NULL, winCanvasSetDXAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "DY", NULL, winCanvasSetDYAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "POSX", iupCanvasGetPosXAttrib, winCanvasSetPosXAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "POSY", iupCanvasGetPosYAttrib, winCanvasSetPosYAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "XAUTOHIDE", NULL, NULL, "YES", NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "YAUTOHIDE", NULL, NULL, "YES", NULL, IUPAF_NOT_MAPPED);
+
+ /* IupCanvas Windows only */
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "HWND", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_clipboard.c b/iup/src/win/iupwin_clipboard.c
new file mode 100755
index 0000000..1e0fab4
--- /dev/null
+++ b/iup/src/win/iupwin_clipboard.c
@@ -0,0 +1,190 @@
+/** \file
+ * \brief Clipboard for the Windows Driver.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+
+#include "iupwin_drv.h"
+
+
+static int winClipboardSetTextAttrib(Ihandle *ih, const char *value)
+{
+ HANDLE hHandle;
+ void* clip_str;
+ int size = strlen(value)+1;
+ (void)ih;
+
+ if (!OpenClipboard(NULL))
+ return 0;
+
+ hHandle = GlobalAlloc(GMEM_MOVEABLE, size);
+ if (!hHandle)
+ return 0;
+
+ clip_str = GlobalLock(hHandle);
+ CopyMemory(clip_str, value, size);
+ GlobalUnlock(hHandle);
+
+ EmptyClipboard();
+ SetClipboardData(CF_TEXT, hHandle);
+ CloseClipboard();
+
+ return 0;
+}
+
+static char* winClipboardGetTextAttrib(Ihandle *ih)
+{
+ HANDLE hHandle;
+ char* str;
+ (void)ih;
+
+ if (!OpenClipboard(NULL))
+ return NULL;
+
+ hHandle = GetClipboardData(CF_TEXT);
+ if (!hHandle)
+ {
+ CloseClipboard();
+ return NULL;
+ }
+
+ str = iupStrGetMemoryCopy((char*)GlobalLock(hHandle));
+
+ GlobalUnlock(hHandle);
+ CloseClipboard();
+ return str;
+}
+
+static int winClipboardSetImageAttrib(Ihandle *ih, const char *value)
+{
+ HBITMAP hBitmap;
+
+ if (!OpenClipboard(NULL))
+ return 0;
+
+ hBitmap = (HBITMAP)iupImageGetImage(value, ih, 0);
+ iupImageClearCache(ih, hBitmap);
+
+ EmptyClipboard();
+ SetClipboardData(CF_BITMAP, (HANDLE)hBitmap);
+ CloseClipboard();
+
+ return 0;
+}
+
+static int winClipboardSetNativeImageAttrib(Ihandle *ih, const char *value)
+{
+ if (!OpenClipboard(NULL))
+ return 0;
+
+ EmptyClipboard();
+ SetClipboardData(CF_DIB, (HANDLE)value);
+ CloseClipboard();
+
+ (void)ih;
+ return 0;
+}
+
+static HANDLE winCopyHandle(HANDLE hHandle)
+{
+ void *src_data, *dst_data;
+ SIZE_T size = GlobalSize(hHandle);
+ HANDLE hNewHandle = GlobalAlloc(GMEM_MOVEABLE, size);
+ if (!hNewHandle)
+ return NULL;
+
+ src_data = GlobalLock(hHandle);
+ dst_data = GlobalLock(hNewHandle);
+ CopyMemory(dst_data, src_data, size);
+ GlobalUnlock(hHandle);
+ GlobalUnlock(hNewHandle);
+
+ return hNewHandle;
+}
+
+static char* winClipboardGetNativeImageAttrib(Ihandle *ih)
+{
+ HANDLE hHandle;
+
+ if (!OpenClipboard(NULL))
+ return 0;
+
+ hHandle = GetClipboardData(CF_DIB);
+ if (!hHandle)
+ {
+ CloseClipboard();
+ return NULL;
+ }
+
+ hHandle = winCopyHandle(hHandle); /* must duplicate because CloseClipboard will invalidate the handle */
+ CloseClipboard();
+
+ (void)ih;
+ return (char*)hHandle;
+}
+
+static char* winClipboardGetTextAvailableAttrib(Ihandle *ih)
+{
+ int check;
+ (void)ih;
+ OpenClipboard(NULL);
+ check = IsClipboardFormatAvailable(CF_TEXT);
+ CloseClipboard();
+ if (check)
+ return "YES";
+ else
+ return "NO";
+}
+
+static char* winClipboardGetImageAvailableAttrib(Ihandle *ih)
+{
+ int check;
+ (void)ih;
+ OpenClipboard(NULL);
+ check = IsClipboardFormatAvailable(CF_DIB);
+ CloseClipboard();
+ if (check)
+ return "YES";
+ else
+ return "NO";
+}
+
+/******************************************************************************/
+
+Ihandle* IupClipboard(void)
+{
+ return IupCreate("clipboard");
+}
+
+Iclass* iupClipboardGetClass(void)
+{
+ Iclass* ic = iupClassNew(NULL);
+
+ ic->name = "clipboard";
+ ic->format = NULL; /* no parameters */
+ ic->nativetype = IUP_TYPECONTROL;
+ ic->childtype = IUP_CHILDNONE;
+ ic->is_interactive = 0;
+
+ /* Attribute functions */
+ iupClassRegisterAttribute(ic, "TEXT", winClipboardGetTextAttrib, winClipboardSetTextAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "NATIVEIMAGE", winClipboardGetNativeImageAttrib, winClipboardSetNativeImageAttrib, NULL, NULL, IUPAF_NO_STRING|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, winClipboardSetImageAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TEXTAVAILABLE", winClipboardGetTextAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEAVAILABLE", winClipboardGetImageAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ return ic;
+}
diff --git a/iup/src/win/iupwin_colordlg.c b/iup/src/win/iupwin_colordlg.c
new file mode 100755
index 0000000..f0baa79
--- /dev/null
+++ b/iup/src/win/iupwin_colordlg.c
@@ -0,0 +1,133 @@
+/** \file
+ * \brief IupColorDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <stdio.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+
+
+#define IUP_COLOR_RED 706
+
+static UINT_PTR winColorDlgHookProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+ (void)wParam;
+ if (uiMsg == WM_INITDIALOG)
+ {
+ HWND hWndItem;
+ CHOOSECOLOR* choosecolor = (CHOOSECOLOR*)lParam;
+ Ihandle* ih = (Ihandle*)choosecolor->lCustData;
+
+ char* value = iupAttribGet(ih, "TITLE");
+ if (value)
+ SetWindowText(hWnd, value);
+
+ ih->handle = hWnd;
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+ iupAttribSetStr(ih, "HWND", (char*)hWnd); /* used by HELP_CB in winDialogBaseProc */
+
+ hWndItem = GetDlgItem(hWnd, IUP_COLOR_RED);
+ SetFocus(hWndItem);
+ }
+ return 0;
+}
+
+static char* winColorDlgColorsToString(COLORREF* lpCustColors)
+{
+ int i, inc, off = 0;
+ char iup_str[20];
+ char* str = iupStrGetMemory(300);
+ for (i=0; i < 16; i++)
+ {
+ inc = sprintf(iup_str, "%d %d %d;", (int)GetRValue(*lpCustColors), (int)GetGValue(*lpCustColors), (int)GetBValue(*lpCustColors));
+ memcpy(str+off, iup_str, inc);
+ off += inc;
+ lpCustColors++;
+ }
+ str[off-1] = 0; /* remove last separator */
+ return str;
+}
+
+static void winColorDlgStringToColors(char* str, COLORREF* lpCustColors)
+{
+ int i = 0;
+ unsigned char r, g, b;
+
+ while (str && *str && i < 16)
+ {
+ if (iupStrToRGB(str, &r, &g, &b))
+ *lpCustColors = RGB(r,g,b);
+
+ str = strchr(str, ';');
+ if (str) str++;
+ i++;
+ lpCustColors++;
+ }
+}
+
+static int winColorDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ CHOOSECOLOR choosecolor;
+ unsigned char r, g, b;
+ COLORREF lpCustColors[16];
+ char* value;
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ if (!parent)
+ parent = GetActiveWindow();
+
+ iupStrToRGB(iupAttribGet(ih, "VALUE"), &r, &g, &b);
+
+ ZeroMemory(lpCustColors, 16*sizeof(COLORREF));
+
+ value = iupAttribGetStr(ih, "COLORTABLE");
+ if (value)
+ winColorDlgStringToColors(value, lpCustColors);
+
+ ZeroMemory(&choosecolor, sizeof(CHOOSECOLOR));
+ choosecolor.lStructSize = sizeof(CHOOSECOLOR);
+ choosecolor.hwndOwner = parent;
+ choosecolor.rgbResult = RGB(r, g, b);
+ choosecolor.lpCustColors = lpCustColors;
+ choosecolor.lCustData = (LPARAM)ih;
+
+ choosecolor.Flags = CC_RGBINIT|CC_FULLOPEN;
+ if (IupGetCallback(ih, "HELP_CB"))
+ choosecolor.Flags |= CC_SHOWHELP;
+
+ choosecolor.Flags |= CC_ENABLEHOOK;
+ choosecolor.lpfnHook = (LPCCHOOKPROC)winColorDlgHookProc;
+
+ if (!ChooseColor(&choosecolor))
+ {
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "COLORTABLE", NULL);
+ iupAttribSetStr(ih, "STATUS", NULL);
+ return IUP_NOERROR;
+ }
+
+ iupAttribSetStrf(ih, "VALUE", "%d %d %d", GetRValue(choosecolor.rgbResult),
+ GetGValue(choosecolor.rgbResult),
+ GetBValue(choosecolor.rgbResult));
+ iupAttribSetStr(ih, "COLORTABLE", winColorDlgColorsToString(lpCustColors));
+ iupAttribSetStr(ih, "STATUS", "1");
+
+ return IUP_NOERROR;
+}
+
+void iupdrvColorDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = winColorDlgPopup;
+}
diff --git a/iup/src/win/iupwin_common.c b/iup/src/win/iupwin_common.c
new file mode 100755
index 0000000..a1a7c0f
--- /dev/null
+++ b/iup/src/win/iupwin_common.c
@@ -0,0 +1,865 @@
+/** \file
+ * \brief Windows Base Procedure
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_childtree.h"
+#include "iup_key.h"
+#include "iup_str.h"
+#include "iup_class.h"
+#include "iup_attrib.h"
+#include "iup_focus.h"
+#include "iup_image.h"
+#include "iup_dialog.h"
+#include "iup_drvinfo.h"
+#include "iup_drv.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_brush.h"
+
+
+#ifndef XBUTTON1
+#define XBUTTON1 0x0001 /* not defined in MingW3 */
+#endif
+
+int iupwinClassExist(const char* name)
+{
+ WNDCLASS WndClass;
+ if (GetClassInfo(iupwin_hinstance, name, &WndClass))
+ return 1;
+ return 0;
+}
+
+int iupwinGetScreenRes(void)
+{
+ int res;
+ HDC ScreenDC = GetDC(NULL);
+ res = GetDeviceCaps(ScreenDC, LOGPIXELSY);
+ ReleaseDC(NULL, ScreenDC);
+ return res;
+}
+
+void iupdrvActivate(Ihandle* ih)
+{
+ /* do not use BM_CLICK because it changes the focus
+ and does not animates the button press */
+ SendMessage(ih->handle, BM_SETSTATE, TRUE, 0);
+ IupFlush();
+ Sleep(150);
+ SendMessage(GetParent(ih->handle), WM_COMMAND, MAKEWPARAM(0, BN_CLICKED), (LPARAM)ih->handle);
+ SendMessage(ih->handle, BM_SETSTATE, FALSE, 0);
+}
+
+WCHAR* iupwinStrChar2Wide(const char* str)
+{
+ if (str)
+ {
+ int len = strlen(str)+1;
+ WCHAR* wstr = malloc(len * sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, len);
+ return wstr;
+ }
+
+ return NULL;
+}
+
+int iupdrvGetScrollbarSize(void)
+{
+ int xv = GetSystemMetrics(SM_CXVSCROLL);
+ int yh = GetSystemMetrics(SM_CYHSCROLL);
+ return xv > yh ? xv : yh;
+}
+
+void iupdrvReparent(Ihandle* ih)
+{
+ SetParent(ih->handle, iupChildTreeGetNativeParentHandle(ih));
+}
+
+void iupdrvBaseLayoutUpdateMethod(Ihandle *ih)
+{
+ SetWindowPos(ih->handle, NULL, ih->x, ih->y, ih->currentwidth, ih->currentheight,
+ SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
+}
+
+void iupdrvDisplayRedraw(Ihandle *ih)
+{
+ /* REDRAW Now */
+ RedrawWindow(ih->handle,NULL,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_NOCHILDREN|RDW_UPDATENOW);
+}
+
+void iupdrvDisplayUpdate(Ihandle *ih)
+{
+ /* Post a REDRAW */
+ RedrawWindow(ih->handle,NULL,NULL,RDW_ERASE|RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_NOCHILDREN);
+}
+
+void iupdrvScreenToClient(Ihandle* ih, int *x, int *y)
+{
+ POINT p;
+ p.x = *x;
+ p.y = *y;
+ ScreenToClient(ih->handle, &p);
+ *x = p.x;
+ *y = p.y;
+}
+
+static void winTrackMouse(HWND hwnd, int enter)
+{
+ TRACKMOUSEEVENT mouse;
+ mouse.cbSize = sizeof(TRACKMOUSEEVENT);
+
+ if (enter)
+ mouse.dwFlags = TME_HOVER;
+ else
+ mouse.dwFlags = TME_LEAVE;
+
+ mouse.hwndTrack = hwnd;
+ mouse.dwHoverTime = 1;
+ TrackMouseEvent(&mouse);
+}
+
+static void winCallEnterLeaveWindow(Ihandle *ih, int enter)
+{
+ Icallback cb = NULL;
+
+ if (!ih->iclass->is_interactive)
+ return;
+
+ if (enter)
+ {
+ winTrackMouse(ih->handle, 0);
+
+ if (!iupAttribGetInt(ih, "_IUPWIN_ENTERWIN"))
+ {
+ cb = IupGetCallback(ih,"ENTERWINDOW_CB");
+ iupAttribSetStr(ih, "_IUPWIN_ENTERWIN", "1");
+ }
+ }
+ else
+ {
+ cb = IupGetCallback(ih,"LEAVEWINDOW_CB");
+ iupAttribSetStr(ih, "_IUPWIN_ENTERWIN", NULL);
+ }
+
+ if (cb)
+ cb(ih);
+}
+
+void iupwinMergeStyle(Ihandle* ih, DWORD old_mask, DWORD value)
+{
+ DWORD dwStyle = GetWindowLong(ih->handle, GWL_STYLE);
+ dwStyle &= ~(old_mask); /* clear old bits */
+ dwStyle |= value;
+ SetWindowLong(ih->handle, GWL_STYLE, dwStyle);
+}
+
+void iupwinSetStyle(Ihandle* ih, DWORD value, int set)
+{
+ DWORD dwStyle = GetWindowLong(ih->handle, GWL_STYLE);
+ if (set)
+ dwStyle |= value;
+ else
+ dwStyle &= ~(value);
+ SetWindowLong(ih->handle, GWL_STYLE, dwStyle);
+}
+
+int iupwinBaseProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ (void)lp;
+
+ switch (msg)
+ {
+ case WM_GETDLGCODE:
+ {
+ *result = DLGC_WANTALLKEYS;
+ return 1;
+ }
+ case WM_NOTIFY: /* usually sent only to parent,
+ but TIPs are configured to be handled here */
+ {
+ NMHDR* msg_info = (NMHDR*)lp;
+ if (msg_info->code == TTN_GETDISPINFO)
+ iupwinTipsGetDispInfo(lp);
+ break;
+ }
+ case WM_DROPFILES:
+ iupwinDropFiles((HDROP)wp, ih);
+ break;
+ case WM_HELP:
+ {
+ Ihandle* child;
+ HELPINFO* help_info = (HELPINFO*)lp;
+
+ if (help_info->iContextType == HELPINFO_MENUITEM)
+ child = iupwinMenuGetItemHandle((HMENU)help_info->hItemHandle, (int)help_info->iCtrlId);
+ else
+ child = iupwinHandleGet(help_info->hItemHandle);
+
+ if (child)
+ {
+ Icallback cb = (Icallback) IupGetCallback(child, "HELP_CB");
+ if (cb)
+ {
+ if (cb(child) == IUP_CLOSE)
+ IupExitLoop();
+
+ *result = 0;
+ return 1; /* abort default processing */
+ }
+ }
+ break;
+ }
+ case WM_MOUSELEAVE:
+ winCallEnterLeaveWindow(ih, 0);
+ break;
+ case WM_MOUSEMOVE:
+ winCallEnterLeaveWindow(ih, 1);
+ break;
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ if (!iupwinKeyEvent(ih, (int)wp, 1))
+ {
+ *result = 0;
+ return 1; /* abort default processing */
+ }
+ break;
+ case WM_SYSKEYUP:
+ case WM_KEYUP:
+ {
+ int ret;
+ if (wp == VK_SNAPSHOT) /* called only on key up */
+ {
+ ret = iupwinKeyEvent(ih, (int)wp, 1);
+ if (ret && iupObjectCheck(ih))
+ ret = iupwinKeyEvent(ih, (int)wp, 0);
+ }
+ else
+ ret = iupwinKeyEvent(ih, (int)wp, 0);
+
+ if (!ret)
+ {
+ *result = 0;
+ return 1; /* abort default processing */
+ }
+
+ break;
+ }
+ case WM_SETFOCUS:
+ iupwinWmSetFocus(ih);
+ break;
+ case WM_KILLFOCUS:
+ iupCallKillFocusCb(ih);
+ break;
+ case WOM_CLOSE:
+ case WOM_DONE:
+ case WOM_OPEN:
+ {
+ IFni cb = (IFni)IupGetCallback(ih, "WOM_CB");
+ if (cb)
+ {
+ int v = -2; /* Error */
+ switch(msg)
+ {
+ case WOM_OPEN: v = 1; break;
+ case WOM_DONE: v = 0; break;
+ case WOM_CLOSE: v = -1; break;
+ }
+ cb(ih, v);
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+LRESULT CALLBACK iupwinBaseWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ int ret = 0;
+ LRESULT result = 0;
+ IwinProc winProc;
+ WNDPROC oldProc;
+ Ihandle *ih;
+
+ ih = iupwinHandleGet(hwnd);
+ if (!ih)
+ return DefWindowProc(hwnd, msg, wp, lp); /* should never happen */
+
+ /* retrieve the control previous procedure for subclassing */
+ oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB");
+
+ /* check if the element defines a custom procedure */
+ winProc = (IwinProc)IupGetCallback(ih, "_IUPWIN_CTRLPROC_CB");
+ if (winProc)
+ ret = winProc(ih, msg, wp, lp, &result);
+ else
+ ret = iupwinBaseProc(ih, msg, wp, lp, &result);
+
+ if (ret)
+ return result;
+ else
+ return CallWindowProc(oldProc, hwnd, msg, wp, lp);
+}
+
+static Ihandle* winContainerWmCommandGetIhandle(Ihandle *ih, WPARAM wp, LPARAM lp)
+{
+ /* WPARAM - if HIWORD is 0 if the message is from a menu.
+ or HIWORD is 1 if the message is from an accelerator.
+ or HIWORD is the notification code if the message is from a control.
+ LOWORD is the identifier.
+ LPARAM - the control sending the message or 0. */
+
+ Ihandle *child = NULL;
+
+ if (HIWORD(wp)==0 && lp==0 && LOWORD(wp)>10)
+ {
+ Ihandle* dlg_menu = IupGetAttributeHandle(ih, "MENU");
+ if (dlg_menu)
+ child = iupwinMenuGetItemHandle((HMENU)dlg_menu->handle, LOWORD(wp)); /* menu */
+ }
+ else
+ {
+ if (lp==0)
+ child = ih; /* native parent */
+ else
+ {
+ child = iupwinHandleGet((void*)lp); /* control */
+ if (!child)
+ child = iupwinHandleGet((void*)GetParent((HWND)lp)); /* control */
+ }
+ }
+
+ return child;
+}
+
+int iupwinBaseContainerProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ /* All messages here are sent to the parent Window,
+ but they are usefull for child controls. */
+
+ switch (msg)
+ {
+ case WM_COMMAND:
+ {
+ Ihandle* child = winContainerWmCommandGetIhandle(ih, wp, lp);
+ if (child)
+ {
+ IFnii cb = (IFnii)IupGetCallback(child, "_IUPWIN_COMMAND_CB");
+ if (cb)
+ cb(child, wp, lp);
+ }
+
+ break;
+ }
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORSCROLLBAR:
+ case WM_CTLCOLORSTATIC:
+ {
+ Ihandle* child = iupwinHandleGet((void*)lp);
+ if (child)
+ {
+ IFctlColor cb = (IFctlColor)IupGetCallback(child, "_IUPWIN_CTLCOLOR_CB");
+ if (cb)
+ return cb(child, (HDC)wp, result);
+ }
+ break;
+ }
+ case WM_DRAWITEM: /* for OWNERDRAW controls */
+ {
+ Ihandle *child = NULL;
+ DRAWITEMSTRUCT *drawitem = (LPDRAWITEMSTRUCT)lp;
+ if (!drawitem)
+ break;
+
+ if (wp == 0) /* a menu */
+ child = iupwinMenuGetItemHandle((HMENU)drawitem->hwndItem, drawitem->itemID);
+ else
+ child = iupwinHandleGet(drawitem->hwndItem);
+
+ if (child)
+ {
+ IFdrawItem cb = (IFdrawItem)IupGetCallback(child, "_IUPWIN_DRAWITEM_CB");
+ if (cb)
+ {
+ cb(child, (void*)drawitem);
+ *result = TRUE;
+ return 1;
+ }
+ }
+ break;
+ }
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ {
+ Ihandle *child = iupwinHandleGet((void*)lp);
+ if (child)
+ {
+ IFni cb = (IFni)IupGetCallback(child, "_IUPWIN_CUSTOMSCROLL_CB");
+ if (cb)
+ cb(child, LOWORD(wp));
+ }
+ break;
+ }
+ case WM_NOTIFY: /* Currently, the following controls support custom draw functionality:
+ Header, List-view, Rebar, Toolbar, ToolTip, Trackbar, Tree-view.
+ And for Button if using Windows XP Style. */
+ {
+ Ihandle *child;
+ NMHDR* msg_info = (NMHDR*)lp;
+ if (!msg_info)
+ break;
+
+ child = iupwinHandleGet(msg_info->hwndFrom);
+ if (child)
+ {
+ IFnotify cb = (IFnotify)IupGetCallback(child, "_IUPWIN_NOTIFY_CB");
+ if (cb)
+ {
+ if (cb(child, (void*)msg_info, result))
+ return 1;
+ }
+ }
+ break;
+ }
+ }
+
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+void iupwinChangeProc(Ihandle *ih, WNDPROC new_proc)
+{
+ IupSetCallback(ih, "_IUPWIN_OLDPROC_CB", (Icallback)GetWindowLongPtr(ih->handle, GWLP_WNDPROC));
+ SetWindowLongPtr(ih->handle, GWLP_WNDPROC, (LONG_PTR)new_proc);
+}
+
+void iupdrvBaseUnMapMethod(Ihandle* ih)
+{
+ WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB");
+ if (oldProc)
+ {
+ SetWindowLongPtr(ih->handle, GWLP_WNDPROC, (LONG_PTR)oldProc);
+ IupSetCallback(ih, "_IUPWIN_OLDPROC_CB", NULL);
+ }
+
+ /* remove the association before destroying */
+ iupwinHandleRemove(ih);
+
+ /* destroys window (it will remove from parent) */
+ DestroyWindow(ih->handle);
+}
+
+void iupwinDropFiles(HDROP hDrop, Ihandle *ih)
+{
+ char *filename;
+ int i, numFiles, numchar, ret;
+ POINT point;
+
+ IFnsiii cb = (IFnsiii)IupGetCallback(ih, "DROPFILES_CB");
+ if (!cb) return;
+
+ numFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
+ DragQueryPoint(hDrop, &point);
+ for (i = 0; i < numFiles; i++)
+ {
+ numchar = DragQueryFile(hDrop, i, NULL, 0);
+ filename = malloc(numchar+1);
+ if (!filename)
+ break;
+
+ DragQueryFile(hDrop, i, filename, numchar+1);
+
+ ret = cb(ih, filename, numFiles-i-1, (int) point.x, (int) point.y);
+
+ free(filename);
+
+ if (ret == IUP_IGNORE)
+ break;
+ }
+ DragFinish(hDrop);
+}
+
+int iupwinGetColorRef(Ihandle *ih, char *name, COLORREF *color)
+{
+ unsigned char r, g, b;
+ /* must use IupGetAttribute to use inheritance */
+ if (iupStrToRGB(IupGetAttribute(ih, name), &r, &g, &b))
+ {
+ *color = RGB(r,g,b);
+ return 1;
+ }
+ return 0;
+}
+
+int iupwinGetParentBgColor(Ihandle* ih, COLORREF* cr)
+{
+ unsigned char r, g, b;
+ char* color = iupBaseNativeParentGetBgColorAttrib(ih);
+ if (iupStrToRGB(color, &r, &g, &b))
+ {
+ *cr = RGB(r,g,b);
+ return 1;
+ }
+ return 0;
+}
+
+int iupdrvBaseSetZorderAttrib(Ihandle* ih, const char* value)
+{
+ if (IsWindowVisible(ih->handle))
+ {
+ if (iupStrEqualNoCase(value, "TOP"))
+ SetWindowPos(ih->handle, HWND_TOP, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
+ else
+ SetWindowPos(ih->handle, HWND_BOTTOM, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
+ }
+
+ return 0;
+}
+
+void iupdrvSetVisible(Ihandle* ih, int visible)
+{
+ ShowWindow(ih->handle, visible? SW_SHOWNORMAL: SW_HIDE);
+}
+
+int iupdrvIsVisible(Ihandle* ih)
+{
+ return IsWindowVisible(ih->handle);
+}
+
+int iupdrvIsActive(Ihandle* ih)
+{
+ return IsWindowEnabled(ih->handle);
+}
+
+void iupdrvSetActive(Ihandle* ih, int enable)
+{
+ EnableWindow(ih->handle, enable);
+}
+
+int iupdrvBaseSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (!value) value = "";
+ SetWindowText(ih->handle, value);
+ return 0;
+}
+
+char* iupdrvBaseGetTitleAttrib(Ihandle* ih)
+{
+ int nc = GetWindowTextLength(ih->handle);
+ if (nc)
+ {
+ char* str = iupStrGetMemory(nc+1);
+ GetWindowText(ih->handle, str, nc+1);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+int iupwinSetDragDropAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ DragAcceptFiles(ih->handle, TRUE);
+ else
+ DragAcceptFiles(ih->handle, FALSE);
+ return 1;
+}
+
+char *iupdrvBaseGetXAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+ RECT rect;
+ GetWindowRect(ih->handle, &rect);
+ sprintf(str, "%d", (int)rect.left);
+ return str;
+}
+
+char *iupdrvBaseGetYAttrib(Ihandle *ih)
+{
+ char* str = iupStrGetMemory(20);
+ RECT rect;
+ GetWindowRect(ih->handle, &rect);
+ sprintf(str, "%d", (int)rect.top);
+ return str;
+}
+
+char* iupdrvBaseGetClientSizeAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(20);
+ RECT rect;
+ GetClientRect(ih->handle, &rect);
+ sprintf(str, "%dx%d", (int)(rect.right-rect.left), (int)(rect.bottom-rect.top));
+ return str;
+}
+
+#ifndef IDC_HAND
+#define IDC_HAND MAKEINTRESOURCE(32649)
+#endif
+#ifndef IDC_APPSTARTING
+#define IDC_APPSTARTING MAKEINTRESOURCE(32650)
+#endif
+#ifndef IDC_HELP
+#define IDC_HELP MAKEINTRESOURCE(32651)
+#endif
+
+static HCURSOR winGetCursor(Ihandle* ih, const char* name)
+{
+ static struct {
+ const char* iupname;
+ const char* sysname;
+ } table[] = {
+ {"NONE", NULL},
+ {"NULL", NULL},
+ {"ARROW", IDC_ARROW},
+ {"BUSY", IDC_WAIT},
+ {"CROSS", IDC_CROSS},
+ {"HAND", IDC_HAND},
+ {"MOVE", IDC_SIZEALL},
+ {"RESIZE_N", IDC_SIZENS},
+ {"RESIZE_S", IDC_SIZENS},
+ {"RESIZE_NS", IDC_SIZENS},
+ {"RESIZE_W", IDC_SIZEWE},
+ {"RESIZE_E", IDC_SIZEWE},
+ {"RESIZE_WE", IDC_SIZEWE},
+ {"RESIZE_NE", IDC_SIZENESW},
+ {"RESIZE_SE", IDC_SIZENWSE},
+ {"RESIZE_NW", IDC_SIZENWSE},
+ {"RESIZE_SW", IDC_SIZENESW},
+ {"TEXT", IDC_IBEAM},
+ {"HELP", IDC_HELP},
+ {"IUP", IDC_HELP},
+ {"NO", IDC_NO},
+ {"UPARROW", IDC_UPARROW},
+ {"APPSTARTING", IDC_APPSTARTING}
+ };
+
+ HCURSOR cur;
+ char str[50];
+ int i, count = sizeof(table)/sizeof(table[0]);
+
+ /* check the cursor cache first (per control)*/
+ sprintf(str, "_IUPWIN_CURSOR_%s", name);
+ cur = (HCURSOR)iupAttribGet(ih, str);
+ if (cur)
+ return cur;
+
+ /* check the pre-defined IUP names first */
+ for (i = 0; i < count; i++)
+ {
+ if (iupStrEqualNoCase(name, table[i].iupname))
+ {
+ if (table[i].sysname)
+ cur = LoadCursor(NULL, table[i].sysname);
+ else
+ cur = NULL;
+
+ break;
+ }
+ }
+
+ if (i == count)
+ {
+ /* check other system cursors */
+ /* cursor PEN is handled here */
+ if (iupStrEqualNoCase(name, "PEN"))
+ name = "CURSOR_PEN";
+
+ /* check for an name defined cursor */
+ cur = iupImageGetCursor(name);
+ }
+
+ iupAttribSetStr(ih, str, (char*)cur);
+ return cur;
+}
+
+int iupdrvBaseSetCursorAttrib(Ihandle* ih, const char* value)
+{
+ /* Cursor can be NULL in Windows. */
+ HCURSOR hCur = winGetCursor(ih, value);
+ iupAttribSetStr(ih, "_IUPWIN_HCURSOR", (char*)hCur); /* To be used in WM_SETCURSOR */
+ /* refresh the cursor */
+ SendMessage(ih->handle, WM_SETCURSOR, (WPARAM)ih->handle, MAKELPARAM(1,WM_MOUSEMOVE));
+ return 1;
+}
+
+void iupdrvBaseRegisterCommonAttrib(Iclass* ic)
+{
+ iupClassRegisterAttribute(ic, "HFONT", iupwinGetHFontAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING);
+}
+
+int iupwinButtonDown(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp)
+{
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+ int ret, doubleclick = 0;
+ int b = 0;
+
+ IFniiiis cb = (IFniiiis) IupGetCallback(ih, "BUTTON_CB");
+ if (!cb)
+ return 0;
+
+ if (msg==WM_XBUTTONDBLCLK ||
+ msg==WM_LBUTTONDBLCLK ||
+ msg==WM_MBUTTONDBLCLK ||
+ msg==WM_RBUTTONDBLCLK)
+ doubleclick = 1;
+
+ iupwinButtonKeySetStatus(LOWORD(wp), status, doubleclick);
+
+ if (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONDBLCLK)
+ b = IUP_BUTTON1;
+ else if (msg==WM_MBUTTONDOWN || msg==WM_MBUTTONDBLCLK)
+ b = IUP_BUTTON2;
+ else if (msg==WM_RBUTTONDOWN || msg==WM_RBUTTONDBLCLK)
+ b = IUP_BUTTON3;
+ else if (msg==WM_XBUTTONDOWN || msg==WM_XBUTTONDBLCLK)
+ {
+ if (HIWORD(wp) == XBUTTON1)
+ b = IUP_BUTTON4;
+ else
+ b = IUP_BUTTON5;
+ }
+
+ ret = cb(ih, b, 1, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp), status);
+ if (ret == IUP_CLOSE)
+ IupExitLoop();
+ else if (ret == IUP_IGNORE)
+ return -1;
+
+ return 1;
+}
+
+int iupwinButtonUp(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp)
+{
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+ int ret, b=0;
+ IFniiiis cb = (IFniiiis) IupGetCallback(ih, "BUTTON_CB");
+ if (!cb)
+ return 0;
+
+ iupwinButtonKeySetStatus(LOWORD(wp), status, 0);
+
+ /* also updates the button status, since wp could not have the flag */
+ if (msg==WM_LBUTTONUP)
+ {
+ b = IUP_BUTTON1;
+ iupKEYSETBUTTON1(status);
+ }
+ else if (msg==WM_MBUTTONUP)
+ {
+ b = IUP_BUTTON2;
+ iupKEYSETBUTTON2(status);
+ }
+ else if (msg==WM_RBUTTONUP)
+ {
+ b = IUP_BUTTON3;
+ iupKEYSETBUTTON3(status);
+ }
+ else if (msg==WM_XBUTTONUP)
+ {
+ if (HIWORD(wp) == XBUTTON1)
+ {
+ b = IUP_BUTTON4;
+ iupKEYSETBUTTON4(status);
+ }
+ else
+ {
+ b = IUP_BUTTON5;
+ iupKEYSETBUTTON5(status);
+ }
+ }
+
+ ret = cb(ih, b, 0, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp), status);
+ if (ret == IUP_CLOSE)
+ IupExitLoop();
+ else if (ret == IUP_IGNORE)
+ return -1;
+
+ return 1;
+}
+
+int iupwinMouseMove(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp)
+{
+ IFniis cb = (IFniis)IupGetCallback(ih, "MOTION_CB");
+ if (cb)
+ {
+ char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT;
+ iupwinButtonKeySetStatus(LOWORD(wp), status, 0);
+ cb(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp), status);
+ return 1;
+ }
+ (void)msg;
+ return 0;
+}
+
+int iupwinCreateWindowEx(Ihandle* ih, LPCSTR lpClassName, DWORD dwExStyle, DWORD dwStyle)
+{
+ ih->serial = iupDialogGetChildId(ih);
+
+ ih->handle = CreateWindowEx(dwExStyle, /* extended window style */
+ lpClassName, /* window class */
+ NULL, /* title */
+ dwStyle, /* window style */
+ 0, /* x-position */
+ 0, /* y-position */
+ 10, /* default width to avoid 0 */
+ 10, /* default height to avoid 0 */
+ iupChildTreeGetNativeParentHandle(ih), /* window parent */
+ (HMENU)ih->serial, /* child identifier */
+ iupwin_hinstance, /* instance of app. */
+ NULL);
+
+ if (!ih->handle)
+ return 0;
+
+ /* associate HWND with Ihandle*, all Win32 controls must call this. */
+ iupwinHandleSet(ih);
+
+ /* replace the WinProc to handle base callbacks */
+ iupwinChangeProc(ih, iupwinBaseWinProc);
+
+ return 1;
+}
+
+char* iupwinGetClipboardText(Ihandle* ih)
+{
+ HANDLE Handle;
+ char* str;
+
+ if (!IsClipboardFormatAvailable(CF_TEXT))
+ return NULL;
+
+ if (!OpenClipboard(ih->handle))
+ return NULL;
+
+ Handle = GetClipboardData(CF_TEXT);
+ if (!Handle)
+ {
+ CloseClipboard();
+ return NULL;
+ }
+
+ str = (char*)GlobalLock(Handle);
+ str = iupStrDup(str);
+
+ GlobalUnlock(Handle);
+
+ CloseClipboard();
+
+ return str;
+}
diff --git a/iup/src/win/iupwin_dialog.c b/iup/src/win/iupwin_dialog.c
new file mode 100755
index 0000000..39fdc0c
--- /dev/null
+++ b/iup/src/win/iupwin_dialog.c
@@ -0,0 +1,1439 @@
+/** \file
+ * \brief IupDialog class
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_layout.h"
+#include "iup_dlglist.h"
+#include "iup_attrib.h"
+#include "iup_drv.h"
+#include "iup_drvinfo.h"
+#include "iup_drvfont.h"
+#include "iup_focus.h"
+#include "iup_str.h"
+#define _IUPDLG_PRIVATE
+#include "iup_dialog.h"
+#include "iup_image.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_brush.h"
+#include "iupwin_info.h"
+
+
+#define IWIN_TRAY_NOTIFICATION 102
+
+static int WM_HELPMSG;
+
+static int winDialogSetBgColorAttrib(Ihandle* ih, const char* value);
+static int winDialogSetTrayAttrib(Ihandle *ih, const char *value);
+
+/****************************************************************
+ Utilities
+****************************************************************/
+
+int iupdrvDialogIsVisible(Ihandle* ih)
+{
+ return iupdrvIsVisible(ih);
+}
+
+void iupdrvDialogUpdateSize(Ihandle* ih)
+{
+ RECT rect;
+ GetWindowRect(ih->handle, &rect);
+ ih->currentwidth = rect.right-rect.left;
+ ih->currentheight = rect.bottom-rect.top;
+}
+
+void iupdrvDialogGetSize(InativeHandle* handle, int *w, int *h)
+{
+ RECT rect;
+ GetWindowRect(handle, &rect);
+ if (w) *w = rect.right-rect.left;
+ if (h) *h = rect.bottom-rect.top;
+}
+
+void iupdrvDialogSetVisible(Ihandle* ih, int visible)
+{
+ ShowWindow(ih->handle, visible? ih->data->cmd_show: SW_HIDE);
+}
+
+void iupdrvDialogGetPosition(InativeHandle* handle, int *x, int *y)
+{
+ RECT rect;
+ GetWindowRect(handle, &rect);
+ if (x) *x = rect.left;
+ if (y) *y = rect.top;
+}
+
+void iupdrvDialogSetPosition(Ihandle *ih, int x, int y)
+{
+ /* Only moves the window and places it at the top of the Z order. */
+ SetWindowPos(ih->handle, HWND_TOP, x, y, 0, 0, SWP_NOSIZE);
+}
+
+void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu)
+{
+ if (ih->data->menu)
+ *menu = iupdrvMenuGetMenuBarSize(ih->data->menu);
+ else
+ *menu = 0;
+
+ if (ih->handle)
+ {
+ iupdrvGetWindowDecor(ih->handle, border, caption);
+
+ if (*menu)
+ *caption -= *menu;
+ }
+ else
+ {
+ int has_titlebar = iupAttribGetBoolean(ih, "MAXBOX") ||
+ iupAttribGetBoolean(ih, "MINBOX") ||
+ iupAttribGetBoolean(ih, "MENUBOX") ||
+ IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */
+
+ *caption = 0;
+ if (has_titlebar)
+ {
+ if (iupAttribGetBoolean(ih, "TOOLBOX") && iupAttribGet(ih, "PARENTDIALOG"))
+ *caption = GetSystemMetrics(SM_CYSMCAPTION); /* tool window */
+ else
+ *caption = GetSystemMetrics(SM_CYCAPTION); /* normal window */
+ }
+
+ *border = 0;
+ if (iupAttribGetBoolean(ih, "RESIZE"))
+ {
+ *border = GetSystemMetrics(SM_CXFRAME); /* Thickness of the sizing border around the perimeter of a window */
+ } /* that can be resized, in pixels. */
+ else if (has_titlebar)
+ {
+ *border = GetSystemMetrics(SM_CXFIXEDFRAME); /* Thickness of the frame around the perimeter of a window */
+ } /* that has a caption but is not sizable, in pixels. */
+ else if (iupAttribGetBoolean(ih, "BORDER"))
+ {
+ *border = GetSystemMetrics(SM_CXBORDER);
+ }
+ }
+}
+
+int iupdrvDialogSetPlacement(Ihandle* ih)
+{
+ char* placement;
+
+ ih->data->cmd_show = SW_SHOWNORMAL;
+ ih->data->show_state = IUP_SHOW;
+
+ if (iupAttribGetBoolean(ih, "FULLSCREEN"))
+ return 1;
+
+ placement = iupAttribGet(ih, "PLACEMENT");
+ if (!placement)
+ {
+ if (IsIconic(ih->handle) || IsZoomed(ih->handle))
+ ih->data->show_state = IUP_RESTORE;
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(placement, "MAXIMIZED"))
+ {
+ ih->data->cmd_show = SW_SHOWMAXIMIZED;
+ ih->data->show_state = IUP_MAXIMIZE;
+ }
+ else if (iupStrEqualNoCase(placement, "MINIMIZED"))
+ {
+ ih->data->cmd_show = SW_SHOWMINIMIZED;
+ ih->data->show_state = IUP_MINIMIZE;
+ }
+ else if (iupStrEqualNoCase(placement, "FULL"))
+ {
+ int width, height, x, y;
+ int caption, border, menu;
+ iupdrvDialogGetDecoration(ih, &border, &caption, &menu);
+
+ /* the dialog will cover the task bar */
+ iupdrvGetFullSize(&width, &height);
+
+ /* position the decoration and menu outside the screen */
+ x = -(border);
+ y = -(border+caption+menu);
+
+ width += 2*border;
+ height += 2*border + caption + menu;
+
+ /* set the new size and position */
+ /* WM_SIZE will update the layout */
+ SetWindowPos(ih->handle, HWND_TOP, x, y, width, height, 0);
+
+ if (IsIconic(ih->handle) || IsZoomed(ih->handle))
+ ih->data->show_state = IUP_RESTORE;
+ }
+
+ iupAttribSetStr(ih, "PLACEMENT", NULL); /* reset to NORMAL */
+
+ return 1;
+}
+
+static int winDialogMDICloseChildren(Ihandle* ih)
+{
+ Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE");
+ if (iupObjectCheck(client))
+ {
+ HWND hWndChild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0);
+
+ /* As long as the MDI client has a child, close it */
+ while (hWndChild)
+ {
+ Ihandle* child = iupwinHandleGet(hWndChild);
+ if (iupObjectCheck(child) && iupAttribGetBoolean(child, "MDICHILD"))
+ {
+ Icallback cb = IupGetCallback(child, "CLOSE_CB");
+ if (cb)
+ {
+ int ret = cb(child);
+ if (ret == IUP_IGNORE)
+ return 0;
+ if (ret == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ IupDestroy(child);
+ }
+
+ hWndChild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0);
+ }
+ }
+ return 1;
+}
+
+
+/****************************************************************************
+ WindowProc
+****************************************************************************/
+
+
+static Ihandle* winMinMaxHandle = NULL;
+
+static int winDialogCheckMinMaxInfo(Ihandle* ih, MINMAXINFO* minmax)
+{
+ int min_w = 1, min_h = 1; /* MINSIZE default value */
+ int max_w = 65535, max_h = 65535; /* MAXSIZE default value */
+
+ iupStrToIntInt(iupAttribGet(ih, "MINSIZE"), &min_w, &min_h, 'x');
+ iupStrToIntInt(iupAttribGet(ih, "MAXSIZE"), &max_w, &max_h, 'x');
+
+ minmax->ptMinTrackSize.x = min_w;
+ minmax->ptMinTrackSize.y = min_h;
+ minmax->ptMaxTrackSize.x = max_w;
+ minmax->ptMaxTrackSize.y = max_h;
+
+ if (winMinMaxHandle == ih)
+ winMinMaxHandle = NULL;
+
+ return 1;
+}
+
+static void winDialogResize(Ihandle* ih, int width, int height)
+{
+ IFnii cb;
+
+ iupdrvDialogUpdateSize(ih);
+
+ cb = (IFnii)IupGetCallback(ih, "RESIZE_CB");
+ if (!cb || cb(ih, width, height)!=IUP_IGNORE) /* width and height here are for the client area */
+ {
+ ih->data->ignore_resize = 1;
+ IupRefresh(ih);
+ ih->data->ignore_resize = 0;
+ }
+}
+
+static int winDialogBaseProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ if (iupwinBaseContainerProc(ih, msg, wp, lp, result))
+ return 1;
+
+ iupwinMenuDialogProc(ih, msg, wp, lp);
+
+ switch (msg)
+ {
+ case WM_GETMINMAXINFO:
+ {
+ if (winDialogCheckMinMaxInfo(ih, (MINMAXINFO*)lp))
+ {
+ *result = 0;
+ return 1;
+ }
+ break;
+ }
+ case WM_MOVE:
+ {
+ IFnii cb = (IFnii)IupGetCallback(ih, "MOVE_CB");
+ RECT rect;
+ GetWindowRect(ih->handle, &rect); /* ignore LPARAM because they are the clientpos and not X/Y */
+ if (cb) cb(ih, rect.left, rect.top);
+ break;
+ }
+ case WM_SIZE:
+ {
+ if (ih->data->ignore_resize)
+ break;
+
+ switch(wp)
+ {
+ case SIZE_MINIMIZED:
+ {
+ if (ih->data->show_state != IUP_MINIMIZE)
+ {
+ IFni show_cb = (IFni)IupGetCallback(ih, "SHOW_CB");
+ if (show_cb && show_cb(ih, IUP_MINIMIZE) == IUP_CLOSE)
+ IupExitLoop();
+ ih->data->show_state = IUP_MINIMIZE;
+ }
+ break;
+ }
+ case SIZE_MAXIMIZED:
+ {
+ if (ih->data->show_state != IUP_MAXIMIZE)
+ {
+ IFni show_cb = (IFni)IupGetCallback(ih, "SHOW_CB");
+ if (show_cb && show_cb(ih, IUP_MAXIMIZE) == IUP_CLOSE)
+ IupExitLoop();
+ ih->data->show_state = IUP_MAXIMIZE;
+ }
+
+ winDialogResize(ih, LOWORD(lp), HIWORD(lp));
+ break;
+ }
+ case SIZE_RESTORED:
+ {
+ if (ih->data->show_state == IUP_MAXIMIZE || ih->data->show_state == IUP_MINIMIZE)
+ {
+ IFni show_cb = (IFni)IupGetCallback(ih, "SHOW_CB");
+ if (show_cb && show_cb(ih, IUP_RESTORE) == IUP_CLOSE)
+ IupExitLoop();
+ ih->data->show_state = IUP_RESTORE;
+ }
+
+ winDialogResize(ih, LOWORD(lp), HIWORD(lp));
+ break;
+ }
+ }
+
+ break;
+ }
+ case WM_USER+IWIN_TRAY_NOTIFICATION:
+ {
+ int dclick = 0;
+ int button = 0;
+ int pressed = 0;
+
+ switch (lp)
+ {
+ case WM_LBUTTONDOWN:
+ pressed = 1;
+ button = 1;
+ break;
+ case WM_MBUTTONDOWN:
+ pressed = 1;
+ button = 2;
+ break;
+ case WM_RBUTTONDOWN:
+ pressed = 1;
+ button = 3;
+ break;
+ case WM_LBUTTONDBLCLK:
+ dclick = 1;
+ button = 1;
+ break;
+ case WM_MBUTTONDBLCLK:
+ dclick = 1;
+ button = 2;
+ break;
+ case WM_RBUTTONDBLCLK:
+ dclick = 1;
+ button = 3;
+ break;
+ case WM_LBUTTONUP:
+ button = 1;
+ break;
+ case WM_MBUTTONUP:
+ button = 2;
+ break;
+ case WM_RBUTTONUP:
+ button = 3;
+ break;
+ }
+
+ if (button != 0)
+ {
+ IFniii cb = (IFniii)IupGetCallback(ih, "TRAYCLICK_CB");
+ if (cb && cb(ih, button, pressed, dclick) == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ break;
+ }
+ case WM_CLOSE:
+ {
+ Icallback cb = IupGetCallback(ih, "CLOSE_CB");
+ if (cb)
+ {
+ int ret = cb(ih);
+ if (ret == IUP_IGNORE)
+ {
+ *result = 0;
+ return 1;
+ }
+ if (ret == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ /* child mdi is automatically destroyed */
+ if (iupAttribGetBoolean(ih, "MDICHILD"))
+ IupDestroy(ih);
+ else
+ {
+ if (!winDialogMDICloseChildren(ih))
+ {
+ *result = 0;
+ return 1;
+ }
+
+ IupHide(ih); /* IUP default processing */
+ }
+
+ *result = 0;
+ return 1;
+ }
+ case WM_SETCURSOR:
+ {
+ if (ih->handle == (HWND)wp && LOWORD(lp)==HTCLIENT)
+ {
+ HCURSOR hCur = (HCURSOR)iupAttribGet(ih, "_IUPWIN_HCURSOR");
+ if (hCur)
+ {
+ SetCursor(hCur);
+ *result = 1;
+ return 1;
+ }
+ else if (iupAttribGet(ih, "CURSOR"))
+ {
+ SetCursor(NULL);
+ *result = 1;
+ return 1;
+ }
+ }
+ break;
+ }
+ case WM_ERASEBKGND:
+ {
+ HBITMAP hBitmap = (HBITMAP)iupAttribGet(ih, "_IUPWIN_BACKGROUND_BITMAP");
+ if (hBitmap)
+ {
+ RECT rect;
+ HDC hdc = (HDC)wp;
+
+ HBRUSH hBrush = CreatePatternBrush(hBitmap);
+ GetClientRect(ih->handle, &rect);
+ FillRect(hdc, &rect, hBrush);
+ DeleteObject(hBrush);
+
+ /* return non zero value */
+ *result = 1;
+ return 1;
+ }
+ else
+ {
+ unsigned char r, g, b;
+ char* color = iupAttribGet(ih, "_IUPWIN_BACKGROUND_COLOR");
+ if (iupStrToRGB(color, &r, &g, &b))
+ {
+ RECT rect;
+ HDC hdc = (HDC)wp;
+
+ SetDCBrushColor(hdc, RGB(r,g,b));
+ GetClientRect(ih->handle, &rect);
+ FillRect(hdc, &rect, (HBRUSH)GetStockObject(DC_BRUSH));
+
+ /* return non zero value */
+ *result = 1;
+ return 1;
+ }
+ }
+ break;
+ }
+ case WM_DESTROY:
+ {
+ /* Since WM_CLOSE changed the Windows default processing */
+ /* WM_DESTROY is NOT received by IupDialogs */
+ /* Except when they are children of other IupDialogs and the parent is destroyed. */
+ /* So we have to destroy the child dialog. */
+ /* The application is responsable for destroying the children before this happen. */
+ IupDestroy(ih);
+ break;
+ }
+ }
+
+ if (msg == (UINT)WM_HELPMSG)
+ {
+ Ihandle* child = NULL;
+ DWORD* struct_ptr = (DWORD*)lp;
+ if (*struct_ptr == sizeof(CHOOSECOLOR))
+ {
+ CHOOSECOLOR* choosecolor = (CHOOSECOLOR*)lp;
+ child = (Ihandle*)choosecolor->lCustData;
+ }
+ if (*struct_ptr == sizeof(CHOOSEFONT))
+ {
+ CHOOSEFONT* choosefont = (CHOOSEFONT*)lp;
+ child = (Ihandle*)choosefont->lCustData;
+ }
+
+ if (child)
+ {
+ Icallback cb = IupGetCallback(child, "HELP_CB");
+ if (cb && cb(child) == IUP_CLOSE)
+ EndDialog((HWND)iupAttribGet(child, "HWND"), IDCANCEL);
+ }
+ }
+
+ return 0;
+}
+
+static LRESULT CALLBACK winDialogProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ LRESULT result;
+ Ihandle *ih = iupwinHandleGet(hwnd);
+ if (!ih)
+ {
+ /* the first time WM_GETMINMAXINFO is called, Ihandle is not associated yet */
+ if (msg == WM_GETMINMAXINFO && winMinMaxHandle)
+ {
+ if (winDialogCheckMinMaxInfo(winMinMaxHandle, (MINMAXINFO*)lp))
+ return 0;
+ }
+
+ return DefWindowProc(hwnd, msg, wp, lp);
+ }
+
+ if (winDialogBaseProc(ih, msg, wp, lp, &result))
+ return result;
+
+ return DefWindowProc(hwnd, msg, wp, lp);
+}
+
+static LRESULT CALLBACK winDialogMDIChildProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ LRESULT result;
+ Ihandle *ih = iupwinHandleGet(hwnd);
+ if (!ih)
+ {
+ /* the first time WM_GETMINMAXINFO is called, Ihandle is not associated yet */
+ if (msg == WM_GETMINMAXINFO && winMinMaxHandle)
+ {
+ if (winDialogCheckMinMaxInfo(winMinMaxHandle, (MINMAXINFO*)lp))
+ return 0;
+ }
+
+ return DefMDIChildProc(hwnd, msg, wp, lp);
+ }
+
+ switch (msg)
+ {
+ case WM_MDIACTIVATE:
+ {
+ HWND hNewActive = (HWND)lp;
+ if (hNewActive == ih->handle)
+ {
+ Icallback cb = (Icallback)IupGetCallback(ih, "MDIACTIVATE_CB");
+ if (cb) cb(ih);
+ }
+ break;
+ }
+ }
+
+ if (winDialogBaseProc(ih, msg, wp, lp, &result))
+ return result;
+
+ return DefMDIChildProc(hwnd, msg, wp, lp);
+}
+
+static Ihandle* winDialogGetMdiChildId(Ihandle* ih, int mdi_child_id)
+{
+ int id, max_child_id, real_id = -1;
+ char name[50];
+ Ihandle* child;
+
+ max_child_id = iupAttribGetInt(ih, "_IUPWIN_MAX_MDI_ID");
+
+ for (id = 0; id < max_child_id; id++)
+ {
+ sprintf(name, "_IUPWIN_MDI_ID_[%d]", id);
+ child = (Ihandle*)iupAttribGet(ih, name);
+ if (iupObjectCheck(child))
+ {
+ real_id++;
+ if (real_id == mdi_child_id)
+ return child;
+ }
+ }
+
+ return NULL;
+}
+
+static LRESULT CALLBACK winDialogMDIFrameProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ LRESULT result;
+ HWND hWndClient = NULL;
+ Ihandle *ih = iupwinHandleGet(hwnd);
+ if (!ih)
+ {
+ /* the first time WM_GETMINMAXINFO is called, Ihandle is not associated yet */
+ if (msg == WM_GETMINMAXINFO && winMinMaxHandle)
+ {
+ if (winDialogCheckMinMaxInfo(winMinMaxHandle, (MINMAXINFO*)lp))
+ return 0;
+ }
+
+ return DefFrameProc(hwnd, hWndClient, msg, wp, lp);
+ }
+
+ {
+ Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE");
+ if (client) hWndClient = client->handle;
+ }
+
+ if (winDialogBaseProc(ih, msg, wp, lp, &result))
+ return result;
+
+ switch (msg)
+ {
+ case WM_MENUCOMMAND:
+ {
+ int menuId = GetMenuItemID((HMENU)lp, (int)wp);
+ if (menuId >= IUP_MDICHILD_START && hWndClient)
+ {
+ Ihandle* child = winDialogGetMdiChildId(ih, menuId-IUP_MDICHILD_START);
+ if (child)
+ SendMessage(hWndClient, WM_MDIACTIVATE, (WPARAM)child->handle, 0);
+ break;
+ }
+ }
+ }
+
+
+ return DefFrameProc(hwnd, hWndClient, msg, wp, lp);
+}
+
+static void winDialogRegisterClass(int mdi)
+{
+ char* name;
+ WNDCLASS wndclass;
+ WNDPROC winproc;
+ ZeroMemory(&wndclass, sizeof(WNDCLASS));
+
+ if (mdi == 2)
+ {
+ name = "IupDialogMDIChild";
+ winproc = (WNDPROC)winDialogMDIChildProc;
+ }
+ else if (mdi == 1)
+ {
+ name = "IupDialogMDIFrame";
+ winproc = (WNDPROC)winDialogMDIFrameProc;
+ }
+ else
+ {
+ if (mdi == -1)
+ name = "IupDialogControl";
+ else
+ name = "IupDialog";
+ winproc = (WNDPROC)winDialogProc;
+ }
+
+ wndclass.hInstance = iupwin_hinstance;
+ wndclass.lpszClassName = name;
+ wndclass.lpfnWndProc = (WNDPROC)winproc;
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+
+ /* To use a standard system color, must increase the background-color value by one */
+ if (mdi == 1)
+ wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1);
+ else
+ wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
+
+ if (mdi == 0)
+ wndclass.style |= CS_SAVEBITS;
+
+ if (mdi == -1)
+ wndclass.style |= CS_HREDRAW | CS_VREDRAW;
+
+ RegisterClass(&wndclass);
+}
+
+
+/****************************************************************
+ dialog class functions
+****************************************************************/
+
+
+static int winDialogMapMethod(Ihandle* ih)
+{
+ InativeHandle* native_parent;
+ DWORD dwStyle = WS_CLIPSIBLINGS,
+ dwExStyle = 0;
+ int has_titlebar = 0,
+ has_border = 0;
+ char* classname = "IupDialog";
+
+ char* title = iupAttribGet(ih, "TITLE");
+ if (title)
+ has_titlebar = 1;
+
+ if (iupAttribGetBoolean(ih, "DIALOGFRAME"))
+ {
+ iupAttribSetStr(ih, "RESIZE", "NO");
+ iupAttribSetStr(ih, "MINBOX", "NO");
+ }
+
+ if (iupAttribGetBoolean(ih, "RESIZE"))
+ dwStyle |= WS_THICKFRAME;
+ else
+ iupAttribSetStr(ih, "MAXBOX", "NO"); /* Must also remove this to RESIZE=NO work */
+
+ if (iupAttribGetBoolean(ih, "MAXBOX"))
+ {
+ dwStyle |= WS_MAXIMIZEBOX;
+ has_titlebar = 1;
+ }
+
+ if (iupAttribGetBoolean(ih, "MINBOX"))
+ {
+ dwStyle |= WS_MINIMIZEBOX;
+ has_titlebar = 1;
+ }
+
+ if (iupAttribGetBoolean(ih, "MENUBOX"))
+ {
+ dwStyle |= WS_SYSMENU;
+ has_titlebar = 1;
+ }
+
+ if (iupAttribGetBoolean(ih, "BORDER") || has_titlebar)
+ has_border = 1;
+
+ if (iupAttribGetBoolean(ih, "MDICHILD"))
+ {
+ static int mdi_child_id = 0;
+ Ihandle *client;
+ char name[50];
+
+ /* must have a parent dialog (the mdi frame) */
+ Ihandle* parent = IupGetAttributeHandle(ih, "PARENTDIALOG");
+ if (!parent || !parent->handle)
+ return IUP_ERROR;
+
+ /* set when the mdi client is mapped */
+ client = (Ihandle*)iupAttribGet(parent, "MDICLIENT_HANDLE");
+ if (!client)
+ return IUP_ERROR;
+
+ /* store the mdi client handle in each mdi child also */
+ iupAttribSetStr(ih, "MDICLIENT_HANDLE", (char*)client);
+
+ sprintf(name, "_IUPWIN_MDI_ID_[%d]", mdi_child_id);
+ iupAttribSetStr(parent, name, (char*)ih);
+ mdi_child_id++;
+ iupAttribSetInt(parent, "_IUPWIN_MAX_MDI_ID", mdi_child_id);
+
+ classname = "IupDialogMDIChild";
+
+ /* The actual parent is the mdi client */
+ native_parent = client->handle;
+
+ dwStyle |= WS_CHILD;
+ if (has_titlebar)
+ dwStyle |= WS_CAPTION;
+ else if (has_border)
+ dwStyle |= WS_BORDER;
+
+ if (!IupGetName(ih))
+ iupAttribSetHandleName(ih);
+ }
+ else
+ {
+ native_parent = iupDialogGetNativeParent(ih);
+
+ if (native_parent)
+ {
+ dwStyle |= WS_POPUP;
+
+ if (has_titlebar)
+ dwStyle |= WS_CAPTION;
+ else if (has_border)
+ dwStyle |= WS_BORDER;
+ }
+ else
+ {
+ if (has_titlebar)
+ {
+ dwStyle |= WS_OVERLAPPED;
+ }
+ else
+ {
+ if (has_border)
+ dwStyle |= WS_POPUP | WS_BORDER;
+ else
+ dwStyle |= WS_POPUP;
+
+ dwExStyle |= WS_EX_NOACTIVATE; /* this will hide it from the taskbar */
+ }
+ }
+
+ if (iupAttribGet(ih, "MDIFRAME"))
+ classname = "IupDialogMDIFrame";
+ }
+
+ if (iupAttribGetBoolean(ih, "TOOLBOX") && native_parent)
+ dwExStyle |= WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE;
+
+ if (iupAttribGetBoolean(ih, "DIALOGFRAME") && native_parent)
+ dwExStyle |= WS_EX_DLGMODALFRAME; /* this will hide the MENUBOX but not the close button */
+
+ if (iupAttribGetBoolean(ih, "COMPOSITED"))
+ dwExStyle |= WS_EX_COMPOSITED;
+ else
+ dwStyle |= WS_CLIPCHILDREN;
+
+ if (iupAttribGetBoolean(ih, "HELPBUTTON"))
+ dwExStyle |= WS_EX_CONTEXTHELP;
+
+ if (iupAttribGetBoolean(ih, "CONTROL") && native_parent)
+ {
+ /* TODO: this were used by LuaCom to create embeded controls,
+ don't know if it is still working */
+ dwStyle = WS_CHILD | WS_TABSTOP | WS_CLIPCHILDREN;
+ classname = "IupDialogControl";
+ }
+
+ /* CreateWindowEx will send WM_GETMINMAXINFO before Ihandle is associated with HWND */
+ if (iupAttribGet(ih, "MINSIZE") || iupAttribGet(ih, "MAXSIZE"))
+ winMinMaxHandle = ih;
+
+ /* size will be updated in IupRefresh -> winDialogLayoutUpdate */
+ /* position will be updated in iupDialogShowXY */
+
+ if (iupAttribGetBoolean(ih, "MDICHILD"))
+ ih->handle = CreateMDIWindow(classname,
+ title, /* title */
+ dwStyle, /* style */
+ 0, /* x-position */
+ 0, /* y-position */
+ 100, /* horizontal size - set this to avoid size calculation problems */
+ 100, /* vertical size */
+ native_parent, /* owner window */
+ iupwin_hinstance, /* instance of app. */
+ 0); /* no creation parameters */
+ else
+ ih->handle = CreateWindowEx(dwExStyle, /* extended styles */
+ classname, /* class */
+ title, /* title */
+ dwStyle, /* style */
+ 0, /* x-position */
+ 0, /* y-position */
+ 100, /* horizontal size - set this to avoid size calculation problems */
+ 100, /* vertical size */
+ native_parent, /* owner window */
+ (HMENU)0, /* Menu or child-window identifier */
+ iupwin_hinstance, /* instance of app. */
+ NULL); /* no creation parameters */
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ /* associate HWND with Ihandle*, all Win32 controls must call this. */
+ iupwinHandleSet(ih);
+
+ if (iupStrEqual(classname, "IupDialogMDIChild")) /* hides the mdi child */
+ ShowWindow(ih->handle, SW_HIDE);
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ /* Reset attributes handled during creation that */
+ /* also can be changed later, and can be consulted from the native system. */
+ iupAttribSetStr(ih, "TITLE", NULL);
+ iupAttribSetStr(ih, "BORDER", NULL);
+
+ /* Ignore VISIBLE before mapping */
+ iupAttribSetStr(ih, "VISIBLE", NULL);
+
+ /* Set the default CmdShow for ShowWindow */
+ ih->data->cmd_show = SW_SHOWNORMAL;
+
+ return IUP_NOERROR;
+}
+
+static void winDialogUnMapMethod(Ihandle* ih)
+{
+ if (ih->data->menu)
+ {
+ ih->data->menu->handle = NULL; /* the dialog will destroy the native menu */
+ IupDestroy(ih->data->menu);
+ }
+
+ if (iupAttribGet(ih, "_IUPDLG_HASTRAY"))
+ winDialogSetTrayAttrib(ih, NULL);
+
+ /* remove the association before destroying */
+ iupwinHandleRemove(ih);
+
+ /* Destroys the window, so we can destroy the class */
+ if (iupAttribGetBoolean(ih, "MDICHILD"))
+ {
+ /* for MDICHILDs must send WM_MDIDESTROY, instead of calling DestroyWindow */
+ Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE");
+ SendMessage(client->handle, WM_MDIDESTROY, (WPARAM)ih->handle, 0);
+ }
+ else
+ DestroyWindow(ih->handle); /* this will destroy the Windows children also. */
+ /* but IupDestroy already destroyed the IUP children */
+ /* so it is safe to call DestroyWindow */
+}
+
+static void winDialogLayoutUpdateMethod(Ihandle *ih)
+{
+ if (ih->data->ignore_resize)
+ return;
+
+ ih->data->ignore_resize = 1;
+
+ /* for dialogs the position is not updated here */
+ SetWindowPos(ih->handle, 0, 0, 0, ih->currentwidth, ih->currentheight,
+ SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSENDCHANGING);
+
+ ih->data->ignore_resize = 0;
+}
+
+static void winDialogReleaseMethod(Iclass* ic)
+{
+ (void)ic;
+ if (iupwinClassExist("IupDialog"))
+ {
+ UnregisterClass("IupDialog", iupwin_hinstance);
+ UnregisterClass("IupDialogControl", iupwin_hinstance);
+ UnregisterClass("IupDialogMDIChild", iupwin_hinstance);
+ UnregisterClass("IupDialogMDIFrame", iupwin_hinstance);
+ }
+}
+
+
+
+/****************************************************************************
+ Attributes
+****************************************************************************/
+
+
+static int winDialogSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ iupAttribStoreStr(ih, "_IUPWIN_BACKGROUND_COLOR", value);
+ iupAttribSetStr(ih, "_IUPWIN_BACKGROUND_BITMAP", NULL);
+ RedrawWindow(ih->handle, NULL, NULL, RDW_ERASE|RDW_ERASENOW); /* force a WM_ERASEBKGND now */
+ return 1;
+ }
+ return 0;
+}
+
+static int winDialogSetBackgroundAttrib(Ihandle* ih, const char* value)
+{
+ if (winDialogSetBgColorAttrib(ih, value))
+ return 1;
+ else
+ {
+ HBITMAP hBitmap = iupImageGetImage(value, ih, 0);
+ if (hBitmap)
+ {
+ iupAttribSetStr(ih, "_IUPWIN_BACKGROUND_COLOR", NULL);
+ iupAttribSetStr(ih, "_IUPWIN_BACKGROUND_BITMAP", (char*)hBitmap);
+ RedrawWindow(ih->handle, NULL, NULL, RDW_ERASE|RDW_ERASENOW); /* force a WM_ERASEBKGND now */
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static HWND iupwin_mdifirst = NULL;
+static HWND iupwin_mdinext = NULL;
+
+static char* winDialogGetMdiActiveAttrib(Ihandle *ih)
+{
+ Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE");
+ if (client)
+ {
+ HWND hchild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0);
+ Ihandle* child = iupwinHandleGet(hchild);
+ if (child)
+ {
+ iupwin_mdinext = NULL;
+ iupwin_mdifirst = hchild;
+ return IupGetName(child);
+ }
+ }
+
+ iupwin_mdifirst = NULL;
+ iupwin_mdinext = NULL;
+ return NULL;
+}
+
+static char* winDialogGetMdiNextAttrib(Ihandle *ih)
+{
+ Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE");
+ if (client)
+ {
+ Ihandle* child;
+ HWND hchild = iupwin_mdinext? iupwin_mdinext: iupwin_mdifirst;
+
+ /* Skip the icon title windows */
+ while (hchild && GetWindow (hchild, GW_OWNER))
+ hchild = GetWindow(hchild, GW_HWNDNEXT);
+
+ if (!hchild || hchild == iupwin_mdifirst)
+ {
+ iupwin_mdinext = NULL;
+ return NULL;
+ }
+
+ child = iupwinHandleGet(hchild);
+ if (child)
+ {
+ iupwin_mdinext = hchild;
+ return IupGetName(child);
+ }
+ }
+
+ iupwin_mdinext = NULL;
+ return NULL;
+}
+
+/* define this here, so we do not need to define _WIN32_WINNT=0x0500 */
+#ifndef WS_EX_LAYERED
+#define WS_EX_LAYERED 0x00080000
+#endif
+
+#ifndef LWA_ALPHA
+#define LWA_ALPHA 0x00000002
+#endif
+
+typedef BOOL (WINAPI*winSetLayeredWindowAttributes)(
+ HWND hwnd,
+ COLORREF crKey,
+ BYTE bAlpha,
+ DWORD dwFlags);
+
+static int winDialogSetOpacityAttrib(Ihandle *ih, const char *value)
+{
+ DWORD dwExStyle = GetWindowLong(ih->handle, GWL_EXSTYLE);
+ if (!value)
+ {
+ if (dwExStyle & WS_EX_LAYERED)
+ {
+ dwExStyle &= ~WS_EX_LAYERED; /* remove the style */
+ SetWindowLong(ih->handle, GWL_EXSTYLE, dwExStyle);
+ RedrawWindow(ih->handle, NULL, NULL, RDW_ERASE|RDW_INVALIDATE|RDW_FRAME|RDW_ALLCHILDREN); /* invalidate everything and all children */
+ }
+ return 0;
+ }
+
+ if (!(dwExStyle & WS_EX_LAYERED))
+ {
+ dwExStyle |= WS_EX_LAYERED; /* add the style */
+ SetWindowLong(ih->handle, GWL_EXSTYLE, dwExStyle);
+ }
+
+ {
+ static winSetLayeredWindowAttributes mySetLayeredWindowAttributes = NULL;
+
+ int opacity;
+ if (!iupStrToInt(value, &opacity))
+ return 0;
+
+ if (!mySetLayeredWindowAttributes)
+ {
+ HMODULE hinstDll = LoadLibrary("user32.dll");
+ if (hinstDll)
+ mySetLayeredWindowAttributes = (winSetLayeredWindowAttributes)GetProcAddress(hinstDll, "SetLayeredWindowAttributes");
+ }
+
+ if (mySetLayeredWindowAttributes)
+ mySetLayeredWindowAttributes(ih->handle, 0, (BYTE)opacity, LWA_ALPHA);
+ }
+
+ RedrawWindow(ih->handle, NULL, NULL, RDW_ERASE|RDW_INVALIDATE|RDW_FRAME|RDW_ALLCHILDREN); /* invalidate everything and all children */
+ return 1;
+}
+
+static int winDialogSetMdiArrangeAttrib(Ihandle *ih, const char *value)
+{
+ Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE");
+ if (client)
+ {
+ UINT msg = 0;
+ WPARAM wp = 0;
+
+ if (iupStrEqualNoCase(value, "TILEHORIZONTAL"))
+ {
+ msg = WM_MDITILE;
+ wp = MDITILE_HORIZONTAL;
+ }
+ else if (iupStrEqualNoCase(value, "TILEVERTICAL"))
+ {
+ msg = WM_MDITILE;
+ wp = MDITILE_VERTICAL;
+ }
+ else if (iupStrEqualNoCase(value, "CASCADE"))
+ msg = WM_MDICASCADE;
+ else if (iupStrEqualNoCase(value, "ICON"))
+ msg = WM_MDIICONARRANGE;
+
+ if (msg)
+ SendMessage(client->handle, msg, wp, 0);
+ }
+ return 0;
+}
+
+static int winDialogSetMdiActivateAttrib(Ihandle *ih, const char *value)
+{
+ Ihandle* client = (Ihandle*)iupAttribGet(ih, "MDICLIENT_HANDLE");
+ if (client)
+ {
+ Ihandle* child = IupGetHandle(value);
+ if (child)
+ SendMessage(client->handle, WM_MDIACTIVATE, (WPARAM)child->handle, 0);
+ else
+ {
+ HWND hchild = (HWND)SendMessage(client->handle, WM_MDIGETACTIVE, 0, 0);
+ if (iupStrEqualNoCase(value, "NEXT"))
+ SendMessage(client->handle, WM_MDINEXT, (WPARAM)hchild, TRUE);
+ else if (iupStrEqualNoCase(value, "PREVIOUS"))
+ SendMessage(client->handle, WM_MDINEXT, (WPARAM)hchild, FALSE);
+ }
+ }
+ return 0;
+}
+
+static int winDialogSetMdiCloseAllAttrib(Ihandle *ih, const char *value)
+{
+ (void)value;
+ winDialogMDICloseChildren(ih);
+ return 0;
+}
+
+static void winDialogTrayMessage(HWND hWnd, DWORD dwMessage, HICON hIcon, PSTR pszTip)
+{
+ NOTIFYICONDATA tnd;
+ memset(&tnd, 0, sizeof(NOTIFYICONDATA));
+
+ tnd.cbSize = sizeof(NOTIFYICONDATA);
+ tnd.hWnd = hWnd;
+ tnd.uID = 1000;
+
+ if (dwMessage == NIM_ADD)
+ {
+ tnd.uFlags = NIF_MESSAGE;
+ tnd.uCallbackMessage = WM_USER+IWIN_TRAY_NOTIFICATION;
+ }
+ else if (dwMessage == NIM_MODIFY)
+ {
+ if (hIcon)
+ {
+ tnd.uFlags |= NIF_ICON;
+ tnd.hIcon = hIcon;
+ }
+
+ if (pszTip)
+ {
+ tnd.uFlags |= NIF_TIP;
+ lstrcpyn(tnd.szTip, pszTip, sizeof(tnd.szTip));
+ }
+ }
+
+ Shell_NotifyIcon(dwMessage, &tnd);
+}
+
+static int winDialogCheckTray(Ihandle *ih)
+{
+ if (iupAttribGet(ih, "_IUPDLG_HASTRAY"))
+ return 1;
+
+ if (iupAttribGetBoolean(ih, "TRAY"))
+ {
+ winDialogTrayMessage(ih->handle, NIM_ADD, NULL, NULL);
+ iupAttribSetStr(ih, "_IUPDLG_HASTRAY", "YES");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int winDialogSetTrayAttrib(Ihandle *ih, const char *value)
+{
+ int tray = iupStrBoolean(value);
+ if (iupAttribGet(ih, "_IUPDLG_HASTRAY"))
+ {
+ if (!tray)
+ {
+ winDialogTrayMessage(ih->handle, NIM_DELETE, NULL, NULL);
+ iupAttribSetStr(ih, "_IUPDLG_HASTRAY", NULL);
+ }
+ }
+ else
+ {
+ if (tray)
+ {
+ winDialogTrayMessage(ih->handle, NIM_ADD, NULL, NULL);
+ iupAttribSetStr(ih, "_IUPDLG_HASTRAY", "YES");
+ }
+ }
+ return 1;
+}
+
+static int winDialogSetTrayTipAttrib(Ihandle *ih, const char *value)
+{
+ if (winDialogCheckTray(ih))
+ winDialogTrayMessage(ih->handle, NIM_MODIFY, NULL, (PSTR)value);
+ return 1;
+}
+
+static int winDialogSetTrayImageAttrib(Ihandle *ih, const char *value)
+{
+ if (winDialogCheckTray(ih))
+ {
+ HICON hIcon = (HICON)iupImageGetIcon(value);
+ if (hIcon)
+ winDialogTrayMessage(ih->handle, NIM_MODIFY, hIcon, NULL);
+ }
+ return 1;
+}
+
+static int winDialogSetBringFrontAttrib(Ihandle *ih, const char *value)
+{
+ if (iupStrBoolean(value))
+ SetForegroundWindow(ih->handle);
+ return 0;
+}
+
+static int winDialogSetTopMostAttrib(Ihandle *ih, const char *value)
+{
+ if (iupStrBoolean(value))
+ SetWindowPos(ih->handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
+ else
+ SetWindowPos(ih->handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
+ return 1;
+}
+
+static int winDialogSetIconAttrib(Ihandle* ih, const char *value)
+{
+ if (!value)
+ SendMessage(ih->handle, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)NULL);
+ else
+ {
+ HICON icon = iupImageGetIcon(value);
+ if (icon)
+ SendMessage(ih->handle, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM)icon);
+ }
+
+ if (IsIconic(ih->handle))
+ RedrawWindow(ih->handle, NULL, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW); /* redraw the icon */
+ else
+ RedrawWindow(ih->handle, NULL, NULL, RDW_FRAME|RDW_UPDATENOW); /* only the frame needs to be redrawn */
+
+ return 1;
+}
+
+static int winDialogSetFullScreenAttrib(Ihandle* ih, const char* value)
+{
+ if (iupStrBoolean(value))
+ {
+ if (!iupAttribGet(ih, "_IUPWIN_FS_STYLE"))
+ {
+ int width, height;
+ LONG off_style, new_style;
+
+ BOOL visible = ShowWindow (ih->handle, SW_HIDE);
+
+ /* remove the decorations */
+ off_style = WS_BORDER | WS_THICKFRAME | WS_CAPTION |
+ WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU;
+ new_style = GetWindowLong(ih->handle, GWL_STYLE);
+ iupAttribSetStr(ih, "_IUPWIN_FS_STYLE", (char*)new_style);
+ new_style &= (~off_style);
+ SetWindowLong(ih->handle, GWL_STYLE, new_style);
+
+ /* save the previous decoration attributes */
+ iupAttribStoreStr(ih, "_IUPWIN_FS_MAXBOX", iupAttribGet(ih, "MAXBOX"));
+ iupAttribStoreStr(ih, "_IUPWIN_FS_MINBOX", iupAttribGet(ih, "MINBOX"));
+ iupAttribStoreStr(ih, "_IUPWIN_FS_MENUBOX",iupAttribGet(ih, "MENUBOX"));
+ iupAttribStoreStr(ih, "_IUPWIN_FS_RESIZE", iupAttribGet(ih, "RESIZE"));
+ iupAttribStoreStr(ih, "_IUPWIN_FS_BORDER", iupAttribGet(ih, "BORDER"));
+ iupAttribStoreStr(ih, "_IUPWIN_FS_TITLE", IupGetAttribute(ih, "TITLE")); /* must use IupGetAttribute to check from the native implementation */
+
+ /* save the previous position and size */
+ iupAttribStoreStr(ih, "_IUPWIN_FS_X", IupGetAttribute(ih, "X")); /* must use IupGetAttribute to check from the native implementation */
+ iupAttribStoreStr(ih, "_IUPWIN_FS_Y", IupGetAttribute(ih, "Y"));
+ iupAttribStoreStr(ih, "_IUPWIN_FS_SIZE", IupGetAttribute(ih, "RASTERSIZE"));
+
+ /* remove the decorations attributes */
+ iupAttribSetStr(ih, "MAXBOX", "NO");
+ iupAttribSetStr(ih, "MINBOX", "NO");
+ iupAttribSetStr(ih, "MENUBOX", "NO");
+ IupSetAttribute(ih, "TITLE", NULL);
+ iupAttribSetStr(ih, "RESIZE", "NO");
+ iupAttribSetStr(ih, "BORDER", "NO");
+
+ /* full screen size */
+ iupdrvGetFullSize(&width, &height);
+
+ SetWindowPos(ih->handle, HWND_TOP, 0, 0, width, height, SWP_FRAMECHANGED);
+
+ /* layout will be updated in WM_SIZE */
+ if (visible)
+ ShowWindow(ih->handle, SW_SHOW);
+ }
+ }
+ else
+ {
+ LONG style = (LONG)iupAttribGet(ih, "_IUPWIN_FS_STYLE");
+ if (style)
+ {
+ BOOL visible = ShowWindow(ih->handle, SW_HIDE);
+
+ /* restore the decorations attributes */
+ iupAttribStoreStr(ih, "MAXBOX", iupAttribGet(ih, "_IUPWIN_FS_MAXBOX"));
+ iupAttribStoreStr(ih, "MINBOX", iupAttribGet(ih, "_IUPWIN_FS_MINBOX"));
+ iupAttribStoreStr(ih, "MENUBOX",iupAttribGet(ih, "_IUPWIN_FS_MENUBOX"));
+ IupSetAttribute(ih, "TITLE", iupAttribGet(ih, "_IUPWIN_FS_TITLE")); /* TITLE is not stored in the HashTable */
+ iupAttribStoreStr(ih, "RESIZE", iupAttribGet(ih, "_IUPWIN_FS_RESIZE"));
+ iupAttribStoreStr(ih, "BORDER", iupAttribGet(ih, "_IUPWIN_FS_BORDER"));
+
+ /* restore the decorations */
+ SetWindowLong(ih->handle, GWL_STYLE, style);
+
+ /* restore position and size */
+ SetWindowPos(ih->handle, HWND_TOP,
+ iupAttribGetInt(ih, "_IUPWIN_FS_X"),
+ iupAttribGetInt(ih, "_IUPWIN_FS_Y"),
+ IupGetInt(ih, "_IUPWIN_FS_SIZE"),
+ IupGetInt2(ih, "_IUPWIN_FS_SIZE"), 0);
+
+ /* layout will be updated in WM_SIZE */
+ if (visible)
+ ShowWindow(ih->handle, SW_SHOW);
+
+ /* remove auxiliar attributes */
+ iupAttribSetStr(ih, "_IUPWIN_FS_MAXBOX", NULL);
+ iupAttribSetStr(ih, "_IUPWIN_FS_MINBOX", NULL);
+ iupAttribSetStr(ih, "_IUPWIN_FS_MENUBOX",NULL);
+ iupAttribSetStr(ih, "_IUPWIN_FS_TITLE", NULL);
+ iupAttribSetStr(ih, "_IUPWIN_FS_RESIZE", NULL);
+ iupAttribSetStr(ih, "_IUPWIN_FS_BORDER", NULL);
+
+ iupAttribSetStr(ih, "_IUPWIN_FS_X", NULL);
+ iupAttribSetStr(ih, "_IUPWIN_FS_Y", NULL);
+ iupAttribSetStr(ih, "_IUPWIN_FS_SIZE", NULL);
+
+ iupAttribSetStr(ih, "_IUPWIN_FS_STYLE", NULL);
+ }
+ }
+ return 1;
+}
+
+
+void iupdrvDialogInitClass(Iclass* ic)
+{
+ if (!iupwinClassExist("IupDialog"))
+ {
+ winDialogRegisterClass(0);
+ winDialogRegisterClass(1);
+ winDialogRegisterClass(2);
+ winDialogRegisterClass(-1);
+
+ WM_HELPMSG = RegisterWindowMessage(HELPMSGSTRING);
+ }
+
+ /* Driver Dependent Class functions */
+ ic->Map = winDialogMapMethod;
+ ic->UnMap = winDialogUnMapMethod;
+ ic->LayoutUpdate = winDialogLayoutUpdateMethod;
+ ic->Release = winDialogReleaseMethod;
+
+ /* Callback Windows Only*/
+ iupClassRegisterCallback(ic, "MDIACTIVATE_CB", "");
+
+ /* Callback Windows and GTK Only */
+ iupClassRegisterCallback(ic, "TRAYCLICK_CB", "iii");
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winDialogSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, iupdrvBaseSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* Base Container */
+ iupClassRegisterAttribute(ic, "CLIENTSIZE", iupdrvBaseGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT);
+
+ /* IupDialog only */
+ iupClassRegisterAttribute(ic, "BACKGROUND", NULL, winDialogSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ICON", NULL, winDialogSetIconAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FULLSCREEN", NULL, winDialogSetFullScreenAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SAVEUNDER", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MINSIZE", NULL, NULL, IUPAF_SAMEASSYSTEM, "1x1", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MAXSIZE", NULL, NULL, IUPAF_SAMEASSYSTEM, "65535x65535", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+
+ /* IupDialog Windows Only */
+ iupClassRegisterAttribute(ic, "HWND", iupBaseGetWidAttrib, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDIARRANGE", NULL, winDialogSetMdiArrangeAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDIACTIVATE", NULL, winDialogSetMdiActivateAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDICLOSEALL", NULL, winDialogSetMdiCloseAllAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDIACTIVE", winDialogGetMdiActiveAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDINEXT", winDialogGetMdiNextAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "OPACITY", NULL, winDialogSetOpacityAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "LAYERALPHA", NULL, winDialogSetOpacityAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "BRINGFRONT", NULL, winDialogSetBringFrontAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "COMPOSITED", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED);
+
+ iupClassRegisterAttribute(ic, "CONTROL", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "HELPBUTTON", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TOOLBOX", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDIFRAME", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDICLIENT", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDIMENU", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MDICHILD", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+
+ /* IupDialog Windows and GTK Only */
+ iupClassRegisterAttribute(ic, "TOPMOST", NULL, winDialogSetTopMostAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TRAY", NULL, winDialogSetTrayAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TRAYIMAGE", NULL, winDialogSetTrayImageAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TRAYTIP", NULL, winDialogSetTrayTipAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_draw.c b/iup/src/win/iupwin_draw.c
new file mode 100755
index 0000000..4a810e6
--- /dev/null
+++ b/iup/src/win/iupwin_draw.c
@@ -0,0 +1,328 @@
+/** \file
+ * \brief Draw Functions
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#include <windows.h>
+#include <uxtheme.h>
+#include <tmschema.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+
+#include "iup.h"
+
+#include "iup_attrib.h"
+#include "iup_class.h"
+#include "iup_str.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_info.h"
+#include "iupwin_draw.h"
+
+
+#ifndef TABP_AEROWIZARDBODY
+#define TABP_AEROWIZARDBODY 11 /* manually added definition */
+#endif
+
+#ifndef TMT_FILLCOLORHINT
+#define TMT_FILLCOLORHINT 3821
+#endif
+#ifndef TMT_TEXTCOLOR
+#define TMT_TEXTCOLOR 3823
+#endif
+
+
+typedef HTHEME (STDAPICALLTYPE *_winThemeOpenData)(HWND hwnd, LPCWSTR pszClassList);
+typedef HRESULT (STDAPICALLTYPE *_winThemeCloseData)(HTHEME hTheme);
+typedef HRESULT (STDAPICALLTYPE *_winThemeDrawBackground)(HTHEME hTheme, HDC hDC, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect);
+typedef HRESULT (STDAPICALLTYPE *_winThemeGetColor)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, COLORREF *pColor);
+
+static _winThemeOpenData winThemeOpenData = NULL;
+static _winThemeCloseData winThemeCloseData = NULL;
+static _winThemeDrawBackground winThemeDrawBackground = NULL;
+static _winThemeGetColor winThemeGetColor = NULL;
+
+typedef BOOL (CALLBACK* _winAlphaBlendFunc)( HDC hdcDest,
+ int xoriginDest, int yoriginDest,
+ int wDest, int hDest, HDC hdcSrc,
+ int xoriginSrc, int yoriginSrc,
+ int wSrc, int hSrc,
+ BLENDFUNCTION ftn);
+static _winAlphaBlendFunc winAlphaBlend = NULL;
+
+static int winDrawThemeEnabled(void)
+{
+ return winThemeOpenData? 1: 0;
+}
+
+void iupwinDrawText(HDC hDC, const char* text, int x, int y, int width, int height, HFONT hFont, COLORREF fgcolor, int style)
+{
+ COLORREF oldcolor;
+ RECT rect;
+ HFONT hOldFont = SelectObject(hDC, hFont);
+
+ rect.left = x;
+ rect.top = y;
+ rect.right = x+width;
+ rect.bottom = y+height;
+
+ SetTextAlign(hDC, TA_TOP|TA_LEFT);
+ SetBkMode(hDC, TRANSPARENT);
+ oldcolor = SetTextColor(hDC, fgcolor);
+
+ DrawText(hDC, text, -1, &rect, style|DT_NOCLIP);
+
+ SelectObject(hDC, hOldFont);
+ SetTextColor(hDC, oldcolor);
+ SetBkMode(hDC, OPAQUE);
+}
+
+void iupwinDrawBitmap(HDC hDC, HBITMAP hBitmap, HBITMAP hMask, int x, int y, int width, int height, int bpp)
+{
+ HDC hMemDC = CreateCompatibleDC(hDC);
+ SelectObject(hMemDC, hBitmap);
+
+ if (bpp == 32 && winAlphaBlend)
+ {
+ BLENDFUNCTION blendfunc;
+ blendfunc.BlendOp = AC_SRC_OVER;
+ blendfunc.BlendFlags = 0;
+ blendfunc.SourceConstantAlpha = 0xFF;
+ blendfunc.AlphaFormat = AC_SRC_ALPHA;
+
+ winAlphaBlend(hDC, x, y, width, height,
+ hMemDC, 0, 0, width, height,
+ blendfunc);
+ }
+ else if (bpp == 8 && hMask)
+ MaskBlt(hDC, x, y, width, height,
+ hMemDC, 0, 0,
+ hMask, 0, 0, MAKEROP4(SRCCOPY, 0xAA0000));
+ else
+ BitBlt(hDC, x, y, width, height,
+ hMemDC, 0, 0,
+ SRCCOPY);
+
+
+ DeleteDC(hMemDC);
+}
+
+void iupwinDrawInit(void)
+{
+ if (!winAlphaBlend)
+ {
+ HINSTANCE lib = LoadLibrary("Msimg32");
+ if (lib)
+ winAlphaBlend = (_winAlphaBlendFunc)GetProcAddress(lib, "AlphaBlend");
+ }
+
+ if (!winThemeOpenData && iupwin_comctl32ver6)
+ {
+ HMODULE hinstDll = LoadLibrary("uxtheme.dll");
+ if (hinstDll)
+ {
+ winThemeOpenData = (_winThemeOpenData)GetProcAddress(hinstDll, "OpenThemeData");
+ winThemeCloseData = (_winThemeCloseData)GetProcAddress(hinstDll, "CloseThemeData");
+ winThemeDrawBackground = (_winThemeDrawBackground)GetProcAddress(hinstDll, "DrawThemeBackground");
+ winThemeGetColor = (_winThemeGetColor)GetProcAddress(hinstDll, "GetThemeColor");
+ }
+ }
+}
+
+static int winDrawGetThemeStateId(int itemState)
+{
+ if (itemState & ODS_DISABLED)
+ return PBS_DISABLED;
+ else if (itemState & ODS_SELECTED)
+ return PBS_PRESSED;
+ else if (itemState & ODS_HOTLIGHT)
+ return PBS_HOT;
+ else if (itemState & ODS_DEFAULT)
+ return PBS_DEFAULTED;
+ else
+ return PBS_NORMAL;
+}
+
+static int winDrawThemeButtonBorder(HWND hWnd, HDC hDC, RECT *rect, UINT itemState)
+{
+ int iStateId;
+ HTHEME hTheme;
+
+ if (!winDrawThemeEnabled())
+ return 0;
+
+ hTheme = winThemeOpenData(hWnd, L"BUTTON");
+ if (!hTheme)
+ return 0;
+
+ iStateId = winDrawGetThemeStateId(itemState);
+
+ winThemeDrawBackground(hTheme, hDC, BP_PUSHBUTTON, iStateId, rect, NULL);
+
+ winThemeCloseData(hTheme);
+ return 1;
+}
+
+void iupwinDrawThemeFrameBorder(HWND hWnd, HDC hDC, RECT *rect, UINT itemState)
+{
+ int iStateId = GBS_NORMAL;
+ HTHEME hTheme;
+
+ if (!winDrawThemeEnabled())
+ return;
+
+ hTheme = winThemeOpenData(hWnd, L"BUTTON");
+ if (!hTheme)
+ return;
+
+ if (itemState & ODS_DISABLED)
+ iStateId = GBS_DISABLED;
+
+ winThemeDrawBackground(hTheme, hDC, BP_GROUPBOX, iStateId, rect, NULL);
+
+ winThemeCloseData(hTheme);
+}
+
+int iupwinDrawGetThemeTabsBgColor(HWND hWnd, COLORREF *color)
+{
+ HTHEME hTheme;
+ HRESULT ret;
+
+ if (!winDrawThemeEnabled())
+ return 0;
+
+ hTheme = winThemeOpenData(hWnd, L"TAB");
+ if (!hTheme)
+ return 0;
+
+ if (iupwinIsVista())
+ ret = winThemeGetColor(hTheme, TABP_AEROWIZARDBODY, TIS_NORMAL, TMT_FILLCOLORHINT, color);
+ else
+ ret = winThemeGetColor(hTheme, TABP_BODY, TIS_NORMAL, TMT_FILLCOLORHINT, color);
+
+ winThemeCloseData(hTheme);
+ return (ret == S_OK)? 1: 0;
+}
+
+int iupwinDrawGetThemeButtonBgColor(HWND hWnd, COLORREF *color)
+{
+ HTHEME hTheme;
+ HRESULT ret;
+
+ if (!winDrawThemeEnabled())
+ return 0;
+
+ hTheme = winThemeOpenData(hWnd, L"BUTTON");
+ if (!hTheme)
+ return 0;
+
+ ret = winThemeGetColor(hTheme, BP_PUSHBUTTON, PBS_NORMAL, TMT_FILLCOLORHINT, color);
+
+ winThemeCloseData(hTheme);
+ return (ret == S_OK)? 1: 0;
+}
+
+int iupwinDrawGetThemeFrameFgColor(HWND hWnd, COLORREF *color)
+{
+ HTHEME hTheme;
+ HRESULT ret;
+
+ if (!winDrawThemeEnabled())
+ return 0;
+
+ hTheme = winThemeOpenData(hWnd, L"BUTTON");
+ if (!hTheme)
+ return 0;
+
+ ret = winThemeGetColor(hTheme, BP_GROUPBOX, GBS_NORMAL, TMT_TEXTCOLOR, color);
+
+ winThemeCloseData(hTheme);
+ return (ret == S_OK)? 1: 0;
+}
+
+static int winDrawGetStateId(int itemState)
+{
+ if (itemState & ODS_DISABLED)
+ return DFCS_INACTIVE;
+ else if (itemState & ODS_SELECTED)
+ return DFCS_PUSHED;
+ else if (itemState & ODS_HOTLIGHT)
+ return DFCS_HOT;
+ else
+ return 0;
+}
+
+void iupwinDrawButtonBorder(HWND hWnd, HDC hDC, RECT *rect, UINT itemState)
+{
+ if (!winDrawThemeButtonBorder(hWnd, hDC, rect, itemState))
+ {
+ DrawFrameControl(hDC, rect, DFC_BUTTON, DFCS_BUTTONPUSH | winDrawGetStateId(itemState));
+ if (itemState & ODS_DEFAULT) /* if a button has the focus, must draw the default button frame */
+ FrameRect(hDC, rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
+ }
+}
+
+void iupdrvDrawFocusRect(Ihandle* ih, void* gc, int x, int y, int w, int h)
+{
+ HDC hDC = (HDC)gc;
+ RECT rect;
+ (void)ih;
+
+ rect.left = x;
+ rect.top = y;
+ rect.right = x+w;
+ rect.bottom = y+h;
+
+ DrawFocusRect(hDC, &rect);
+}
+
+void iupwinDrawRemoveTheme(HWND hwnd)
+{
+ typedef HRESULT (STDAPICALLTYPE *winSetWindowTheme)(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList);
+ static winSetWindowTheme mySetWindowTheme = NULL;
+ if (!mySetWindowTheme)
+ {
+ HMODULE hinstDll = LoadLibrary("uxtheme.dll");
+ if (hinstDll)
+ mySetWindowTheme = (winSetWindowTheme)GetProcAddress(hinstDll, "SetWindowTheme");
+ }
+
+ if (mySetWindowTheme)
+ mySetWindowTheme(hwnd, L"", L"");
+}
+
+void iupwinDrawParentBackground(Ihandle* ih, HDC hDC, RECT* rect)
+{
+ unsigned char r=0, g=0, b=0;
+ char* color = iupBaseNativeParentGetBgColorAttrib(ih);
+ iupStrToRGB(color, &r, &g, &b);
+ SetDCBrushColor(hDC, RGB(r,g,b));
+ FillRect(hDC, rect, (HBRUSH)GetStockObject(DC_BRUSH));
+}
+
+HDC iupwinDrawCreateBitmapDC(iupwinBitmapDC *bmpDC, HDC hDC, int w, int h)
+{
+ bmpDC->w = w;
+ bmpDC->h = h;
+ bmpDC->hDC = hDC;
+
+ bmpDC->hBitmap = CreateCompatibleBitmap(bmpDC->hDC, w, h);
+ bmpDC->hBitmapDC = CreateCompatibleDC(bmpDC->hDC);
+ bmpDC->hOldBitmap = SelectObject(bmpDC->hBitmapDC, bmpDC->hBitmap);
+ return bmpDC->hBitmapDC;
+}
+
+void iupwinDrawDestroyBitmapDC(iupwinBitmapDC *bmpDC)
+{
+ BitBlt(bmpDC->hDC, 0, 0, bmpDC->w, bmpDC->h, bmpDC->hBitmapDC, 0, 0, SRCCOPY);
+ SelectObject(bmpDC->hBitmapDC, bmpDC->hOldBitmap);
+ DeleteObject(bmpDC->hBitmap);
+ DeleteDC(bmpDC->hBitmapDC);
+}
+
diff --git a/iup/src/win/iupwin_draw.h b/iup/src/win/iupwin_draw.h
new file mode 100755
index 0000000..c9a57e6
--- /dev/null
+++ b/iup/src/win/iupwin_draw.h
@@ -0,0 +1,47 @@
+/** \file
+ * \brief Draw Functions
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUPWIN_DRAW_H
+#define __IUPWIN_DRAW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void iupwinDrawInit(void);
+
+void iupwinDrawBitmap(HDC hDC, HBITMAP hBitmap, HBITMAP hMask, int x, int y, int width, int height, int bpp);
+void iupwinDrawText(HDC hDC, const char* text, int x, int y, int width, int height, HFONT hFont, COLORREF fgcolor, int style);
+
+void iupwinDrawParentBackground(Ihandle* ih, HDC hDC, RECT* rect);
+void iupwinDrawButtonBorder(HWND hWnd, HDC hDC, RECT *rect, UINT itemState);
+
+void iupwinDrawThemeFrameBorder(HWND hWnd, HDC hDC, RECT *rect, UINT itemState);
+int iupwinDrawGetThemeTabsBgColor(HWND hWnd, COLORREF *color);
+int iupwinDrawGetThemeButtonBgColor(HWND hWnd, COLORREF *color);
+int iupwinDrawGetThemeFrameFgColor(HWND hWnd, COLORREF *color);
+void iupwinDrawRemoveTheme(HWND hWnd);
+
+typedef struct _iupwinBitmapDC
+{
+ HBITMAP hBitmap, hOldBitmap;
+ HDC hBitmapDC, hDC;
+ int w, h;
+} iupwinBitmapDC;
+
+HDC iupwinDrawCreateBitmapDC(iupwinBitmapDC *bmpDC, HDC hDC, int w, int h);
+void iupwinDrawDestroyBitmapDC(iupwinBitmapDC *bmpDC);
+
+#ifndef ODS_HOTLIGHT /* Only defined if WINVER >= 0x0500 */
+#define ODS_HOTLIGHT 0x0040
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/win/iupwin_drv.h b/iup/src/win/iupwin_drv.h
new file mode 100755
index 0000000..3372c1a
--- /dev/null
+++ b/iup/src/win/iupwin_drv.h
@@ -0,0 +1,113 @@
+/** \file
+ * \brief Windows Driver
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUPWIN_DRV_H
+#define __IUPWIN_DRV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifndef WS_EX_COMPOSITED
+#define WS_EX_COMPOSITED 0x02000000L /* it is defined only when _WIN32_WINNT >= 0x0501 */
+#endif
+
+
+/* global variables */
+/* declared where they are initialized */
+extern HINSTANCE iupwin_hinstance; /* winopen.c */
+extern HINSTANCE iupwin_dll_hinstance; /* winmain.c */
+extern int iupwin_comctl32ver6; /* winopen.c */
+
+void iupwinShowLastError(void);
+
+/* focus */
+void iupwinWmSetFocus(Ihandle *ih);
+
+/* key */
+int iupwinKeyEvent(Ihandle* ih, int wincode, int press);
+void iupwinButtonKeySetStatus(WORD keys, char* status, int doubleclick);
+void iupwinKeyEncode(int key, unsigned int *keyval, unsigned int *state);
+
+/* tips */
+void iupwinTipsGetDispInfo(LPARAM lp);
+
+/* font */
+char* iupwinGetHFontAttrib(Ihandle *ih);
+HFONT iupwinGetHFont(const char* value);
+char* iupwinFindHFont(HFONT hFont);
+
+/* menu */
+void iupwinMenuDialogProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp);
+
+/* common */
+
+/* Definition of a callback used to return the background brush of controls called "_IUPWIN_CTLCOLOR_CB". */
+typedef int (*IFctlColor)(Ihandle* ih, HDC hdc, LRESULT *result);
+
+/* Definition of a callback used to draw custom controls called "_IUPWIN_DRAWITEM_CB".
+ drawitem is a pointer to a DRAWITEMSTRUCT struct. */
+typedef void (*IFdrawItem)(Ihandle* ih, void* drawitem);
+
+/* Definition of a callback used to notify custom controls called "_IUPWIN_NOTIFY_CB".
+ msg_info is a pointer to a NMHDR struct. */
+typedef int (*IFnotify)(Ihandle* ih, void* msg_info, HRESULT *result);
+
+/* Definition of callback used for custom WinProc. Can return 0 or 1.
+ 0 = do default processing.
+ 1 = ABORT default processing and the result value should be returned.
+*/
+typedef int (*IwinProc)(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result);
+
+/* Base WinProc used by all native elements. Configure base message handling
+ and custom IwinProc using "_IUPWIN_CTRLPROC_CB" callback. */
+LRESULT CALLBACK iupwinBaseWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
+
+/* Base IwinProc callback used by native controls. */
+int iupwinBaseProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result);
+
+/* Base IwinProc callback used by native containers.
+ Handle messages that are sent to the parent Window. */
+int iupwinBaseContainerProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result);
+
+/* Creates the Window with native parent and child ID, associate HWND with Ihandle*,
+ and replace the WinProc by iupwinBaseWinProc */
+int iupwinCreateWindowEx(Ihandle* ih, LPCSTR lpClassName, DWORD dwExStyle, DWORD dwStyle);
+
+int iupwinClassExist(const char* name);
+int iupwinGetColorRef(Ihandle *ih, char *name, COLORREF *color);
+int iupwinGetParentBgColor(Ihandle* ih, COLORREF* cr);
+void iupwinDropFiles(HDROP hDrop, Ihandle *ih);
+Ihandle* iupwinMenuGetItemHandle(HMENU hmenu, int menuId);
+Ihandle* iupwinMenuGetHandle(HMENU hMenu);
+int iupwinSetDragDropAttrib(Ihandle* ih, const char* value);
+void iupwinChangeProc(Ihandle *ih, WNDPROC new_proc);
+void iupwinMergeStyle(Ihandle* ih, DWORD old_mask, DWORD value);
+void iupwinSetStyle(Ihandle* ih, DWORD value, int set);
+WCHAR* iupwinStrChar2Wide(const char* str);
+int iupwinButtonUp(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp);
+int iupwinButtonDown(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp);
+int iupwinMouseMove(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp);
+char* iupwinGetClipboardText(Ihandle* ih);
+
+int iupwinGetScreenRes(void);
+/* 1 point = 1/72 inch */
+/* pixel = (point/72)*(pixel/inch) */
+#define IUPWIN_PT2PIXEL(_pt, _res) MulDiv(_pt, _res, 72) /* (((_pt)*(_res))/72) */
+#define IUPWIN_PIXEL2PT(_pixel, _res) MulDiv(_pixel, 72, _res) /* (((_pixel)*72)/(_res)) */
+
+
+/* child window identifier of the first MDI child window created,
+ should not conflict with any other command identifiers. */
+#define IUP_MDICHILD_START 100000000
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/win/iupwin_filedlg.c b/iup/src/win/iupwin_filedlg.c
new file mode 100755
index 0000000..da66b4b
--- /dev/null
+++ b/iup/src/win/iupwin_filedlg.c
@@ -0,0 +1,580 @@
+/** \file
+ * \brief IupFileDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commdlg.h>
+#include <shlobj.h>
+
+#include <stdio.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+#include "iup_drvinfo.h"
+
+#include "iupwin_drv.h"
+
+
+#ifndef OFN_FORCESHOWHIDDEN
+#define OFN_FORCESHOWHIDDEN 0x10000000 /* Show All files including System and hidden files */
+#endif
+
+#define MAX_FILENAME_SIZE 65000
+#define IUP_PREVIEWCANVAS 3000
+
+enum {IUP_DIALOGOPEN, IUP_DIALOGSAVE, IUP_DIALOGDIR};
+
+
+static void winFileDlgStrReplacePathSlash(char* name)
+{
+ /* check for "/" */
+ int i, len = strlen(name);
+ for (i = 0; i < len; i++)
+ {
+ if (name[i] == '/')
+ name[i] = '\\';
+ }
+}
+
+static INT CALLBACK winFileDlgBrowseCallback(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+ (void)lParam;
+ if (uMsg == BFFM_INITIALIZED)
+ {
+ char* value;
+ Ihandle* ih = (Ihandle*)lpData;
+ ih->handle = hWnd;
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+ value = iupStrDup(iupAttribGet(ih, "DIRECTORY"));
+ if (value)
+ {
+ winFileDlgStrReplacePathSlash(value);
+ SendMessage(hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)value);
+ free(value);
+ }
+ }
+ else if (uMsg == BFFM_SELCHANGED)
+ {
+ char* buffer = iupStrGetMemory(MAX_FILENAME_SIZE);
+ ITEMIDLIST* selecteditem = (ITEMIDLIST*)lParam;
+ buffer[0] = 0;
+ SHGetPathFromIDList(selecteditem, buffer);
+ if (buffer[0] == 0)
+ SendMessage(hWnd, BFFM_ENABLEOK, 0, (LPARAM)FALSE);
+ else
+ SendMessage(hWnd, BFFM_ENABLEOK, 0, (LPARAM)TRUE);
+ }
+ return 0;
+}
+
+static void winFileDlgGetFolder(Ihandle *ih)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ BROWSEINFO browseinfo;
+ char buffer[MAX_PATH];
+ ITEMIDLIST *selecteditem;
+
+ if (!parent)
+ parent = GetActiveWindow();
+
+ ZeroMemory(&browseinfo, sizeof(BROWSEINFO));
+ browseinfo.lpszTitle = iupAttribGet(ih, "TITLE");
+ browseinfo.pszDisplayName = buffer;
+ browseinfo.lpfn = winFileDlgBrowseCallback;
+ browseinfo.lParam = (LPARAM)ih;
+ browseinfo.ulFlags = BIF_NEWDIALOGSTYLE;
+ browseinfo.hwndOwner = parent;
+
+ selecteditem = SHBrowseForFolder(&browseinfo);
+ if (!selecteditem)
+ {
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "STATUS", "-1");
+ }
+ else
+ {
+ SHGetPathFromIDList(selecteditem, buffer);
+ iupAttribStoreStr(ih, "VALUE", buffer);
+ iupAttribSetStr(ih, "STATUS", "0");
+ }
+
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ iupAttribSetStr(ih, "FILTERUSED", NULL);
+}
+
+/************************************************************************************************/
+
+static UINT_PTR CALLBACK winFileDlgSimpleHook(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+ (void)wParam;
+ switch(uiMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ OPENFILENAME* openfilename = (OPENFILENAME*)lParam;
+ Ihandle* ih = (Ihandle*)openfilename->lCustData;
+ ih->handle = GetParent(hWnd);
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+ SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)ih);
+ break;
+ }
+ case WM_DESTROY:
+ {
+ Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER);
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ if (cb) cb(ih, NULL, "FINISH");
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ LPOFNOTIFY pofn = (LPOFNOTIFY)lParam;
+ Ihandle* ih = (Ihandle*)pofn->lpOFN->lCustData;
+ switch (pofn->hdr.code)
+ {
+ case CDN_INITDONE:
+ {
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ if (cb) cb(ih, NULL, "INIT");
+ break;
+ }
+ case CDN_FILEOK:
+ case CDN_SELCHANGE:
+ {
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ if (cb)
+ {
+ char* filename = iupStrGetMemory(MAX_FILENAME_SIZE);
+ if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE)
+ {
+ int ret;
+ char* file_msg;
+
+ if (!iupdrvIsFile(filename))
+ break;
+
+ if (pofn->hdr.code == CDN_FILEOK)
+ file_msg = "OK";
+ else
+ file_msg = "SELECT";
+
+ ret = cb(ih, filename, file_msg);
+ if (pofn->hdr.code == CDN_FILEOK && ret == IUP_IGNORE)
+ {
+ SetWindowLongPtr(hWnd, DWLP_MSGRESULT, 1L);
+ return 1; /* will refuse the file */
+ }
+ }
+ }
+ break;
+ }
+ case CDN_HELP:
+ {
+ Icallback cb = (Icallback) IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ EndDialog(GetParent(hWnd), IDCANCEL);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static void winFileDlgSetPreviewCanvasPos(HWND hWnd, HWND hWndPreview)
+{
+ int height, width, ypos, xpos;
+ RECT rect, dlgrect;
+ HWND hWndFileList = GetDlgItem(GetParent(hWnd), 0x0471);
+ HWND hWndFileCombo = GetDlgItem(GetParent(hWnd), 0x047C);
+
+ /* GetWindowRect return screen coordinates, must convert to parent's client coordinates */
+ GetWindowRect(hWnd, &dlgrect);
+
+ GetWindowRect(hWndPreview, &rect);
+ ypos = rect.top - dlgrect.top; /* keep the same vertical position, at first time this is 0 */
+ height = rect.bottom-rect.top; /* keep the same height */
+
+ GetWindowRect(hWndFileList, &rect);
+ xpos = rect.left - dlgrect.left; /* horizontally align with file list at left */
+
+ GetWindowRect(hWndFileCombo, &rect);
+ width = (rect.right - dlgrect.left) - xpos; /* set size to align with file combo at right */
+
+ /* also position the child window that contains the template, must have room for the preview canvas */
+ if (ypos) /* first time does nothing */
+ SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, (rect.right - dlgrect.left), (dlgrect.bottom - dlgrect.top), SWP_NOMOVE|SWP_NOZORDER);
+
+ SetWindowPos(hWndPreview, HWND_TOP, xpos, ypos, width, height, SWP_NOZORDER);
+}
+
+static void winFileDlgUpdatePreviewGLCanvas(Ihandle* ih)
+{
+ Ihandle* glcanvas = IupGetAttributeHandle(ih, "PREVIEWGLCANVAS");
+ if (glcanvas)
+ {
+ iupAttribSetStr(glcanvas, "HWND", iupAttribGet(ih, "HWND"));
+ glcanvas->iclass->Map(glcanvas);
+ }
+}
+
+static UINT_PTR CALLBACK winFileDlgPreviewHook(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+ /* hWnd here is a handle to the child window that contains the template,
+ NOT the file dialog. Only the preview canvas is a child of this window. */
+
+ switch(uiMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ OPENFILENAME* openfilename = (OPENFILENAME*)lParam;
+ Ihandle* ih = (Ihandle*)openfilename->lCustData;
+ HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS);
+
+ ih->handle = GetParent(hWnd);
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+
+ if (hWndPreview)
+ {
+ RECT rect;
+
+ winFileDlgSetPreviewCanvasPos(hWnd, hWndPreview);
+
+ GetClientRect(hWndPreview, &rect);
+ iupAttribSetInt(ih, "PREVIEWWIDTH", rect.right - rect.left);
+ iupAttribSetInt(ih, "PREVIEWHEIGHT", rect.bottom - rect.top);
+ }
+ SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)ih);
+ iupAttribSetStr(ih, "WID", (char*)hWndPreview);
+ iupAttribSetStr(ih, "HWND", (char*)hWndPreview);
+ winFileDlgUpdatePreviewGLCanvas(ih);
+ break;
+ }
+ case WM_DRAWITEM:
+ {
+ if (wParam == IUP_PREVIEWCANVAS)
+ {
+ LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT)lParam;
+ Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER);
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ char* filename = iupStrGetMemory(MAX_FILENAME_SIZE);
+ iupAttribSetStr(ih, "PREVIEWDC", (char*)lpDrawItem->hDC);
+ if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE)
+ {
+ if (iupdrvIsFile(filename))
+ cb(ih, filename, "PAINT");
+ else
+ cb(ih, NULL, "PAINT");
+ }
+ else
+ cb(ih, NULL, "PAINT");
+ iupAttribSetStr(ih, "PREVIEWDC", NULL);
+ }
+ break;
+ }
+ case WM_SIZE:
+ {
+ HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS);
+ if (hWndPreview)
+ {
+ Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER);
+ RECT rect;
+
+ winFileDlgSetPreviewCanvasPos(hWnd, hWndPreview);
+
+ GetClientRect(hWndPreview, &rect);
+ iupAttribSetInt(ih, "PREVIEWWIDTH", rect.right-rect.left);
+
+ RedrawWindow(hWndPreview, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW);
+ }
+ break;
+ }
+ case WM_DESTROY:
+ {
+ Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER);
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ cb(ih, NULL, "FINISH");
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ LPOFNOTIFY pofn = (LPOFNOTIFY)lParam;
+ Ihandle* ih = (Ihandle*)pofn->lpOFN->lCustData;
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ switch (pofn->hdr.code)
+ {
+ case CDN_INITDONE:
+ {
+ HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS);
+ cb(ih, NULL, "INIT");
+ if (hWndPreview) RedrawWindow(hWndPreview, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW);
+ break;
+ }
+ case CDN_FILEOK:
+ case CDN_SELCHANGE:
+ {
+ HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS);
+ char* filename = iupStrGetMemory(MAX_FILENAME_SIZE);
+ if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE)
+ {
+ int ret;
+ char* file_msg;
+
+ if (!iupdrvIsFile(filename))
+ break;
+
+ if (pofn->hdr.code == CDN_FILEOK)
+ file_msg = "OK";
+ else
+ file_msg = "SELECT";
+
+ ret = cb(ih, filename, file_msg);
+ if (pofn->hdr.code == CDN_FILEOK && ret == IUP_IGNORE)
+ {
+ SetWindowLongPtr(hWnd, DWLP_MSGRESULT, 1L);
+ return 1; /* will refuse the file */
+ }
+ }
+ if (pofn->hdr.code == CDN_SELCHANGE && hWndPreview)
+ RedrawWindow(hWndPreview, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW);
+ break;
+ }
+ case CDN_HELP:
+ {
+ Icallback cb = (Icallback) IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ EndDialog(GetParent(hWnd), IDCANCEL);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static char* winFileDlgStrReplaceSeparator(const char* name)
+{
+ int i=0;
+ char* buffer = (char*)malloc(strlen(name)+2);
+
+ /* replace symbols "|" by terminator "\0" */
+
+ while (*name)
+ {
+ buffer[i] = *name;
+
+ if (buffer[i] == '|')
+ buffer[i] = 0;
+
+ i++;
+ name++;
+ }
+
+ buffer[i] = 0;
+ buffer[i+1] = 0; /* additional 0 at the end */
+ return buffer;
+}
+
+static int winFileDlgPopup(Ihandle *ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ OPENFILENAME openfilename;
+ int result, dialogtype;
+ char *value;
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ value = iupAttribGetStr(ih, "DIALOGTYPE");
+ if (iupStrEqualNoCase(value, "SAVE"))
+ dialogtype = IUP_DIALOGSAVE;
+ else if (iupStrEqualNoCase(value, "DIR"))
+ dialogtype = IUP_DIALOGDIR;
+ else
+ dialogtype = IUP_DIALOGOPEN;
+
+ if (dialogtype == IUP_DIALOGDIR)
+ {
+ winFileDlgGetFolder(ih);
+ return IUP_NOERROR;
+ }
+
+ if (!parent)
+ parent = GetActiveWindow();
+
+ ZeroMemory(&openfilename, sizeof(OPENFILENAME));
+ openfilename.lStructSize = sizeof(OPENFILENAME);
+ openfilename.hwndOwner = parent;
+
+ value = iupAttribGet(ih, "EXTFILTER");
+ if (value)
+ {
+ int index;
+ openfilename.lpstrFilter = winFileDlgStrReplaceSeparator(value);
+
+ value = iupAttribGet(ih, "FILTERUSED");
+ if (iupStrToInt(value, &index))
+ openfilename.nFilterIndex = index;
+ else
+ openfilename.nFilterIndex = 1;
+ }
+ else
+ {
+ value = iupAttribGet(ih, "FILTER");
+ if (value)
+ {
+ int sz1, sz2;
+ char* info = iupAttribGet(ih, "FILTERINFO");
+ if (!info)
+ info = value;
+
+ /* concat FILTERINFO+FILTER */
+ sz1 = strlen(info)+1;
+ sz2 = strlen(value)+1;
+ openfilename.lpstrFilter = (char*)malloc(sz1+sz2+1);
+
+ memcpy((char*)openfilename.lpstrFilter, info, sz1);
+ memcpy((char*)openfilename.lpstrFilter+sz1, value, sz2);
+ ((char*)openfilename.lpstrFilter)[sz1+sz2] = 0; /* additional 0 at the end */
+ openfilename.nFilterIndex = 1;
+ }
+ }
+
+ openfilename.lpstrFile = (char*)malloc(MAX_FILENAME_SIZE+1);
+ value = iupAttribGet(ih, "FILE");
+ if (value)
+ {
+ strncpy(openfilename.lpstrFile, value, MAX_FILENAME_SIZE);
+ winFileDlgStrReplacePathSlash(openfilename.lpstrFile);
+ }
+ else
+ openfilename.lpstrFile[0] = 0;
+
+ openfilename.nMaxFile = MAX_FILENAME_SIZE;
+
+ openfilename.lpstrInitialDir = iupStrDup(iupAttribGet(ih, "DIRECTORY"));
+ if (openfilename.lpstrInitialDir)
+ winFileDlgStrReplacePathSlash((char*)openfilename.lpstrInitialDir);
+
+ openfilename.lpstrTitle = iupAttribGet(ih, "TITLE");
+ openfilename.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
+
+ if (!iupAttribGetBoolean(ih, "NOOVERWRITEPROMPT"))
+ openfilename.Flags |= OFN_OVERWRITEPROMPT;
+
+ if (iupAttribGetBoolean(ih, "SHOWHIDDEN"))
+ openfilename.Flags |= OFN_FORCESHOWHIDDEN;
+
+ value = iupAttribGet(ih, "ALLOWNEW");
+ if (!value)
+ {
+ if (dialogtype == IUP_DIALOGSAVE)
+ value = "YES";
+ else
+ value = "NO";
+ }
+ if (iupStrBoolean(value))
+ openfilename.Flags |= OFN_CREATEPROMPT;
+ else
+ openfilename.Flags |= OFN_FILEMUSTEXIST;
+
+ if (iupAttribGetBoolean(ih, "NOCHANGEDIR"))
+ openfilename.Flags |= OFN_NOCHANGEDIR;
+
+ if (iupAttribGetBoolean(ih, "MULTIPLEFILES"))
+ openfilename.Flags |= OFN_ALLOWMULTISELECT;
+
+ openfilename.lpfnHook = winFileDlgSimpleHook;
+ openfilename.Flags |= OFN_ENABLEHOOK | OFN_EXPLORER | OFN_ENABLESIZING;
+ openfilename.lCustData = (LPARAM)ih;
+
+ if (iupAttribGetBoolean(ih, "SHOWPREVIEW") && IupGetCallback(ih, "FILE_CB"))
+ {
+ openfilename.Flags |= OFN_ENABLETEMPLATE;
+ openfilename.hInstance = iupwin_dll_hinstance? iupwin_dll_hinstance: iupwin_hinstance;
+ openfilename.lpTemplateName = "iupPreviewDlg";
+ openfilename.lpfnHook = winFileDlgPreviewHook;
+ }
+
+ if (IupGetCallback(ih, "HELP_CB"))
+ openfilename.Flags |= OFN_SHOWHELP;
+
+ if (dialogtype == IUP_DIALOGOPEN)
+ result = GetOpenFileName(&openfilename);
+ else
+ result = GetSaveFileName(&openfilename);
+
+ if (result)
+ {
+ if (iupAttribGetBoolean(ih, "MULTIPLEFILES"))
+ {
+ int i = 0;
+
+ /* If there is more than one file, replace terminator by the separator */
+ if (openfilename.lpstrFile && openfilename.lpstrFile[openfilename.nFileOffset-1] == 0 && openfilename.nFileOffset>0)
+ {
+ while (openfilename.lpstrFile[i] != 0 || openfilename.lpstrFile[i+1] != 0)
+ {
+ if (openfilename.lpstrFile[i]==0)
+ openfilename.lpstrFile[i] = '|';
+ i++;
+ }
+ openfilename.lpstrFile[i] = '|';
+ }
+
+ iupAttribSetStr(ih, "STATUS", "0");
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ }
+ else
+ {
+ if (iupdrvIsFile(openfilename.lpstrFile)) /* check if file exists */
+ {
+ iupAttribSetStr(ih, "FILEEXIST", "YES");
+ iupAttribSetStr(ih, "STATUS", "0");
+ }
+ else
+ {
+ iupAttribSetStr(ih, "FILEEXIST", "NO");
+ iupAttribSetStr(ih, "STATUS", "1");
+ }
+ }
+
+ iupAttribStoreStr(ih, "VALUE", openfilename.lpstrFile);
+ iupAttribSetInt(ih, "FILTERUSED", (int)openfilename.nFilterIndex);
+ }
+ else
+ {
+ iupAttribSetStr(ih, "FILTERUSED", NULL);
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ iupAttribSetStr(ih, "STATUS", "-1");
+ }
+
+ if (openfilename.lpstrFilter) free((char*)openfilename.lpstrFilter);
+ if (openfilename.lpstrInitialDir) free((char*)openfilename.lpstrInitialDir);
+ if (openfilename.lpstrFile) free(openfilename.lpstrFile);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvFileDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = winFileDlgPopup;
+
+ /* IupFileDialog Windows and GTK Only */
+ iupClassRegisterAttribute(ic, "EXTFILTER", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILTERINFO", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILTERUSED", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MULTIPLEFILES", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_focus.c b/iup/src/win/iupwin_focus.c
new file mode 100755
index 0000000..63da02d
--- /dev/null
+++ b/iup/src/win/iupwin_focus.c
@@ -0,0 +1,62 @@
+/** \file
+ * \brief Windows Focus
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <windows.h>
+
+#include "iup.h"
+#include "iup_object.h"
+#include "iup_focus.h"
+#include "iup_assert.h"
+#include "iup_drv.h"
+#include "iup_attrib.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+
+/* not defined for gcc */
+#ifndef WM_CHANGEUISTATE
+#define WM_CHANGEUISTATE 0x0127
+#endif
+#ifndef UIS_CLEAR
+#define UIS_CLEAR 2
+#endif
+#ifndef UISF_HIDEFOCUS
+#define UISF_HIDEFOCUS 0x1
+#endif
+
+/* Since Windows XP, the focus feedback only appears after the user press a key.
+ Except for the IupText where the feedback is the caret.
+ Before that if you click in a control the focus feedback will be hidden.
+
+ We manually send WM_CHANGEUISTATE because we do not use IsDialogMessage anymore,
+ and the focus feedback was not shown even after the used press a key.
+
+ TODO: I would like a form to always show the feedback, but could not understand how WM_CHANGEUISTATE works.
+ Neither SystemParametersInfo(SPI_SETKEYBOARDCUES, TRUE) or SystemParametersInfo(SPI_SETKEYBOARDPREF, TRUE) worked.
+*/
+void iupdrvSetFocus(Ihandle *ih)
+{
+ SetFocus(ih->handle);
+ SendMessage(ih->handle, WM_CHANGEUISTATE, UIS_CLEAR|UISF_HIDEFOCUS, 0);
+}
+
+void iupwinWmSetFocus(Ihandle *ih)
+{
+ Ihandle* dialog = IupGetDialog(ih);
+ if (ih != dialog)
+ iupAttribSetStr(dialog, "_IUPWIN_LASTFOCUS", (char*)ih); /* used by IupMenu */
+ else
+ {
+ /* if a control inside that dialog had the focus, then reset to it when the dialog gets the focus */
+ Ihandle* lastfocus = (Ihandle*)iupAttribGet(dialog, "_IUPWIN_LASTFOCUS");
+ if (lastfocus) IupSetFocus(lastfocus);
+ }
+
+ iupCallGetFocusCb(ih);
+}
diff --git a/iup/src/win/iupwin_font.c b/iup/src/win/iupwin_font.c
new file mode 100755
index 0000000..659e2d9
--- /dev/null
+++ b/iup/src/win/iupwin_font.c
@@ -0,0 +1,342 @@
+/** \file
+ * \brief Windows Font mapping
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <windows.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_array.h"
+#include "iup_attrib.h"
+#include "iup_object.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_assert.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_info.h"
+
+
+typedef struct IwinFont_
+{
+ char standardfont[200];
+ HFONT hFont;
+ int charwidth, charheight;
+} IwinFont;
+
+static Iarray* win_fonts = NULL;
+
+static IwinFont* winFindFont(const char *standardfont)
+{
+ HFONT hFont;
+ int height_pixels;
+ char typeface[50] = "";
+ int height = 8;
+ int is_bold = 0,
+ is_italic = 0,
+ is_underline = 0,
+ is_strikeout = 0;
+ int res = iupwinGetScreenRes();
+ int i, count = iupArrayCount(win_fonts);
+ const char* mapped_name;
+
+ /* Check if the standardfont already exists in cache */
+ IwinFont* fonts = (IwinFont*)iupArrayGetData(win_fonts);
+ for (i = 0; i < count; i++)
+ {
+ if (iupStrEqualNoCase(standardfont, fonts[i].standardfont))
+ return &fonts[i];
+ }
+
+ /* parse the old format first */
+ if (!iupFontParseWin(standardfont, typeface, &height, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParsePango(standardfont, typeface, &height, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ return NULL;
+ }
+
+ mapped_name = iupFontGetWinName(typeface);
+ if (mapped_name)
+ strcpy(typeface, mapped_name);
+
+ /* get in pixels */
+ if (height < 0)
+ height_pixels = height; /* already in pixels */
+ else
+ height_pixels = -IUPWIN_PT2PIXEL(height, res);
+
+ if (height_pixels == 0)
+ return NULL;
+
+ hFont = CreateFont(height_pixels,
+ 0,0,0,
+ (is_bold) ? FW_BOLD : FW_NORMAL,
+ is_italic,
+ is_underline,
+ is_strikeout,
+ DEFAULT_CHARSET,OUT_TT_PRECIS,
+ CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
+ FF_DONTCARE|DEFAULT_PITCH,
+ typeface);
+ if (!hFont)
+ return NULL;
+
+ /* create room in the array */
+ fonts = (IwinFont*)iupArrayInc(win_fonts);
+
+ strcpy(fonts[i].standardfont, standardfont);
+ fonts[i].hFont = hFont;
+
+ {
+ TEXTMETRIC tm;
+ HDC hdc = GetDC(NULL);
+ HFONT oldfont = SelectObject(hdc, hFont);
+
+ GetTextMetrics(hdc, &tm);
+
+ SelectObject(hdc, oldfont);
+ ReleaseDC(NULL, hdc);
+
+ fonts[i].charwidth = tm.tmAveCharWidth;
+ fonts[i].charheight = tm.tmHeight;
+ }
+
+ return &fonts[i];
+}
+
+static void winFontFromLogFont(LOGFONT* logfont, char * font)
+{
+ int is_bold = (logfont->lfWeight == FW_NORMAL)? 0: 1;
+ int is_italic = logfont->lfItalic;
+ int is_underline = logfont->lfUnderline;
+ int is_strikeout = logfont->lfStrikeOut;
+ int height_pixels = logfont->lfHeight; /* negative value */
+ int res = iupwinGetScreenRes();
+ int height = IUPWIN_PIXEL2PT(-height_pixels, res); /* return in points */
+
+ sprintf(font, "%s, %s%s%s%s %d", logfont->lfFaceName,
+ is_bold?"Bold ":"",
+ is_italic?"Italic ":"",
+ is_underline?"Underline ":"",
+ is_strikeout?"Strikeout ":"",
+ height);
+}
+
+char* iupdrvGetSystemFont(void)
+{
+ static char systemfont[200] = "";
+ NONCLIENTMETRICS ncm;
+ ncm.cbSize = sizeof(NONCLIENTMETRICS);
+ if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, FALSE))
+ winFontFromLogFont(&ncm.lfMessageFont, systemfont);
+ else
+ strcpy(systemfont, "Tahoma, 10");
+ return systemfont;
+}
+
+char* iupwinFindHFont(HFONT hFont)
+{
+ int i, count = iupArrayCount(win_fonts);
+
+ /* Check if the standardfont already exists in cache */
+ IwinFont* fonts = (IwinFont*)iupArrayGetData(win_fonts);
+ for (i = 0; i < count; i++)
+ {
+ if (hFont == fonts[i].hFont)
+ return fonts[i].standardfont;
+ }
+
+ return NULL;
+}
+
+HFONT iupwinGetHFont(const char* value)
+{
+ IwinFont* winfont = winFindFont(value);
+ if (!winfont)
+ return NULL;
+ else
+ return winfont->hFont;
+}
+
+static IwinFont* winFontCreateNativeFont(Ihandle *ih, const char* value)
+{
+ IwinFont* winfont = winFindFont(value);
+ if (!winfont)
+ {
+ iupERROR1("Failed to create Font: %s", value);
+ return NULL;
+ }
+
+ iupAttribSetStr(ih, "_IUP_WINFONT", (char*)winfont);
+ return winfont;
+}
+
+static IwinFont* winFontGet(Ihandle *ih)
+{
+ IwinFont* winfont = (IwinFont*)iupAttribGet(ih, "_IUP_WINFONT");
+ if (!winfont)
+ winfont = winFontCreateNativeFont(ih, iupGetFontAttrib(ih));
+ return winfont;
+}
+
+char* iupwinGetHFontAttrib(Ihandle *ih)
+{
+ IwinFont* winfont = winFontGet(ih);
+ if (!winfont)
+ return NULL;
+ else
+ return (char*)winfont->hFont;
+}
+
+int iupdrvSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ IwinFont* winfont = winFontCreateNativeFont(ih, value);
+ if (!winfont)
+ return 1;
+
+ /* If FONT is changed, must update the SIZE attribute */
+ iupBaseUpdateSizeFromFont(ih);
+
+ /* FONT attribute must be able to be set before mapping,
+ so the font is enable for size calculation. */
+ if (ih->handle && (ih->iclass->nativetype != IUP_TYPEVOID))
+ SendMessage(ih->handle, WM_SETFONT, (WPARAM)winfont->hFont, MAKELPARAM(TRUE,0));
+
+ return 1;
+}
+
+static HDC winFontGetDC(Ihandle* ih)
+{
+ if (ih->iclass->nativetype == IUP_TYPEVOID)
+ return GetDC(NULL);
+ else
+ return GetDC(ih->handle); /* handle can be NULL here */
+}
+
+static void winFontReleaseDC(Ihandle* ih, HDC hdc)
+{
+ if (ih->iclass->nativetype == IUP_TYPEVOID)
+ ReleaseDC(NULL, hdc);
+ else
+ ReleaseDC(ih->handle, hdc); /* handle can be NULL here */
+}
+
+void iupdrvFontGetMultiLineStringSize(Ihandle* ih, const char* str, int *w, int *h)
+{
+ int num_lin, max_w;
+
+ IwinFont* winfont = winFontGet(ih);
+ if (!winfont)
+ {
+ if (w) *w = 0;
+ if (h) *h = 0;
+ return;
+ }
+
+ if (!str)
+ {
+ if (w) *w = 0;
+ if (h) *h = winfont->charheight * 1;
+ return;
+ }
+
+ max_w = 0;
+ num_lin = 1;
+ if (str[0])
+ {
+ SIZE size;
+ int len;
+ const char *nextstr;
+ const char *curstr = str;
+
+ HDC hdc = winFontGetDC(ih);
+ HFONT oldhfont = SelectObject(hdc, winfont->hFont);
+
+ do
+ {
+ nextstr = iupStrNextLine(curstr, &len);
+ GetTextExtentPoint32(hdc, curstr, len, &size);
+ max_w = iupMAX(max_w, size.cx);
+
+ curstr = nextstr;
+ if (*nextstr)
+ num_lin++;
+ } while(*nextstr);
+
+ SelectObject(hdc, oldhfont);
+ winFontReleaseDC(ih, hdc);
+ }
+
+ if (w) *w = max_w;
+ if (h) *h = winfont->charheight*num_lin;
+}
+
+int iupdrvFontGetStringWidth(Ihandle* ih, const char* str)
+{
+ HDC hdc;
+ HFONT oldhfont, hFont;
+ SIZE size;
+ int len;
+ char* line_end;
+
+ if (!str || str[0]==0)
+ return 0;
+
+ hFont = (HFONT)iupwinGetHFontAttrib(ih);
+ if (!hFont)
+ return 0;
+
+ hdc = winFontGetDC(ih);
+ oldhfont = SelectObject(hdc, hFont);
+
+ line_end = strchr(str, '\n');
+ if (line_end)
+ len = line_end-str;
+ else
+ len = strlen(str);
+
+ GetTextExtentPoint32(hdc, str, len, &size);
+
+ SelectObject(hdc, oldhfont);
+ winFontReleaseDC(ih, hdc);
+
+ return size.cx;
+}
+
+void iupdrvFontGetCharSize(Ihandle* ih, int *charwidth, int *charheight)
+{
+ IwinFont* winfont = winFontGet(ih);
+ if (!winfont)
+ {
+ if (charwidth) *charwidth = 0;
+ if (charheight) *charheight = 0;
+ return;
+ }
+
+ if (charwidth) *charwidth = winfont->charwidth;
+ if (charheight) *charheight = winfont->charheight;
+}
+
+void iupdrvFontInit(void)
+{
+ win_fonts = iupArrayCreate(50, sizeof(IwinFont));
+}
+
+void iupdrvFontFinish(void)
+{
+ int i, count = iupArrayCount(win_fonts);
+ IwinFont* fonts = (IwinFont*)iupArrayGetData(win_fonts);
+ for (i = 0; i < count; i++)
+ {
+ DeleteObject(fonts[i].hFont);
+ fonts[i].hFont = NULL;
+ }
+ iupArrayDestroy(win_fonts);
+}
diff --git a/iup/src/win/iupwin_fontdlg.c b/iup/src/win/iupwin_fontdlg.c
new file mode 100755
index 0000000..0602441
--- /dev/null
+++ b/iup/src/win/iupwin_fontdlg.c
@@ -0,0 +1,160 @@
+/** \file
+ * \brief IupFontDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <stdio.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+#include "iup_drvfont.h"
+
+#include "iupwin_drv.h"
+
+
+#define IUP_FONTFAMILYCOMBOBOX 0x0470
+
+static UINT_PTR winFontDlgHookProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+ (void)wParam;
+ if (uiMsg == WM_INITDIALOG)
+ {
+ HWND hWndItem;
+ CHOOSEFONT* choosefont = (CHOOSEFONT*)lParam;
+ Ihandle* ih = (Ihandle*)choosefont->lCustData;
+
+ char* value = iupAttribGet(ih, "TITLE");
+ if (value)
+ SetWindowText(hWnd, value);
+
+ ih->handle = hWnd;
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+ iupAttribSetStr(ih, "HWND", (char*)hWnd); /* used by HELP_CB in winDialogBaseProc */
+
+ hWndItem = GetDlgItem(hWnd, IUP_FONTFAMILYCOMBOBOX);
+ SetFocus(hWndItem);
+ }
+ return 0;
+}
+
+static int winFontDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ unsigned char r, g, b;
+ CHOOSEFONT choosefont;
+ LOGFONT logfont;
+ char* standardfont;
+ int height_pixels;
+ char typeface[50] = "";
+ int height = 8;
+ int is_bold = 0,
+ is_italic = 0,
+ is_underline = 0,
+ is_strikeout = 0;
+ int res = iupwinGetScreenRes();
+
+ iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */
+ iupAttribSetInt(ih, "_IUPDLG_Y", y);
+
+ if (!parent)
+ parent = GetActiveWindow();
+
+ standardfont = iupAttribGet(ih, "VALUE");
+ if (!standardfont)
+ return IUP_ERROR;
+
+ /* parse the old format first */
+ if (!iupFontParseWin(standardfont, typeface, &height, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ {
+ if (!iupFontParsePango(standardfont, typeface, &height, &is_bold, &is_italic, &is_underline, &is_strikeout))
+ return IUP_ERROR;
+ }
+
+ /* get size in pixels */
+ if (height < 0)
+ height_pixels = height; /* already in pixels */
+ else
+ height_pixels = -IUPWIN_PT2PIXEL(height, res);
+
+ if (height_pixels == 0)
+ return IUP_ERROR;
+
+ ZeroMemory(&choosefont, sizeof(CHOOSEFONT));
+ choosefont.lStructSize = sizeof(CHOOSEFONT);
+
+ if (iupStrToRGB(iupAttribGet(ih, "COLOR"), &r, &g, &b))
+ choosefont.rgbColors = RGB(r, g, b);
+
+ choosefont.hwndOwner = parent;
+ choosefont.lpLogFont = &logfont;
+ choosefont.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT | CF_ENABLEHOOK;
+ choosefont.lCustData = (LPARAM)ih;
+ choosefont.lpfnHook = (LPCFHOOKPROC)winFontDlgHookProc;
+
+ if (IupGetCallback(ih, "HELP_CB"))
+ choosefont.Flags |= CF_SHOWHELP;
+
+ strcpy(logfont.lfFaceName, typeface);
+ logfont.lfHeight = height_pixels;
+ logfont.lfWeight = (is_bold)? FW_BOLD: FW_NORMAL;
+ logfont.lfItalic = (BYTE)is_italic;
+ logfont.lfUnderline = (BYTE)is_underline;
+ logfont.lfStrikeOut = (BYTE)is_strikeout;
+
+ logfont.lfCharSet = DEFAULT_CHARSET;
+ logfont.lfEscapement = 0;
+ logfont.lfOrientation = 0;
+ logfont.lfWidth = 0;
+ logfont.lfOutPrecision = OUT_TT_PRECIS;
+ logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ logfont.lfQuality = DEFAULT_QUALITY;
+ logfont.lfPitchAndFamily = FF_DONTCARE|DEFAULT_PITCH;
+
+ if (!ChooseFont(&choosefont))
+ {
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "COLOR", NULL);
+ iupAttribSetStr(ih, "STATUS", NULL);
+ return IUP_NOERROR;
+ }
+
+ is_bold = (logfont.lfWeight == FW_NORMAL)? 0: 1;
+ is_italic = logfont.lfItalic;
+ is_underline = logfont.lfUnderline;
+ is_strikeout = logfont.lfStrikeOut;
+ height_pixels = logfont.lfHeight;
+
+ if (height < 0) /* not an error, use old value as a reference for the units */
+ height = height_pixels; /* return in pixels */
+ else
+ height = IUPWIN_PIXEL2PT(-height_pixels, res); /* return in points */
+
+ iupAttribSetStrf(ih, "VALUE", "%s, %s%s%s%s %d", logfont.lfFaceName,
+ is_bold?"Bold ":"",
+ is_italic?"Italic ":"",
+ is_underline?"Underline ":"",
+ is_strikeout?"Strikeout ":"",
+ height);
+
+ iupAttribSetStrf(ih, "COLOR", "%d %d %d", GetRValue(choosefont.rgbColors),
+ GetGValue(choosefont.rgbColors),
+ GetBValue(choosefont.rgbColors));
+ iupAttribSetStr(ih, "STATUS", "1");
+
+ return IUP_NOERROR;
+}
+
+void iupdrvFontDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = winFontDlgPopup;
+
+ /* IupFontDialog Windows Only */
+ iupClassRegisterAttribute(ic, "COLOR", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_frame.c b/iup/src/win/iupwin_frame.c
new file mode 100755
index 0000000..0949b5d
--- /dev/null
+++ b/iup/src/win/iupwin_frame.c
@@ -0,0 +1,203 @@
+/** \file
+ * \brief Frame Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_stdcontrols.h"
+#include "iup_frame.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_draw.h"
+#include "iupwin_info.h"
+
+
+void iupdrvFrameGetDecorOffset(Ihandle* ih, int *x, int *y)
+{
+ if (iupwin_comctl32ver6)
+ {
+ *x = 3;
+ *y = 3;
+ }
+ else
+ {
+ *x = 2;
+ *y = 2;
+ }
+
+ if (iupAttribGet(ih, "_IUPFRAME_HAS_TITLE") || iupAttribGet(ih, "TITLE"))
+ {
+ (*y) += iupFrameGetTitleHeight(ih);
+ }
+}
+
+static void winFrameDrawText(HDC hDC, const char* text, int x, int y, COLORREF fgcolor)
+{
+ COLORREF oldcolor;
+
+ SetTextAlign(hDC, TA_TOP|TA_LEFT);
+ SetBkMode(hDC, TRANSPARENT);
+ oldcolor = SetTextColor(hDC, fgcolor);
+
+ TextOut(hDC, x, y, text, strlen(text));
+
+ SetTextColor(hDC, oldcolor);
+ SetBkMode(hDC, OPAQUE);
+}
+
+static void winFrameDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem)
+{
+ iupwinBitmapDC bmpDC;
+ HDC hDC = iupwinDrawCreateBitmapDC(&bmpDC, drawitem->hDC, drawitem->rcItem.right-drawitem->rcItem.left,
+ drawitem->rcItem.bottom-drawitem->rcItem.top);
+
+ iupwinDrawParentBackground(ih, hDC, &drawitem->rcItem);
+
+ if (iupAttribGet(ih, "_IUPFRAME_HAS_TITLE"))
+ {
+ int x, y;
+ HFONT hOldFont, hFont = (HFONT)iupwinGetHFontAttrib(ih);
+ int txt_height = iupFrameGetTitleHeight(ih);
+ COLORREF fgcolor;
+ SIZE size;
+
+ char* title = iupdrvBaseGetTitleAttrib(ih);
+ if (!title) title = "";
+
+ x = drawitem->rcItem.left+7;
+ y = drawitem->rcItem.top;
+
+ hOldFont = SelectObject(hDC, hFont);
+ GetTextExtentPoint32(hDC, title, strlen(title), &size);
+ ExcludeClipRect(hDC, x-2, y, x+size.cx+2, y+size.cy);
+
+ drawitem->rcItem.top += txt_height/2;
+ if (iupwin_comctl32ver6)
+ iupwinDrawThemeFrameBorder(ih->handle, hDC, &drawitem->rcItem, drawitem->itemState);
+ else
+ DrawEdge(hDC, &drawitem->rcItem, EDGE_ETCHED, BF_RECT);
+
+ SelectClipRgn(hDC, NULL);
+
+ if (drawitem->itemState & ODS_DISABLED)
+ fgcolor = GetSysColor(COLOR_GRAYTEXT);
+ else
+ {
+ unsigned char r, g, b;
+ char* color = iupAttribGetInherit(ih, "FGCOLOR");
+ if (!color)
+ {
+ if (!iupwinDrawGetThemeFrameFgColor(ih->handle, &fgcolor))
+ fgcolor = 0; /* black */
+ }
+ else
+ {
+ if (iupStrToRGB(color, &r, &g, &b))
+ fgcolor = RGB(r,g,b);
+ else
+ fgcolor = 0; /* black */
+ }
+ }
+
+ winFrameDrawText(hDC, title, x, y, fgcolor);
+
+ SelectObject(hDC, hOldFont);
+ }
+ else
+ {
+ char* value = iupAttribGetStr(ih, "SUNKEN");
+ if (iupStrBoolean(value))
+ DrawEdge(hDC, &drawitem->rcItem, EDGE_SUNKEN, BF_RECT);
+ else
+ DrawEdge(hDC, &drawitem->rcItem, EDGE_ETCHED, BF_RECT);
+ }
+
+ iupwinDrawDestroyBitmapDC(&bmpDC);
+}
+
+static int winFrameProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ switch (msg)
+ {
+ case WM_GETDLGCODE:
+ {
+ *result = DLGC_STATIC; /* same return as GROUPBOX */
+ return 1;
+ }
+ case WM_NCHITTEST:
+ {
+ *result = HTTRANSPARENT; /* same return as GROUPBOX */
+ return 1;
+ }
+ case WM_ERASEBKGND:
+ {
+ /* just to ignore the internal processing */
+ *result = 1;
+ return 1;
+ }
+ }
+
+ return iupwinBaseContainerProc(ih, msg, wp, lp, result);
+}
+
+static int winFrameMapMethod(Ihandle* ih)
+{
+ char *title;
+ DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS|
+ BS_OWNERDRAW, /* owner draw necessary because BS_GROUPBOX does not work ok */
+ dwExStyle = 0;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ title = iupAttribGet(ih, "TITLE");
+ if (title)
+ iupAttribSetStr(ih, "_IUPFRAME_HAS_TITLE", "1");
+
+ if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED"))
+ dwExStyle |= WS_EX_COMPOSITED;
+ else
+ dwStyle |= WS_CLIPCHILDREN;
+
+ if (!iupwinCreateWindowEx(ih, "BUTTON", dwExStyle, dwStyle))
+ return IUP_ERROR;
+
+ /* replace the WinProc to handle other messages */
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winFrameProc);
+
+ /* Process WM_DRAWITEM */
+ IupSetCallback(ih, "_IUPWIN_DRAWITEM_CB", (Icallback)winFrameDrawItem);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvFrameInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winFrameMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", iupBaseNativeParentGetBgColorAttrib, NULL, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, iupdrvBaseSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_globalattrib.c b/iup/src/win/iupwin_globalattrib.c
new file mode 100755
index 0000000..a176925
--- /dev/null
+++ b/iup/src/win/iupwin_globalattrib.c
@@ -0,0 +1,243 @@
+/** \file
+ * \brief Windows Driver iupdrvSetGlobal
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <windows.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvinfo.h"
+#include "iup_strmessage.h"
+
+#include "iupwin_drv.h"
+
+static int win_monitor_index = 0;
+
+/* Not defined in compilers older than VC9 */
+#ifndef MAPVK_VK_TO_VSC
+#define MAPVK_VK_TO_VSC (0)
+#endif
+
+static void winGlobalSendKey(int key, int press)
+{
+ unsigned int keyval, state;
+ INPUT input[2];
+ LPARAM extra_info;
+ WORD state_scan = 0, key_scan;
+ ZeroMemory(input, 2*sizeof(INPUT));
+
+ iupwinKeyEncode(key, &keyval, &state);
+ if (!keyval)
+ return;
+
+ extra_info = GetMessageExtraInfo();
+ if (state)
+ state_scan = (WORD)MapVirtualKey(state, MAPVK_VK_TO_VSC);
+ key_scan = (WORD)MapVirtualKey(keyval, MAPVK_VK_TO_VSC);
+
+ if (press & 0x01)
+ {
+ if (state)
+ {
+ /* modifier first */
+ input[0].type = INPUT_KEYBOARD;
+ input[0].ki.wVk = (WORD)state;
+ input[0].ki.wScan = state_scan;
+ input[0].ki.dwExtraInfo = extra_info;
+
+ /* key second */
+ input[1].type = INPUT_KEYBOARD;
+ input[1].ki.wVk = (WORD)keyval;
+ input[1].ki.wScan = key_scan;
+ input[1].ki.dwExtraInfo = extra_info;
+
+ SendInput(2, input, sizeof(INPUT));
+ }
+ else
+ {
+ input[0].type = INPUT_KEYBOARD;
+ input[0].ki.wVk = (WORD)keyval;
+ input[0].ki.wScan = key_scan;
+ input[0].ki.dwExtraInfo = extra_info;
+
+ SendInput(1, input, sizeof(INPUT));
+ }
+ }
+
+ if (press & 0x02)
+ {
+ if (state)
+ {
+ /* key first */
+ input[0].type = INPUT_KEYBOARD;
+ input[0].ki.dwFlags = KEYEVENTF_KEYUP;
+ input[0].ki.wVk = (WORD)keyval;
+ input[0].ki.wScan = key_scan;
+ input[0].ki.dwExtraInfo = extra_info;
+
+ /* modifier second */
+ input[1].type = INPUT_KEYBOARD;
+ input[1].ki.dwFlags = KEYEVENTF_KEYUP;
+ input[1].ki.wVk = (WORD)state;
+ input[1].ki.wScan = state_scan;
+ input[1].ki.dwExtraInfo = extra_info;
+
+ SendInput(2, input, sizeof(INPUT));
+ }
+ else
+ {
+ input[0].type = INPUT_KEYBOARD;
+ input[0].ki.dwFlags = KEYEVENTF_KEYUP;
+ input[0].ki.wVk = (WORD)keyval;
+ input[0].ki.wScan = key_scan;
+ input[0].ki.dwExtraInfo = extra_info;
+
+ SendInput(1, input, sizeof(INPUT));
+ }
+ }
+}
+
+static BOOL CALLBACK winMonitorInfoEnum(HMONITOR handle, HDC handle_dc, LPRECT rect, LPARAM data)
+{
+ RECT* monitors_rect = (RECT*)data;
+ monitors_rect[win_monitor_index] = *rect;
+ win_monitor_index++;
+ (void)handle_dc;
+ (void)handle;
+ return TRUE;
+}
+
+int iupdrvSetGlobal(const char *name, const char *value)
+{
+ if (iupStrEqual(name, "LANGUAGE"))
+ {
+ iupStrMessageUpdateLanguage(value);
+ return 1;
+ }
+ if (iupStrEqual(name, "CURSORPOS"))
+ {
+ int x, y;
+ if (iupStrToIntInt(value, &x, &y, 'x') == 2)
+ SetCursorPos(x, y);
+ return 0;
+ }
+ if (iupStrEqual(name, "KEYPRESS"))
+ {
+ int key;
+ if (iupStrToInt(value, &key))
+ winGlobalSendKey(key, 0x01);
+ return 0;
+ }
+ if (iupStrEqual(name, "KEYRELEASE"))
+ {
+ int key;
+ if (iupStrToInt(value, &key))
+ winGlobalSendKey(key, 0x02);
+ return 0;
+ }
+ if (iupStrEqual(name, "KEY"))
+ {
+ int key;
+ if (iupStrToInt(value, &key))
+ winGlobalSendKey(key, 0x03);
+ return 0;
+ }
+ return 1;
+}
+
+char *iupdrvGetGlobal(const char *name)
+{
+ if (iupStrEqual(name, "CURSORPOS"))
+ {
+ int x, y;
+ char* str = iupStrGetMemory(50);
+ iupdrvGetCursorPos(&x, &y);
+ sprintf(str, "%dx%d", x, y);
+ return str;
+ }
+ if (iupStrEqual(name, "SHIFTKEY"))
+ {
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[0] == 'S')
+ return "ON";
+ return "OFF";
+ }
+ if (iupStrEqual(name, "CONTROLKEY"))
+ {
+ char key[5];
+ iupdrvGetKeyState(key);
+ if (key[1] == 'C')
+ return "ON";
+ return "OFF";
+ }
+ if (iupStrEqual(name, "MODKEYSTATE"))
+ {
+ char *str = iupStrGetMemory(5);
+ iupdrvGetKeyState(str);
+ return str;
+ }
+ if (iupStrEqual(name, "SCREENSIZE"))
+ {
+ char *str = iupStrGetMemory(50);
+ int w, h;
+ iupdrvGetScreenSize(&w, &h);
+ sprintf(str, "%dx%d", w, h);
+ return str;
+ }
+ if (iupStrEqual(name, "FULLSIZE"))
+ {
+ char *str = iupStrGetMemory(50);
+ int w, h;
+ iupdrvGetFullSize(&w, &h);
+ sprintf(str, "%dx%d", w, h);
+ return str;
+ }
+ if (iupStrEqual(name, "SCREENDEPTH"))
+ {
+ char *str = iupStrGetMemory(50);
+ int bpp = iupdrvGetScreenDepth();
+ sprintf(str, "%d", bpp);
+ return str;
+ }
+ if (iupStrEqual(name, "VIRTUALSCREEN"))
+ {
+ char *str = iupStrGetMemory(50);
+ int x = GetSystemMetrics(SM_XVIRTUALSCREEN);
+ int y = GetSystemMetrics(SM_YVIRTUALSCREEN);
+ int w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
+ int h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
+ sprintf(str, "%d %d %d %d", x, y, w, h);
+ return str;
+ }
+ if (iupStrEqual(name, "MONITORSINFO"))
+ {
+ int i;
+ int monitors_count = GetSystemMetrics(SM_CMONITORS);
+ RECT* monitors_rect = malloc(monitors_count*sizeof(RECT));
+ char *str = iupStrGetMemory(monitors_count*50);
+ char* pstr = str;
+
+ win_monitor_index = 0;
+ EnumDisplayMonitors(NULL, NULL, winMonitorInfoEnum, (LPARAM)monitors_rect);
+
+ for (i=0; i < monitors_count; i++)
+ pstr += sprintf(pstr, "%d %d %d %d\n", (int)monitors_rect[i].left, (int)monitors_rect[i].top, (int)(monitors_rect[i].right-monitors_rect[i].left), (int)(monitors_rect[i].bottom-monitors_rect[i].top));
+
+ free(monitors_rect);
+ return str;
+ }
+ if (iupStrEqual(name, "TRUECOLORCANVAS"))
+ {
+ if (iupdrvGetScreenDepth() > 8)
+ return "YES";
+ return "NO";
+ }
+ return NULL;
+}
diff --git a/iup/src/win/iupwin_handle.c b/iup/src/win/iupwin_handle.c
new file mode 100755
index 0000000..d5a7f77
--- /dev/null
+++ b/iup/src/win/iupwin_handle.c
@@ -0,0 +1,56 @@
+/** \file
+ * \brief HWND to ihandle table
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_table.h"
+
+#include "iupwin_handle.h"
+
+
+static Itable* winhandle_table; /* table indexed by HWND containing Ihandle* address */
+
+Ihandle* iupwinHandleGet(void* handle)
+{
+ Ihandle* ih;
+ if (!handle)
+ return NULL;
+ ih = (Ihandle*)iupTableGet(winhandle_table, (char*)handle);
+ if (ih && !iupObjectCheck(ih))
+ return NULL;
+ return ih;
+}
+
+void iupwinHandleSet(Ihandle *ih)
+{
+ iupTableSet(winhandle_table, (char*)ih->handle, ih, IUPTABLE_POINTER);
+}
+
+void iupwinHandleAdd(Ihandle *ih, InativeHandle* hWnd)
+{
+ iupTableSet(winhandle_table, (char*)hWnd, ih, IUPTABLE_POINTER);
+}
+
+void iupwinHandleRemove(Ihandle *ih)
+{
+ iupTableRemove(winhandle_table, (char*)ih->handle);
+}
+
+void iupwinHandleInit(void)
+{
+ winhandle_table = iupTableCreate(IUPTABLE_POINTERINDEXED);
+}
+
+void iupwinHandleFinish(void)
+{
+ iupTableDestroy(winhandle_table);
+ winhandle_table = NULL;
+}
diff --git a/iup/src/win/iupwin_handle.h b/iup/src/win/iupwin_handle.h
new file mode 100755
index 0000000..4a8643d
--- /dev/null
+++ b/iup/src/win/iupwin_handle.h
@@ -0,0 +1,28 @@
+/** \file
+ * \brief HWND to ihandle table
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUPWIN_HANDLE_H
+#define __IUPWIN_HANDLE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Returns the IUP handle given the Windows handle. */
+
+Ihandle* iupwinHandleGet(void* handle);
+void iupwinHandleSet(Ihandle *ih);
+void iupwinHandleAdd(Ihandle *ih, InativeHandle* hWnd);
+void iupwinHandleRemove(Ihandle *ih);
+void iupwinHandleInit(void);
+void iupwinHandleFinish(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/win/iupwin_image.c b/iup/src/win/iupwin_image.c
new file mode 100755
index 0000000..2db9800
--- /dev/null
+++ b/iup/src/win/iupwin_image.c
@@ -0,0 +1,668 @@
+/** \file
+ * \brief Image Resource.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_image.h"
+
+#include "iupwin_drv.h"
+
+/* RGB in RGBA DIBs are pre-multiplied by alpha to AlphaBlend usage. */
+#define iupALPHAPRE(_src, _alpha) (((_src)*(_alpha))/255)
+
+static int winDibNumColors(BITMAPINFOHEADER* bmih)
+{
+ if (bmih->biBitCount > 8)
+ {
+ if (bmih->biCompression == BI_BITFIELDS)
+ return 3;
+ else
+ return 0;
+ }
+ else
+ {
+ if (bmih->biClrUsed != 0)
+ return bmih->biClrUsed;
+ else
+ return 1 << bmih->biBitCount;
+ }
+}
+
+void iupdrvImageGetRawData(void* handle, unsigned char* imgdata)
+{
+ int x, y, w, h, bpp, bmp_line_size, bits_size;
+ BYTE* bits;
+ HANDLE hHandle = (HANDLE)handle;
+ void* dib = GlobalLock(hHandle);
+ BITMAPINFOHEADER* bmih = (BITMAPINFOHEADER*)dib;
+
+ w = bmih->biWidth;
+ h = abs(bmih->biHeight);
+ bpp = iupImageNormBpp(bmih->biBitCount);
+ bmp_line_size = ((w * bmih->biBitCount + 31) / 32) * 4; /* DWORD aligned, 4 bytes boundary in a N bpp image */
+ bits_size = bmp_line_size*h;
+
+ bits = ((BYTE*)dib) + sizeof(BITMAPINFOHEADER) + winDibNumColors(bmih)*sizeof(RGBQUAD);
+
+ /* windows bitmaps are bottom up */
+ /* imgdata is bottom up */
+
+ if (bmih->biHeight < 0)
+ bits = bits + (bits_size - bmp_line_size); /* start of last line */
+
+ if (bpp == 8)
+ {
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ switch (bmih->biBitCount)
+ {
+ case 1:
+ *imgdata++ = (unsigned char)((bits[x / 8] >> (7 - x % 8)) & 0x01);
+ break;
+ case 4:
+ *imgdata++ = (unsigned char)((bits[x / 2] >> ((1 - x % 2) * 4)) & 0x0F);
+ break;
+ case 8:
+ *imgdata++ = bits[x];
+ break;
+ }
+ }
+
+ if (bmih->biHeight < 0)
+ bits -= bmp_line_size;
+ else
+ bits += bmp_line_size;
+ }
+ }
+ else
+ {
+ int offset, planesize;
+ unsigned short color;
+ unsigned int rmask = 0, gmask = 0, bmask = 0,
+ roff = 0, goff = 0, boff = 0; /* pixel bit mask control when reading 16 and 32 bpp images */
+ unsigned char *red, *green, *blue, *alpha;
+
+ planesize = w*h;
+ red = imgdata;
+ green = imgdata+planesize;
+ blue = imgdata+2*planesize;
+ alpha = imgdata+3*planesize;
+
+ if (bmih->biBitCount == 16)
+ offset = bmp_line_size; /* do not increment for each pixel, jump line */
+ else
+ offset = bmp_line_size - (w*bmih->biBitCount)/8; /* increment for each pixel, jump pad */
+
+ if (bmih->biCompression == BI_BITFIELDS)
+ {
+ unsigned int Mask;
+ unsigned int* palette = (unsigned int*)(((BYTE*)bmih) + sizeof(BITMAPINFOHEADER));
+
+ rmask = Mask = palette[0];
+ while (!(Mask & 0x01))
+ {Mask >>= 1; roff++;}
+
+ gmask = Mask = palette[1];
+ while (!(Mask & 0x01))
+ {Mask >>= 1; goff++;}
+
+ bmask = Mask = palette[2];
+ while (!(Mask & 0x01))
+ {Mask >>= 1; boff++;}
+ }
+ else if (bmih->biBitCount == 16)
+ {
+ bmask = 0x001F;
+ gmask = 0x03E0;
+ rmask = 0x7C00;
+ boff = 0;
+ goff = 5;
+ roff = 10;
+ }
+
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ if (bmih->biBitCount == 16)
+ {
+ color = ((unsigned short*)bits)[x];
+ *red++ = (unsigned char)((((rmask & color) >> roff) * 255) / (rmask >> roff));
+ *green++ = (unsigned char)((((gmask & color) >> goff) * 255) / (gmask >> goff));
+ *blue++ = (unsigned char)((((bmask & color) >> boff) * 255) / (bmask >> boff));
+ }
+ else
+ {
+ *blue++ = *bits++;
+ *green++ = *bits++;
+ *red++ = *bits++;
+
+ if (bmih->biBitCount == 32)
+ {
+ if (alpha)
+ *alpha++ = *bits++;
+ else
+ bits++;
+ }
+ }
+ }
+
+ bits += offset;
+
+ if (bmih->biHeight < 0)
+ bits -= 2*bmp_line_size;
+ }
+ }
+
+ GlobalUnlock(hHandle);
+}
+
+void* iupdrvImageCreateImageRaw(int width, int height, int bpp, iupColor* colors, int colors_count, unsigned char *imgdata)
+{
+ int y,x,bmp_line_size,channels,bits_size,header_size;
+ HANDLE hHandle;
+ BYTE* bits; /* DIB bitmap bits, created in CreateDIBSection and filled here */
+ void* dib;
+ BITMAPINFOHEADER* bmih;
+
+ bmp_line_size = ((width * bpp + 31) / 32) * 4; /* DWORD aligned, 4 bytes boundary in a N bpp image */
+ bits_size = bmp_line_size*height;
+ header_size = sizeof(BITMAPINFOHEADER) + colors_count*sizeof(RGBQUAD);
+
+ hHandle = GlobalAlloc(GMEM_MOVEABLE, header_size+bits_size);
+ if (!hHandle)
+ return NULL;
+
+ dib = GlobalLock(hHandle);
+ bits = ((BYTE*)dib) + header_size;
+
+ bmih = (BITMAPINFOHEADER*)dib;
+
+ memset(bmih, 0, sizeof(BITMAPINFOHEADER));
+ bmih->biSize = sizeof(BITMAPINFOHEADER);
+ bmih->biWidth = width;
+ bmih->biHeight = height;
+ bmih->biPlanes = 1; /* not the same as PLANES */
+ bmih->biBitCount = (WORD)bpp;
+ bmih->biCompression = BI_RGB;
+ bmih->biClrUsed = colors_count;
+
+ if (colors_count)
+ {
+ RGBQUAD* bitmap_colors = (RGBQUAD*)(((BYTE*)dib) + sizeof(BITMAPINFOHEADER));
+ int i;
+ for (i=0;i<colors_count;i++)
+ {
+ bitmap_colors[i].rgbRed = colors[i].r;
+ bitmap_colors[i].rgbGreen = colors[i].g;
+ bitmap_colors[i].rgbBlue = colors[i].b;
+ bitmap_colors[i].rgbReserved = 0;
+ }
+ }
+
+ channels = 1;
+ if (bpp == 24)
+ channels = 3;
+ else if (bpp == 32)
+ channels = 4;
+
+ /* windows bitmaps are bottom up */
+ /* imgdata is bottom up */
+
+ if (bpp != 8) /* (bpp == 32 || bpp == 24) */
+ {
+ unsigned char *r, *g, *b, *a;
+
+ int planesize = width*height;
+ r = imgdata;
+ g = imgdata+planesize;
+ b = imgdata+2*planesize;
+ a = imgdata+3*planesize;
+
+ for (y=0; y<height; y++)
+ {
+ int lineoffset = y*width;
+ for (x=0; x<width; x++)
+ {
+ int offset = channels*x;
+ /* Windows Bitmap order is BGRA */
+ BYTE *bmp_b = &bits[offset],
+ *bmp_g = bmp_b+1,
+ *bmp_r = bmp_g+1,
+ *bmp_a = bmp_r+1;
+
+ *bmp_r = r[lineoffset+x];
+ *bmp_g = g[lineoffset+x];
+ *bmp_b = b[lineoffset+x];
+
+ if (channels == 4) /* bpp==32 */
+ {
+ *bmp_a = a[lineoffset+x];
+
+ /* RGB in RGBA DIBs are pre-multiplied by alpha to AlphaBlend usage. */
+ *bmp_r = iupALPHAPRE(*bmp_r,*bmp_a);
+ *bmp_g = iupALPHAPRE(*bmp_g,*bmp_a);
+ *bmp_b = iupALPHAPRE(*bmp_b,*bmp_a);
+ }
+ }
+
+ bits += bmp_line_size;
+ }
+ }
+ else
+ {
+ for (y=0; y<height; y++)
+ {
+ int lineoffset = y*width;
+ for (x=0; x<width; x++)
+ {
+ bits[x] = imgdata[lineoffset+x];
+ }
+
+ bits += bmp_line_size;
+ }
+ }
+
+ GlobalUnlock(hHandle);
+ return hHandle;
+}
+
+int iupdrvImageGetRawInfo(void* handle, int *w, int *h, int *bpp, iupColor* colors, int *colors_count)
+{
+ HANDLE hHandle = (HANDLE)handle;
+ void* dib = GlobalLock(hHandle);
+ BITMAPINFOHEADER* bmih = (BITMAPINFOHEADER*)dib;
+
+ if (w) *w = bmih->biWidth;
+ if (h) *h = abs(bmih->biHeight);
+ if (bpp) *bpp = iupImageNormBpp(bmih->biBitCount);
+
+ if (bmih->biBitCount <= 8)
+ {
+ RGBQUAD* bitmap_colors = (RGBQUAD*)(((BYTE*)bmih) + sizeof(BITMAPINFOHEADER));
+ int i;
+
+ if (bmih->biClrUsed != 0)
+ *colors_count = bmih->biClrUsed;
+ else
+ *colors_count = 1 << bmih->biBitCount;
+
+ for (i=0;i<*colors_count;i++)
+ {
+ colors[i].r = bitmap_colors[i].rgbRed;
+ colors[i].g = bitmap_colors[i].rgbGreen;
+ colors[i].b = bitmap_colors[i].rgbBlue;
+ }
+ }
+
+ GlobalUnlock(hHandle);
+ return 1;
+}
+
+static int winImageInitDibColors(iupColor* colors, RGBQUAD* bmpcolors, int colors_count,
+ unsigned char bg_r, unsigned char bg_g, unsigned char bg_b, int make_inactive)
+{
+ int i, ret = 0;
+ for (i=0;i<colors_count;i++)
+ {
+ bmpcolors[i].rgbRed = colors[i].r;
+ bmpcolors[i].rgbGreen = colors[i].g;
+ bmpcolors[i].rgbBlue = colors[i].b;
+ bmpcolors[i].rgbReserved = colors[i].a;
+
+ if (bmpcolors[i].rgbReserved == 0) /* full transparent alpha */
+ {
+ bmpcolors[i].rgbBlue = bg_b;
+ bmpcolors[i].rgbGreen = bg_g;
+ bmpcolors[i].rgbRed = bg_r;
+ ret = 1;
+ }
+ else
+ bmpcolors[i].rgbReserved = 0; /* clear non transparent mark */
+
+ if (make_inactive)
+ iupImageColorMakeInactive(&(bmpcolors[i].rgbRed), &(bmpcolors[i].rgbGreen), &(bmpcolors[i].rgbBlue),
+ bg_r, bg_g, bg_b);
+ }
+
+ return ret;
+}
+
+static HBITMAP winImageCreateBitmap(Ihandle *ih, int width, int height, int bpp, BYTE** bits,
+ unsigned char bg_r, unsigned char bg_g, unsigned char bg_b, int make_inactive)
+{
+ HDC hDC;
+ int colors_count;
+ HBITMAP hBitmap;
+ BITMAPINFOHEADER* bmih; /* bitmap info header */
+ iupColor colors[256];
+
+ if (bpp == 32 || bpp == 24)
+ colors_count = 0;
+ else /* bpp == 8 */
+ iupImageInitColorTable(ih, colors, &colors_count);
+
+ bmih = malloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*colors_count);
+ if (!bmih)
+ return NULL;
+
+ memset(bmih, 0, sizeof(BITMAPINFOHEADER));
+ bmih->biSize = sizeof(BITMAPINFOHEADER);
+ bmih->biWidth = width;
+ bmih->biHeight = height;
+ bmih->biPlanes = 1; /* not the same as PLANES */
+ bmih->biBitCount = (WORD)bpp;
+ bmih->biCompression = BI_RGB;
+ bmih->biClrUsed = colors_count;
+
+ if (colors_count)
+ {
+ /* since colors are only passed to the CreateDIBSection here, must update BGCOLOR and inactive here */
+ RGBQUAD* bitmap_colors = (RGBQUAD*)(((BYTE*)bmih) + sizeof(BITMAPINFOHEADER));
+ if (winImageInitDibColors(colors, bitmap_colors, colors_count, bg_r, bg_g, bg_b, make_inactive))
+ iupAttribSetStr(ih, "_IUP_BGCOLOR_DEPEND", "1");
+ }
+
+ hDC = GetDC(NULL);
+ hBitmap = CreateDIBSection(hDC, (BITMAPINFO*)bmih, DIB_RGB_COLORS, (void**)bits, NULL, 0x0);
+ ReleaseDC(NULL, hDC);
+ free(bmih);
+
+ return hBitmap;
+}
+
+void* iupdrvImageCreateImage(Ihandle *ih, const char* bgcolor, int make_inactive)
+{
+ unsigned char bg_r = 0, bg_g = 0, bg_b = 0;
+ int y,x,bmp_line_size,data_line_size,
+ width = ih->currentwidth,
+ height = ih->currentheight,
+ channels = iupAttribGetInt(ih, "CHANNELS"),
+ flat_alpha = iupAttribGetBoolean(ih, "FLAT_ALPHA"),
+ bpp = iupAttribGetInt(ih, "BPP");
+ unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID");
+ HBITMAP hBitmap;
+ BYTE* bits; /* DIB bitmap bits, created in CreateDIBSection and filled here */
+
+ iupStrToRGB(bgcolor, &bg_r, &bg_g, &bg_b);
+
+ hBitmap = winImageCreateBitmap(ih, width, height, bpp, &bits, bg_r, bg_g, bg_b, make_inactive);
+ if (!hBitmap)
+ return NULL;
+
+ bmp_line_size = ((width * bpp + 31) / 32) * 4; /* DWORD aligned, 4 bytes boundary in a N bpp image */
+ data_line_size = width*channels;
+
+ /* windows bitmaps are bottom up */
+ imgdata += (height-1)*data_line_size; /* iupimage is top down */
+
+ for (y=0; y<height; y++)
+ {
+ for (x=0; x<width; x++)
+ {
+ if (bpp != 8) /* (bpp == 32 || bpp == 24) */
+ {
+ int offset = channels*x;
+ /* Windows Bitmap order is BGRA */
+ BYTE *b = &bits[offset],
+ *g = b+1,
+ *r = g+1,
+ *a = r+1,
+ *dat = &imgdata[offset];
+
+ *r = *(dat);
+ *g = *(dat+1);
+ *b = *(dat+2);
+
+ if (channels == 4) /* bpp==32 */
+ {
+ if (flat_alpha)
+ {
+ *a = *(dat+3);
+ *r = iupALPHABLEND(*r, bg_r, *a);
+ *g = iupALPHABLEND(*g, bg_g, *a);
+ *b = iupALPHABLEND(*b, bg_b, *a);
+ *a = 255;
+ }
+
+ if (make_inactive)
+ iupImageColorMakeInactive(r, g, b, bg_r, bg_g, bg_b);
+
+ if (!flat_alpha)
+ {
+ *a = *(dat+3);
+
+ /* RGB in RGBA DIBs are pre-multiplied by alpha to AlphaBlend usage. */
+ *r = iupALPHAPRE(*r,*a);
+ *g = iupALPHAPRE(*g,*a);
+ *b = iupALPHAPRE(*b,*a);
+ }
+ }
+ }
+ else /* bpp == 8 */
+ {
+ bits[x] = imgdata[x];
+ }
+ }
+
+ bits += bmp_line_size;
+ imgdata -= data_line_size; /* iupimage is top down */
+ }
+
+ if (make_inactive || (channels == 4 && flat_alpha))
+ iupAttribSetStr(ih, "_IUP_BGCOLOR_DEPEND", "1");
+
+ return hBitmap;
+}
+
+static HBITMAP winImageCreateBitmask(Ihandle *ih, int invert)
+{
+ int y, x, mask_line_size,data_line_size, colors_count, set,
+ width = ih->currentwidth,
+ height = ih->currentheight,
+ channels = iupAttribGetInt(ih, "CHANNELS"),
+ bpp = iupAttribGetInt(ih, "BPP");
+ unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID");
+ HBITMAP hBitmap;
+ BYTE* bitmask, *bitmask_ptr;
+ iupColor colors[256];
+
+ if (bpp == 8)
+ iupImageInitColorTable(ih, colors, &colors_count);
+
+ mask_line_size = ((width + 15) / 16) * 2; /* WORD aligned, 2 bytes boundary in a 1 bpp image */
+ data_line_size = width*channels;
+
+ bitmask = malloc(height * mask_line_size);
+ memset(bitmask, 0, height * mask_line_size); /* opaque */
+
+ /* mask and iupimage are top down */
+
+ bitmask_ptr = bitmask;
+ for (y=0; y<height; y++)
+ {
+ for (x=0; x<width; x++)
+ {
+ set = 0;
+
+ if (bpp == 32)
+ {
+ BYTE* dat = &imgdata[channels*x];
+ if (*(dat+3) == 0) /* full transparent alpha */
+ set = 1;
+ }
+ else if (bpp == 8)
+ {
+ unsigned char index = imgdata[x];
+ if (colors[index].a == 0) /* full transparent alpha */
+ set = 1;
+ }
+
+ if (set)
+ bitmask_ptr[x/8] |= 1 << (7 - (x % 8)); /* set transparent mask bit */
+ }
+
+ bitmask_ptr += mask_line_size;
+ imgdata += data_line_size;
+ }
+
+ if (invert)
+ {
+ int k, size = height * mask_line_size;
+ for (k = 0; k < size; k++)
+ bitmask[k] = ~bitmask[k];
+ }
+
+ hBitmap = CreateBitmap(width, height, 1, 1, bitmask);
+ free(bitmask);
+ return hBitmap;
+}
+
+static HICON winImageCreateIcon(Ihandle *ih, int is_cursor)
+{
+ HBITMAP hBitmap, hBitmapMask;
+ ICONINFO iconinfo;
+ HICON icon;
+ char* color0 = NULL;
+
+ /* If cursor and no transparency defined, assume 0 if transparent.
+ We do this only in Windows and because of backward compatibility. */
+ if (is_cursor)
+ {
+ int bpp = iupAttribGetInt(ih, "BPP");
+ if (bpp == 8)
+ {
+ if (!iupStrEqual(iupAttribGet(ih, "0"), "BGCOLOR") &&
+ !iupStrEqual(iupAttribGet(ih, "1"), "BGCOLOR") &&
+ !iupStrEqual(iupAttribGet(ih, "2"), "BGCOLOR"))
+ {
+ color0 = iupStrDup(iupAttribGet(ih, "0"));
+ iupAttribSetStr(ih, "0", "BGCOLOR");
+ }
+ }
+ }
+
+ hBitmap = iupdrvImageCreateImage(ih, NULL, 0);
+ if (!hBitmap)
+ {
+ if (color0) free(color0);
+ return NULL;
+ }
+
+ /* Transparency mask */
+ hBitmapMask = winImageCreateBitmask(ih, 0);
+ if (!hBitmapMask)
+ {
+ DeleteObject(hBitmap);
+ if (color0) free(color0);
+ return NULL;
+ }
+
+ /* destination = (destination AND bitmask) XOR bitmap */
+ iconinfo.hbmMask = hBitmapMask; /* AND */
+ iconinfo.hbmColor = hBitmap; /* XOR */
+
+ if (is_cursor)
+ {
+ int x=0,y=0;
+ iupStrToIntInt(iupAttribGet(ih, "HOTSPOT"), &x, &y, ':');
+
+ iconinfo.xHotspot = x;
+ iconinfo.yHotspot = y;
+ iconinfo.fIcon = FALSE;
+ }
+ else
+ iconinfo.fIcon = TRUE;
+
+ icon = CreateIconIndirect(&iconinfo);
+
+ DeleteObject(hBitmap);
+ DeleteObject(hBitmapMask);
+
+ if (color0)
+ {
+ iupAttribStoreStr(ih, "0", color0);
+ free(color0);
+ }
+
+ return icon;
+}
+
+void* iupdrvImageCreateIcon(Ihandle *ih)
+{
+ return winImageCreateIcon(ih, 0);
+}
+
+void* iupdrvImageCreateCursor(Ihandle *ih)
+{
+ return winImageCreateIcon(ih, 1);
+}
+
+void* iupdrvImageCreateMask(Ihandle *ih)
+{
+ int invert = 1;
+ if (!ih) return NULL;
+ if (iupAttribGet(ih, "_IUPIMG_NO_INVERT")) invert = 0;
+ return (void*)winImageCreateBitmask(ih, invert);
+}
+
+void* iupdrvImageLoad(const char* name, int type)
+{
+ int iup2win[3] = {IMAGE_BITMAP, IMAGE_ICON, IMAGE_CURSOR};
+ HANDLE hImage = LoadImage(iupwin_hinstance, (LPCTSTR)name, iup2win[type], 0, 0, type==0?LR_CREATEDIBSECTION:0);
+ if (!hImage && iupwin_dll_hinstance)
+ hImage = LoadImage(iupwin_dll_hinstance, (LPCTSTR)name, iup2win[type], 0, 0, type==0?LR_CREATEDIBSECTION:0);
+ if (!hImage)
+ hImage = LoadImage(NULL, (LPCTSTR)name, iup2win[type], 0, 0, LR_LOADFROMFILE|(type==0?LR_CREATEDIBSECTION:0));
+ return hImage;
+}
+
+int iupdrvImageGetInfo(void* handle, int *w, int *h, int *bpp)
+{
+ BITMAP bm;
+ if (!GetObject((HBITMAP)handle, sizeof(BITMAP), (LPSTR)&bm))
+ {
+ if (w) *w = 0;
+ if (h) *h = 0;
+ if (bpp) *bpp = 0;
+ return 0;
+ }
+ if (w) *w = bm.bmWidth;
+ if (h) *h = abs(bm.bmHeight);
+ if (bpp) *bpp = iupImageNormBpp(bm.bmBitsPixel*bm.bmPlanes);
+ return 1;
+}
+
+void iupdrvImageDestroy(void* handle, int type)
+{
+ switch (type)
+ {
+ case IUPIMAGE_IMAGE:
+ if (GetObjectType((HBITMAP)handle)==OBJ_BITMAP)
+ DeleteObject((HBITMAP)handle);
+ else
+ GlobalFree((HANDLE)handle);
+ break;
+ case IUPIMAGE_ICON:
+ DestroyIcon((HICON)handle);
+ break;
+ case IUPIMAGE_CURSOR:
+ DestroyCursor((HCURSOR)handle);
+ break;
+ }
+}
+
diff --git a/iup/src/win/iupwin_info.c b/iup/src/win/iupwin_info.c
new file mode 100755
index 0000000..8ea7dd4
--- /dev/null
+++ b/iup/src/win/iupwin_info.c
@@ -0,0 +1,277 @@
+/** \file
+ * \brief Windows System Information
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <windows.h>
+#include <uxtheme.h>
+
+#include "iup.h"
+
+#include "iup_str.h"
+#include "iup_drv.h"
+
+#include "iupwin_info.h"
+
+
+int iupwinIsVista(void)
+{
+ OSVERSIONINFO osvi;
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&osvi);
+
+ if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion >= 6)
+ return 1;
+
+ return 0;
+}
+
+int iupwinGetSystemMajorVersion(void)
+{
+ OSVERSIONINFO osvi;
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&osvi);
+ return osvi.dwMajorVersion;
+}
+
+char *iupwinGetSystemLanguage(void)
+{
+ LANGID id = GetSystemDefaultUILanguage();
+ char *lang = NULL;
+ switch(id)
+ {
+ case 0x0000: lang = "Language Neutral"; break;
+ case 0x007f: lang = "Locale Invariant"; break;
+ case 0x0400: lang = "User Default Language"; break;
+ case 0x0800: lang = "System Default Language"; break;
+ case 0x0436: lang = "Afrikaans"; break;
+ case 0x041c: lang = "Albanian"; break;
+ case 0x0401: lang = "Arabic (Saudi Arabia)"; break;
+ case 0x0801: lang = "Arabic (Iraq)"; break;
+ case 0x0c01: lang = "Arabic (Egypt)"; break;
+ case 0x1001: lang = "Arabic (Libya)"; break;
+ case 0x1401: lang = "Arabic (Algeria)"; break;
+ case 0x1801: lang = "Arabic (Morocco)"; break;
+ case 0x1c01: lang = "Arabic (Tunisia)"; break;
+ case 0x2001: lang = "Arabic (Oman)"; break;
+ case 0x2401: lang = "Arabic (Yemen)"; break;
+ case 0x2801: lang = "Arabic (Syria)"; break;
+ case 0x2c01: lang = "Arabic (Jordan)"; break;
+ case 0x3001: lang = "Arabic (Lebanon)"; break;
+ case 0x3401: lang = "Arabic (Kuwait)"; break;
+ case 0x3801: lang = "Arabic (U.A.E.)"; break;
+ case 0x3c01: lang = "Arabic (Bahrain)"; break;
+ case 0x4001: lang = "Arabic (Qatar)"; break;
+ case 0x042b: lang = "Armenian"; break;
+ case 0x042c: lang = "Azeri (Latin)"; break;
+ case 0x082c: lang = "Azeri (Cyrillic)"; break;
+ case 0x042d: lang = "Basque"; break;
+ case 0x0423: lang = "Belarusian"; break;
+ case 0x0402: lang = "Bulgarian"; break;
+ case 0x0455: lang = "Burmese"; break;
+ case 0x0403: lang = "Catalan"; break;
+ case 0x0404: lang = "Chinese (Taiwan)"; break;
+ case 0x0804: lang = "Chinese"; break;
+ case 0x0c04: lang = "Chinese (Hong Kong)"; break;
+ case 0x1004: lang = "Chinese (Singapore)"; break;
+ case 0x1404: lang = "Chinese (Macau)"; break;
+ case 0x041a: lang = "Croatian"; break;
+ case 0x0405: lang = "Czech"; break;
+ case 0x0406: lang = "Danish"; break;
+ case 0x0465: lang = "Divehi"; break;
+ case 0x0413: lang = "Dutch (Netherlands)"; break;
+ case 0x0813: lang = "Dutch (Belgium)"; break;
+ case 0x0409: lang = "English (United States)"; break;
+ case 0x0809: lang = "English (United Kingdom)"; break;
+ case 0x0c09: lang = "English (Australian)"; break;
+ case 0x1009: lang = "English (Canadian)"; break;
+ case 0x1409: lang = "English (New Zealand)"; break;
+ case 0x1809: lang = "English (Ireland)"; break;
+ case 0x1c09: lang = "English (South Africa)"; break;
+ case 0x2009: lang = "English (Jamaica)"; break;
+ case 0x2409: lang = "English (Caribbean)"; break;
+ case 0x2809: lang = "English (Belize)"; break;
+ case 0x2c09: lang = "English (Trinidad)"; break;
+ case 0x3009: lang = "English (Zimbabwe)"; break;
+ case 0x3409: lang = "English (Philippines)"; break;
+ case 0x0425: lang = "Estonian"; break;
+ case 0x0438: lang = "Faeroese"; break;
+ case 0x0429: lang = "Farsi"; break;
+ case 0x040b: lang = "Finnish"; break;
+ case 0x040c: lang = "French (Standard)"; break;
+ case 0x080c: lang = "French (Belgian)"; break;
+ case 0x0c0c: lang = "French (Canadian)"; break;
+ case 0x100c: lang = "French (Switzerland)"; break;
+ case 0x140c: lang = "French (Luxembourg)"; break;
+ case 0x180c: lang = "French (Monaco)"; break;
+ case 0x0456: lang = "Galician"; break;
+ case 0x0437: lang = "Georgian"; break;
+ case 0x0407: lang = "German (Standard)"; break;
+ case 0x0807: lang = "German (Switzerland)"; break;
+ case 0x0c07: lang = "German (Austria)"; break;
+ case 0x1007: lang = "German (Luxembourg)"; break;
+ case 0x1407: lang = "German (Liechtenstein)"; break;
+ case 0x0408: lang = "Greek"; break;
+ case 0x0447: lang = "Gujarati"; break;
+ case 0x040d: lang = "Hebrew"; break;
+ case 0x0439: lang = "Hindi"; break;
+ case 0x040e: lang = "Hungarian"; break;
+ case 0x040f: lang = "Icelandic"; break;
+ case 0x0421: lang = "Indonesian"; break;
+ case 0x0410: lang = "Italian (Standard)"; break;
+ case 0x0810: lang = "Italian (Switzerland)"; break;
+ case 0x0411: lang = "Japanese"; break;
+ case 0x044b: lang = "Kannada"; break;
+ case 0x0457: lang = "Konkani"; break;
+ case 0x0412: lang = "Korean"; break;
+ case 0x0812: lang = "Korean (Johab)"; break;
+ case 0x0440: lang = "Kyrgyz"; break;
+ case 0x0426: lang = "Latvian"; break;
+ case 0x0427: lang = "Lithuanian"; break;
+ case 0x0827: lang = "Lithuanian (Classic)"; break;
+ case 0x042f: lang = "Macedonian"; break;
+ case 0x043e: lang = "Malay (Malaysian)"; break;
+ case 0x083e: lang = "Malay (Brunei Darussalam)"; break;
+ case 0x044e: lang = "Marathi"; break;
+ case 0x0450: lang = "Mongolian"; break;
+ case 0x0414: lang = "Norwegian (Bokmal)"; break;
+ case 0x0814: lang = "Norwegian (Nynorsk)"; break;
+ case 0x0415: lang = "Polish"; break;
+ case 0x0416: lang = "Portuguese (Brazil)"; break;
+ case 0x0816: lang = "Portuguese (Portugal)"; break;
+ case 0x0446: lang = "Punjabi"; break;
+ case 0x0418: lang = "Romanian"; break;
+ case 0x0419: lang = "Russian"; break;
+ case 0x044f: lang = "Sanskrit"; break;
+ case 0x0c1a: lang = "Serbian (Cyrillic)"; break;
+ case 0x081a: lang = "Serbian (Latin)"; break;
+ case 0x041b: lang = "Slovak"; break;
+ case 0x0424: lang = "Slovenian"; break;
+ case 0x040a: lang = "Spanish (Spain, Traditional Sort)"; break;
+ case 0x080a: lang = "Spanish (Mexican)"; break;
+ case 0x0c0a: lang = "Spanish (Spain, International Sort)"; break;
+ case 0x100a: lang = "Spanish (Guatemala)"; break;
+ case 0x140a: lang = "Spanish (Costa Rica)"; break;
+ case 0x180a: lang = "Spanish (Panama)"; break;
+ case 0x1c0a: lang = "Spanish (Dominican Republic)"; break;
+ case 0x200a: lang = "Spanish (Venezuela)"; break;
+ case 0x240a: lang = "Spanish (Colombia)"; break;
+ case 0x280a: lang = "Spanish (Peru)"; break;
+ case 0x2c0a: lang = "Spanish (Argentina)"; break;
+ case 0x300a: lang = "Spanish (Ecuador)"; break;
+ case 0x340a: lang = "Spanish (Chile)"; break;
+ case 0x380a: lang = "Spanish (Uruguay)"; break;
+ case 0x3c0a: lang = "Spanish (Paraguay)"; break;
+ case 0x400a: lang = "Spanish (Bolivia)"; break;
+ case 0x440a: lang = "Spanish (El Salvador)"; break;
+ case 0x480a: lang = "Spanish (Honduras)"; break;
+ case 0x4c0a: lang = "Spanish (Nicaragua)"; break;
+ case 0x500a: lang = "Spanish (Puerto Rico)"; break;
+ case 0x0430: lang = "Sutu"; break;
+ case 0x0441: lang = "Swahili (Kenya)"; break;
+ case 0x041d: lang = "Swedish"; break;
+ case 0x081d: lang = "Swedish (Finland)"; break;
+ case 0x045a: lang = "Syriac"; break;
+ case 0x0449: lang = "Tamil"; break;
+ case 0x0444: lang = "Tatar (Tatarstan)"; break;
+ case 0x044a: lang = "Telugu"; break;
+ case 0x041e: lang = "Thai"; break;
+ case 0x041f: lang = "Turkish"; break;
+ case 0x0422: lang = "Ukrainian"; break;
+ case 0x0420: lang = "Urdu (Pakistan)"; break;
+ case 0x0820: lang = "Urdu (India)"; break;
+ case 0x0443: lang = "Uzbek (Latin)"; break;
+ case 0x0843: lang = "Uzbek (Cyrillic)"; break;
+ case 0x042a: lang = "Vietnamese"; break;
+ }
+ return lang;
+}
+
+#define PACKVERSION(major,minor) MAKELONG(minor,major)
+typedef struct _DLLVERSIONINFO
+{
+ DWORD cbSize;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ DWORD dwBuildNumber;
+ DWORD dwPlatformID;
+} DLLVERSIONINFO;
+typedef HRESULT (CALLBACK* DLLGETVERSIONPROC)(DLLVERSIONINFO *);
+
+static DWORD winGetDllVersion(LPCTSTR lpszDllName)
+{
+ HINSTANCE hinstDll;
+ DWORD dwVersion = 0;
+
+ /* For security purposes, LoadLibrary should be provided with a
+ fully-qualified path to the DLL. The lpszDllName variable should be
+ tested to ensure that it is a fully qualified path before it is used. */
+ hinstDll = LoadLibrary(lpszDllName);
+
+ if (hinstDll)
+ {
+ DLLGETVERSIONPROC pDllGetVersion;
+ pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinstDll, "DllGetVersion");
+
+ /* Because some DLLs might not implement this function, you
+ must test for it explicitly. Depending on the particular
+ DLL, the lack of a DllGetVersion function can be a useful
+ indicator of the version. */
+
+ if (pDllGetVersion)
+ {
+ DLLVERSIONINFO dvi;
+ HRESULT hr;
+
+ ZeroMemory(&dvi, sizeof(dvi));
+ dvi.cbSize = sizeof(dvi);
+
+ hr = pDllGetVersion(&dvi);
+ if (SUCCEEDED(hr))
+ dwVersion = PACKVERSION(dvi.dwMajorVersion, dvi.dwMinorVersion);
+ }
+
+ FreeLibrary(hinstDll);
+ }
+
+ return dwVersion;
+}
+
+int iupwinGetComCtl32Version(void)
+{
+ return winGetDllVersion(TEXT("comctl32.dll"));
+}
+
+void iupwinGetSysColor(char* color, int wincolor)
+{
+ COLORREF syscolor = GetSysColor(wincolor);
+ sprintf(color, "%d %d %d", (int)GetRValue(syscolor), (int)GetGValue(syscolor), (int)GetBValue(syscolor));
+}
+
+char* iupwinGetSystemFgColor(void)
+{
+ static char def_fgcolor[50];
+ iupwinGetSysColor(def_fgcolor, COLOR_WINDOWTEXT);
+ return def_fgcolor;
+}
+
+int iupwinIsAppThemed(void)
+{
+ typedef BOOL (STDAPICALLTYPE *winIsAppThemed)(void);
+ static winIsAppThemed myIsAppThemed = NULL;
+ if (!myIsAppThemed)
+ {
+ HMODULE hinstDll = LoadLibrary("uxtheme.dll");
+ if (hinstDll)
+ myIsAppThemed = (winIsAppThemed)GetProcAddress(hinstDll, "IsAppThemed");
+ }
+
+ if (myIsAppThemed)
+ return myIsAppThemed();
+ else
+ return 0;
+}
diff --git a/iup/src/win/iupwin_info.h b/iup/src/win/iupwin_info.h
new file mode 100755
index 0000000..d39bae0
--- /dev/null
+++ b/iup/src/win/iupwin_info.h
@@ -0,0 +1,29 @@
+/** \file
+ * \brief Windows System Information
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#ifndef __IUPWIN_INFO_H
+#define __IUPWIN_INFO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* system */
+int iupwinGetSystemMajorVersion(void);
+int iupwinGetComCtl32Version(void);
+char* iupwinGetSystemLanguage(void);
+int iupwinIsAppThemed(void);
+int iupwinIsVista(void);
+
+/* color */
+void iupwinGetSysColor(char* color, int wincolor);
+char* iupwinGetSystemFgColor(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/iup/src/win/iupwin_key.c b/iup/src/win/iupwin_key.c
new file mode 100755
index 0000000..921ed94
--- /dev/null
+++ b/iup/src/win/iupwin_key.c
@@ -0,0 +1,348 @@
+/** \file
+ * \brief Windows Driver keyboard mapping
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+
+#include <windows.h>
+
+#include "iup.h"
+#include "iupkey.h"
+
+#include "iup_object.h"
+#include "iup_key.h"
+
+#include "iupwin_drv.h"
+
+
+#ifndef VK_OEM_PLUS
+#define VK_OEM_PLUS 0xBB /* '+' any country */
+#define VK_OEM_COMMA 0xBC /* ',' any country */
+#define VK_OEM_MINUS 0xBD /* '-' any country */
+#define VK_OEM_PERIOD 0xBE /* '.' any country */
+#define VK_OEM_102 0xE2 /* "<>" or "\|" on RT 102-key kbd. */
+#endif
+
+typedef struct _Iwin2iupkey
+{
+ int wincode;
+ int iupcode;
+ int s_iupcode;
+ int c_iupcode;
+ int m_iupcode;
+ int y_iupcode;
+} Iwin2iupkey;
+
+static Iwin2iupkey winkey_map[] = {
+
+{ VK_ESCAPE, K_ESC, K_sESC, K_cESC, K_mESC, K_yESC },
+{ VK_PAUSE, K_PAUSE, K_sPAUSE, K_cPAUSE, K_mPAUSE, K_yPAUSE },
+{ VK_SNAPSHOT, K_Print, K_sPrint, K_cPrint, K_mPrint, K_yPrint },
+{ VK_APPS, K_Menu, K_sMenu, K_cMenu, K_mMenu, K_yMenu },
+
+{ VK_HOME, K_HOME, K_sHOME, K_cHOME, K_mHOME, K_yHOME },
+{ VK_UP, K_UP, K_sUP, K_cUP, K_mUP, K_yUP },
+{ VK_PRIOR, K_PGUP, K_sPGUP, K_cPGUP, K_mPGUP, K_yPGUP },
+{ VK_LEFT, K_LEFT, K_sLEFT, K_cLEFT, K_mLEFT, K_yLEFT },
+{ VK_CLEAR, K_MIDDLE,K_sMIDDLE, K_cMIDDLE,K_mMIDDLE,K_yMIDDLE},
+{ VK_RIGHT, K_RIGHT, K_sRIGHT, K_cRIGHT, K_mRIGHT, K_yRIGHT },
+{ VK_END, K_END, K_sEND, K_cEND, K_mEND, K_yEND },
+{ VK_DOWN, K_DOWN, K_sDOWN, K_cDOWN, K_mDOWN, K_yDOWN },
+{ VK_NEXT, K_PGDN, K_sPGDN, K_cPGDN, K_mPGDN, K_yPGDN },
+{ VK_INSERT, K_INS, K_sINS, K_cINS, K_mINS, K_yINS },
+{ VK_DELETE, K_DEL, K_sDEL, K_cDEL, K_mDEL, K_yDEL },
+{ VK_SPACE, K_SP, K_sSP, K_cSP, K_mSP, K_ySP },
+{ VK_TAB, K_TAB, K_sTAB, K_cTAB, K_mTAB, K_yTAB },
+{ VK_RETURN, K_CR, K_sCR, K_cCR, K_mCR, K_yCR },
+{ VK_BACK, K_BS, K_sBS, K_cBS, K_mBS, K_yBS },
+
+/* VK_0 - VK_9 are the same as ASCII '0' - '9' (0x30 - 0x39) */
+{ '1', K_1, K_exclam, K_c1, K_m1, K_y1 },
+{ '2', K_2, K_at, K_c2, K_m2, K_y2 },
+{ '3', K_3, K_numbersign, K_c3, K_m3, K_y3 },
+{ '4', K_4, K_dollar, K_c4, K_m4, K_y4 },
+{ '5', K_5, K_percent, K_c5, K_m5, K_y5 },
+{ '6', K_6, K_circum, K_c6, K_m6, K_y6 },
+{ '7', K_7, K_ampersand, K_c7, K_m7, K_y7 },
+{ '8', K_8, K_asterisk, K_c8, K_m8, K_y8 },
+{ '9', K_9, K_parentleft, K_c9, K_m9, K_y9 },
+{ '0', K_0, K_parentright, K_c0, K_m0, K_y0 },
+
+/* VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A) */
+{ 'A', K_a, K_A, K_cA, K_mA, K_yA},
+{ 'B', K_b, K_B, K_cB, K_mB, K_yB},
+{ 'C', K_c, K_C, K_cC, K_mC, K_yC},
+{ 'D', K_d, K_D, K_cD, K_mD, K_yD},
+{ 'E', K_e, K_E, K_cE, K_mE, K_yE},
+{ 'F', K_f, K_F, K_cF, K_mF, K_yF},
+{ 'G', K_g, K_G, K_cG, K_mG, K_yG},
+{ 'H', K_h, K_H, K_cH, K_mH, K_yH},
+{ 'I', K_i, K_I, K_cI, K_mI, K_yI},
+{ 'J', K_j, K_J, K_cJ, K_mJ, K_yJ},
+{ 'K', K_k, K_K, K_cK, K_mK, K_yK},
+{ 'L', K_l, K_L, K_cL, K_mL, K_yL},
+{ 'M', K_m, K_M, K_cM, K_mM, K_yM},
+{ 'N', K_n, K_N, K_cN, K_mN, K_yN},
+{ 'O', K_o, K_O, K_cO, K_mO, K_yO},
+{ 'P', K_p, K_P, K_cP, K_mP, K_yP},
+{ 'Q', K_q, K_Q, K_cQ, K_mQ, K_yQ},
+{ 'R', K_r, K_R, K_cR, K_mR, K_yR},
+{ 'S', K_s, K_S, K_cS, K_mS, K_yS},
+{ 'T', K_t, K_T, K_cT, K_mT, K_yT},
+{ 'U', K_u, K_U, K_cU, K_mU, K_yU},
+{ 'V', K_v, K_V, K_cV, K_mV, K_yV},
+{ 'W', K_w, K_W, K_cW, K_mW, K_yW},
+{ 'X', K_x, K_X, K_cX, K_mX, K_yX},
+{ 'Y', K_y, K_Y, K_cY, K_mY, K_yY},
+{ 'Z', K_z, K_Z, K_cZ, K_mZ, K_yZ},
+
+{ VK_F1, K_F1, K_sF1, K_cF1, K_mF1, K_yF1 },
+{ VK_F2, K_F2, K_sF2, K_cF2, K_mF2, K_yF2 },
+{ VK_F3, K_F3, K_sF3, K_cF3, K_mF3, K_yF3 },
+{ VK_F4, K_F4, K_sF4, K_cF4, K_mF4, K_yF4 },
+{ VK_F5, K_F5, K_sF5, K_cF5, K_mF5, K_yF5 },
+{ VK_F6, K_F6, K_sF6, K_cF6, K_mF6, K_yF6 },
+{ VK_F7, K_F7, K_sF7, K_cF7, K_mF7, K_yF7 },
+{ VK_F8, K_F8, K_sF8, K_cF8, K_mF8, K_yF8 },
+{ VK_F9, K_F9, K_sF9, K_cF9, K_mF9, K_yF9 },
+{ VK_F10, K_F10, K_sF10, K_cF10, K_mF10, K_yF10 },
+{ VK_F11, K_F11, K_sF11, K_cF11, K_mF11, K_yF11 },
+{ VK_F12, K_F12, K_sF12, K_cF12, K_mF12, K_yF12 },
+
+{ VK_OEM_1, K_semicolon, K_colon, K_cSemicolon, K_mSemicolon, K_ySemicolon },
+{ VK_OEM_PLUS, K_equal, K_plus, K_cEqual, K_mEqual, K_yEqual },
+{ VK_OEM_COMMA, K_comma, K_less, K_cComma, K_mComma, K_yComma },
+{ VK_OEM_MINUS, K_minus, K_underscore, K_cMinus, K_mMinus, K_yMinus },
+{ VK_OEM_PERIOD, K_period, K_greater, K_cPeriod, K_mPeriod, K_yPeriod },
+{ VK_OEM_2, K_slash, K_question, K_cSlash, K_mSlash, K_ySlash },
+{ VK_OEM_3, K_grave, K_tilde, 0, 0, 0 },
+{ VK_OEM_4, K_bracketleft, K_braceleft, K_cBracketleft, K_mBracketleft, K_yBracketleft },
+{ VK_OEM_5, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash },
+{ VK_OEM_6, K_bracketright, K_braceright, K_cBracketright,K_mBracketright,K_yBracketright },
+{ VK_OEM_7, K_apostrophe, K_quotedbl, 0, 0, 0 },
+{ VK_OEM_102, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash },
+
+{ VK_NUMPAD0, K_0, K_0, K_c0, K_m0, K_y0 },
+{ VK_NUMPAD1, K_1, K_1, K_c1, K_m1, K_y1 },
+{ VK_NUMPAD2, K_2, K_2, K_c2, K_m2, K_y2 },
+{ VK_NUMPAD3, K_3, K_3, K_c3, K_m3, K_y3 },
+{ VK_NUMPAD4, K_4, K_4, K_c4, K_m4, K_y4 },
+{ VK_NUMPAD5, K_5, K_5, K_c5, K_m5, K_y5 },
+{ VK_NUMPAD6, K_6, K_6, K_c6, K_m6, K_y6 },
+{ VK_NUMPAD7, K_7, K_7, K_c7, K_m7, K_y7 },
+{ VK_NUMPAD8, K_8, K_8, K_c8, K_m8, K_y8 },
+{ VK_NUMPAD9, K_9, K_9, K_c9, K_m9, K_y9 },
+{ VK_MULTIPLY, K_asterisk, K_sAsterisk, K_cAsterisk, K_mAsterisk, K_yAsterisk },
+{ VK_ADD, K_plus, K_sPlus, K_cPlus, K_mPlus, K_yPlus },
+{ VK_SUBTRACT, K_minus, K_sMinus, K_cMinus, K_mMinus, K_yMinus },
+{ VK_DECIMAL, K_period, K_sPeriod, K_cPeriod, K_mPeriod, K_yPeriod },
+{ VK_DIVIDE, K_slash, K_sSlash, K_cSlash, K_mSlash, K_ySlash },
+{ VK_SEPARATOR, K_comma, K_sComma, K_cComma, K_mComma, K_yComma }
+};
+
+static Iwin2iupkey keytable_abnt[] = {
+{ '1', K_1, K_exclam, K_c1, K_m1, K_y1 },
+{ '2', K_2, K_at, K_c2, K_m2, K_y2 },
+{ '3', K_3, K_numbersign, K_c3, K_m3, K_y3 },
+{ '4', K_4, K_dollar, K_c4, K_m4, K_y4 },
+{ '5', K_5, K_percent, K_c5, K_m5, K_y5 },
+{ '6', K_6, K_circum, K_c6, K_m6, K_y6 },
+
+{ VK_OEM_1, K_ccedilla, K_Ccedilla, K_cCcedilla, K_mCcedilla, K_yCcedilla },
+{ VK_OEM_2, K_semicolon, K_colon, K_cSemicolon, K_mSemicolon, K_ySemicolon },
+{ VK_OEM_3, K_apostrophe, K_quotedbl, 0, 0, 0 },
+{ VK_OEM_4, K_acute, K_grave, 0, 0, 0 },
+{ VK_OEM_5, K_bracketright, K_braceright, K_cBracketleft, K_mBracketleft, K_yBracketleft },
+{ VK_OEM_6, K_bracketleft, K_braceleft, K_cBracketright, K_mBracketright, K_yBracketright },
+{ VK_OEM_7, K_tilde, K_circum, 0, 0, 0 },
+{ VK_OEM_102, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash },
+{ VK_OEM_PLUS, K_equal, K_plus, K_cEqual, K_mEqual, K_yEqual },
+{ 0xC1, K_slash, K_question, K_cSlash, K_mSlash, K_ySlash },
+{ 0xC2, K_period, K_sPeriod, K_cPeriod, K_mPeriod, K_yPeriod },
+{ VK_SEPARATOR,K_period, K_sPeriod, K_cPeriod, K_mPeriod, K_yPeriod },
+{ VK_DECIMAL, K_comma, K_sComma, K_cComma, K_mComma, K_yComma }
+};
+
+
+void iupwinKeyEncode(int key, unsigned int *keyval, unsigned int *state)
+{
+ int i, iupcode = key & 0xFF; /* 0-255 interval */
+ int count = sizeof(winkey_map)/sizeof(winkey_map[0]);
+ for (i = 0; i < count; i++)
+ {
+ Iwin2iupkey* key_map = &(winkey_map[i]);
+ if (key_map->iupcode == iupcode)
+ {
+ *keyval = key_map->wincode;
+ *state = 0;
+
+ if (iupcode != key)
+ {
+ if (key_map->c_iupcode == key)
+ *state = VK_CONTROL;
+ else if (key_map->m_iupcode == key)
+ *state = VK_MENU;
+ else if (key_map->y_iupcode == key)
+ *state = VK_LWIN;
+ else if (key_map->s_iupcode == key)
+ *state = VK_SHIFT;
+ }
+ return;
+ }
+ else if (key_map->s_iupcode == key) /* There are Shift keys bellow 256 */
+ {
+ *keyval = key_map->wincode;
+ *state = VK_SHIFT;
+ return;
+ }
+ }
+}
+
+static int winKeyMap2Iup(Iwin2iupkey* table, int i)
+{
+ int code = 0;
+ if (GetKeyState(VK_CONTROL) & 0x8000)
+ code = table[i].c_iupcode;
+ else if (GetKeyState(VK_MENU) & 0x8000)
+ code = table[i].m_iupcode;
+ else if ((GetKeyState(VK_LWIN) & 0x8000) || (GetKeyState(VK_RWIN) & 0x8000))
+ code = table[i].y_iupcode;
+ else if (GetKeyState(VK_CAPITAL) & 0x01) /* if it's on */
+ {
+ if ((GetKeyState(VK_SHIFT) & 0x8000) || !iupKeyCanCaps(table[i].iupcode))
+ return table[i].iupcode;
+ else
+ code = table[i].s_iupcode;
+ }
+ else if (GetKeyState(VK_SHIFT) & 0x8000)
+ code = table[i].s_iupcode;
+ else
+ return table[i].iupcode;
+
+ if (!code)
+ code = table[i].iupcode;
+
+ return code;
+}
+
+static int winKeyDecode(int wincode)
+{
+ HKL k;
+ int i, count;
+
+ k = GetKeyboardLayout(0);
+ if ((int)HIWORD(k) == 0x0416) /* ABNT */
+ {
+ int abnt_count = sizeof(keytable_abnt)/sizeof(keytable_abnt[0]);
+ for (i = 0; i < abnt_count; i++)
+ {
+ if (keytable_abnt[i].wincode == wincode)
+ return winKeyMap2Iup(keytable_abnt, i);
+ }
+ }
+
+ count = sizeof(winkey_map)/sizeof(winkey_map[0]);
+ for (i = 0; i < count; i++)
+ {
+ if (winkey_map[i].wincode == wincode)
+ return winKeyMap2Iup(winkey_map, i);
+ }
+
+ return 0;
+}
+
+int iupwinKeyEvent(Ihandle* ih, int wincode, int press)
+{
+ int result, code;
+
+ if (!ih->iclass->is_interactive)
+ return 1;
+
+ code = winKeyDecode(wincode);
+ if (code == 0)
+ return 1;
+
+ if (press)
+ {
+ result = iupKeyCallKeyCb(ih, code);
+ if (result == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return 1;
+ }
+ else if (result == IUP_IGNORE)
+ return 0;
+
+ /* in the previous callback the dialog could be destroyed */
+ if (iupObjectCheck(ih))
+ {
+ /* this is called only for canvas */
+ if (ih->iclass->nativetype == IUP_TYPECANVAS)
+ {
+ result = iupKeyCallKeyPressCb(ih, code, 1);
+ if (result == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return 1;
+ }
+ else if (result == IUP_IGNORE)
+ return 0;
+ }
+ }
+
+ if (!iupKeyProcessNavigation(ih, code, (GetKeyState(VK_SHIFT) & 0x8000)))
+ return 0;
+ }
+ else
+ {
+ /* this is called only for canvas */
+ if (ih->iclass->nativetype == IUP_TYPECANVAS)
+ {
+ result = iupKeyCallKeyPressCb(ih, code, 0);
+ if (result == IUP_CLOSE)
+ {
+ IupExitLoop();
+ return 1;
+ }
+ else if (result == IUP_IGNORE)
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+void iupwinButtonKeySetStatus(WORD keys, char* status, int doubleclick)
+{
+ if (keys & MK_SHIFT)
+ iupKEYSETSHIFT(status);
+
+ if (keys & MK_CONTROL)
+ iupKEYSETCONTROL(status);
+
+ if (keys & MK_LBUTTON)
+ iupKEYSETBUTTON1(status);
+
+ if (keys & MK_MBUTTON)
+ iupKEYSETBUTTON2(status);
+
+ if (keys & MK_RBUTTON)
+ iupKEYSETBUTTON3(status);
+
+ if (doubleclick)
+ iupKEYSETDOUBLE(status);
+
+ if (GetKeyState(VK_MENU) & 0x8000)
+ iupKEYSETALT(status);
+
+ if ((GetKeyState(VK_LWIN) & 0x8000) || (GetKeyState(VK_RWIN) & 0x8000))
+ iupKEYSETSYS(status);
+
+ if (keys & MK_XBUTTON1)
+ iupKEYSETBUTTON4(status);
+
+ if (keys & MK_XBUTTON2)
+ iupKEYSETBUTTON5(status);
+}
diff --git a/iup/src/win/iupwin_label.c b/iup/src/win/iupwin_label.c
new file mode 100755
index 0000000..d5a1f53
--- /dev/null
+++ b/iup/src/win/iupwin_label.c
@@ -0,0 +1,339 @@
+/** \file
+ * \brief Label Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_label.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_image.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_draw.h"
+
+
+static void winLabelDrawImage(Ihandle* ih, HDC hDC, int rect_width, int rect_height)
+{
+ int xpad = ih->data->horiz_padding,
+ ypad = ih->data->vert_padding;
+ int x, y, width, height, bpp;
+ HBITMAP hBitmap, hMask = NULL;
+ char *name;
+ int make_inactive = 0;
+
+ if (iupdrvIsActive(ih))
+ name = iupAttribGet(ih, "IMAGE");
+ else
+ {
+ name = iupAttribGet(ih, "IMINACTIVE");
+ if (!name)
+ {
+ name = iupAttribGet(ih, "IMAGE");
+ make_inactive = 1;
+ }
+ }
+
+ hBitmap = iupImageGetImage(name, ih, make_inactive);
+ if (!hBitmap)
+ return;
+
+ /* must use this info, since image can be a driver image loaded from resources */
+ iupdrvImageGetInfo(hBitmap, &width, &height, &bpp);
+
+ if (ih->data->horiz_alignment == IUP_ALIGN_ARIGHT)
+ x = rect_width - (width + 2*xpad);
+ else if (ih->data->horiz_alignment == IUP_ALIGN_ACENTER)
+ x = (rect_width - (width + 2*xpad))/2;
+ else /* ALEFT */
+ x = 0;
+
+ if (ih->data->vert_alignment == IUP_ALIGN_ABOTTOM)
+ y = rect_height - (height + 2*ypad);
+ else if (ih->data->vert_alignment == IUP_ALIGN_ATOP)
+ y = 0;
+ else /* ACENTER */
+ y = (rect_height - (height + 2*ypad))/2;
+
+ x += xpad;
+ y += ypad;
+
+ if (bpp == 8)
+ hMask = iupdrvImageCreateMask(IupGetHandle(name));
+
+ iupwinDrawBitmap(hDC, hBitmap, hMask, x, y, width, height, bpp);
+
+ if (hMask)
+ DeleteObject(hMask);
+}
+
+static void winLabelDrawText(Ihandle* ih, HDC hDC, int rect_width, int rect_height)
+{
+ int xpad = ih->data->horiz_padding,
+ ypad = ih->data->vert_padding;
+ int x, y, width, height, style;
+ HFONT hFont = (HFONT)iupwinGetHFontAttrib(ih);
+ COLORREF fgcolor;
+
+ char* title = iupdrvBaseGetTitleAttrib(ih);
+ char* str = iupStrProcessMnemonic(title, NULL, 0); /* remove & */
+ iupdrvFontGetMultiLineStringSize(ih, str, &width, &height);
+ if (str && str!=title) free(str);
+
+ if (ih->data->horiz_alignment == IUP_ALIGN_ARIGHT)
+ style = DT_RIGHT;
+ else if (ih->data->horiz_alignment == IUP_ALIGN_ACENTER)
+ style = DT_CENTER;
+ else /* ALEFT */
+ style = DT_LEFT;
+
+ if (ih->data->vert_alignment == IUP_ALIGN_ABOTTOM)
+ y = rect_height - (height + 2*ypad);
+ else if (ih->data->vert_alignment == IUP_ALIGN_ATOP)
+ y = 0;
+ else /* ACENTER */
+ y = (rect_height - (height + 2*ypad))/2;
+
+ /* let DrawText do the horizontal alignment */
+ x = xpad;
+ width = rect_width - 2*xpad;
+ y += ypad;
+
+ if (iupdrvIsActive(ih))
+ fgcolor = ih->data->fgcolor;
+ else
+ fgcolor = GetSysColor(COLOR_GRAYTEXT);
+
+ /* WORDWRAP and ELLIPSIS */
+ style |= ih->data->text_style;
+
+ iupwinDrawText(hDC, title, x, y, width, height, hFont, fgcolor, style);
+}
+
+static void winLabelDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem)
+{
+ HDC hDC;
+ iupwinBitmapDC bmpDC;
+ int width, height;
+
+ if (!(drawitem->itemAction & ODA_DRAWENTIRE))
+ return;
+
+ width = drawitem->rcItem.right - drawitem->rcItem.left;
+ height = drawitem->rcItem.bottom - drawitem->rcItem.top;
+
+ hDC = iupwinDrawCreateBitmapDC(&bmpDC, drawitem->hDC, width, height);
+
+ iupwinDrawParentBackground(ih, hDC, &drawitem->rcItem);
+
+ if (ih->data->type == IUP_LABEL_IMAGE)
+ winLabelDrawImage(ih, hDC, width, height);
+ else
+ winLabelDrawText(ih, hDC, width, height);
+
+ iupwinDrawDestroyBitmapDC(&bmpDC);
+}
+
+/************************************************************************************************/
+
+static int winLabelSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT)
+ {
+ char value1[30] = "", value2[30] = "";
+
+ iupStrToStrStr(value, value1, value2, ':');
+
+ if (iupStrEqualNoCase(value1, "ARIGHT"))
+ ih->data->horiz_alignment = IUP_ALIGN_ARIGHT;
+ else if (iupStrEqualNoCase(value1, "ACENTER"))
+ ih->data->horiz_alignment = IUP_ALIGN_ACENTER;
+ else /* "ALEFT" */
+ ih->data->horiz_alignment = IUP_ALIGN_ALEFT;
+
+ if (iupStrEqualNoCase(value2, "ABOTTOM"))
+ ih->data->vert_alignment = IUP_ALIGN_ABOTTOM;
+ else if (iupStrEqualNoCase(value2, "ACENTER"))
+ ih->data->vert_alignment = IUP_ALIGN_ACENTER;
+ else /* "ATOP" */
+ ih->data->vert_alignment = IUP_ALIGN_ATOP;
+
+ iupdrvDisplayRedraw(ih);
+ }
+ return 0;
+}
+
+static char* winLabelGetAlignmentAttrib(Ihandle *ih)
+{
+ if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT)
+ {
+ char* horiz_align2str[3] = {"ALEFT", "ACENTER", "ARIGHT"};
+ char* vert_align2str[3] = {"ATOP", "ACENTER", "ABOTTOM"};
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%s:%s", horiz_align2str[ih->data->horiz_alignment], vert_align2str[ih->data->vert_alignment]);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int winLabelSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+
+ if (ih->handle && ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT)
+ iupdrvDisplayRedraw(ih);
+
+ return 0;
+}
+
+static int winLabelSetWordWrapAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_TEXT)
+ {
+ if (iupStrBoolean(value))
+ ih->data->text_style |= DT_WORDBREAK;
+ else
+ ih->data->text_style &= ~DT_WORDBREAK;
+
+ iupdrvDisplayRedraw(ih);
+ }
+
+ return 1;
+}
+
+static int winLabelSetEllipsisAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_LABEL_TEXT)
+ {
+ if (iupStrBoolean(value))
+ ih->data->text_style |= DT_END_ELLIPSIS;
+ else
+ ih->data->text_style &= ~DT_END_ELLIPSIS;
+
+ iupdrvDisplayRedraw(ih);
+ }
+
+ return 1;
+}
+
+static int winLabelSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT)
+ {
+ unsigned char r, g, b;
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ ih->data->fgcolor = RGB(r,g,b);
+ iupdrvDisplayRedraw(ih);
+ }
+ }
+ return 1;
+}
+
+static int winLabelProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ switch (msg)
+ {
+ case WM_NCCALCSIZE:
+ {
+ if (wp == TRUE)
+ {
+ *result = WVR_HREDRAW|WVR_VREDRAW;
+ return 1;
+ }
+ }
+ }
+
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+static int winLabelMapMethod(Ihandle* ih)
+{
+ char* value;
+ DWORD dwStyle = WS_CHILD |
+ SS_NOTIFY; /* SS_NOTIFY is necessary because of the base messages */
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ value = iupAttribGet(ih, "SEPARATOR");
+ if (value)
+ {
+ if (iupStrEqualNoCase(value, "HORIZONTAL"))
+ {
+ ih->data->type = IUP_LABEL_SEP_HORIZ;
+ dwStyle |= SS_ETCHEDHORZ;
+ }
+ else /* "VERTICAL" */
+ {
+ ih->data->type = IUP_LABEL_SEP_VERT;
+ dwStyle |= SS_ETCHEDVERT;
+ }
+ }
+ else
+ {
+ /* The lack for good alignment support in STATIC control forces IUP to draw its own label,
+ but uses the Windows functions to draw text and images in native format. */
+ dwStyle |= SS_OWNERDRAW;
+
+ value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ ih->data->type = IUP_LABEL_IMAGE;
+ else
+ ih->data->type = IUP_LABEL_TEXT;
+ }
+
+ if (!iupwinCreateWindowEx(ih, "STATIC", 0, dwStyle))
+ return IUP_ERROR;
+
+ if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT)
+ {
+ /* replace the WinProc to handle other messages */
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winLabelProc);
+
+ IupSetCallback(ih, "_IUPWIN_DRAWITEM_CB", (Icallback)winLabelDrawItem);
+ }
+
+ return IUP_NOERROR;
+}
+
+void iupdrvLabelInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winLabelMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ /* the most important use of this is to provide the correct background for images */
+ iupClassRegisterAttribute(ic, "BGCOLOR", iupBaseNativeParentGetBgColorAttrib, NULL, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, winLabelSetFgColorAttrib, "DLGFGCOLOR", NULL, IUPAF_NOT_MAPPED); /* force new default value */
+ iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, iupdrvBaseSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupLabel only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", winLabelGetAlignmentAttrib, winLabelSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ALEFT:ACENTER", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "PADDING", iupLabelGetPaddingAttrib, winLabelSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+
+ /* IupLabel Windows and GTK only */
+ iupClassRegisterAttribute(ic, "WORDWRAP", NULL, winLabelSetWordWrapAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "ELLIPSIS", NULL, winLabelSetEllipsisAttrib, NULL, NULL, IUPAF_DEFAULT);
+}
diff --git a/iup/src/win/iupwin_list.c b/iup/src/win/iupwin_list.c
new file mode 100755
index 0000000..8fdadb6
--- /dev/null
+++ b/iup/src/win/iupwin_list.c
@@ -0,0 +1,1460 @@
+/** \file
+ * \brief List Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_mask.h"
+#include "iup_focus.h"
+#include "iup_list.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_draw.h"
+
+
+#ifndef EM_SETCUEBANNER /* defined only if _WIN32_WINNT >= 0x501 */
+#define ECM_FIRST 0x1500 /* Edit control messages */
+#define EM_SETCUEBANNER (ECM_FIRST + 1)
+#endif
+
+#define WM_CARET WM_APP+1 /* Custom IUP message */
+
+#define WIN_GETCOUNT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETCOUNT: LB_GETCOUNT)
+#define WIN_GETTEXTLEN(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETLBTEXTLEN: LB_GETTEXTLEN)
+#define WIN_GETTEXT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETLBTEXT: LB_GETTEXT)
+#define WIN_ADDSTRING(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_ADDSTRING: LB_ADDSTRING)
+#define WIN_DELETESTRING(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_DELETESTRING: LB_DELETESTRING)
+#define WIN_INSERTSTRING(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_INSERTSTRING: LB_INSERTSTRING)
+#define WIN_RESETCONTENT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_RESETCONTENT: LB_RESETCONTENT)
+#define WIN_SETCURSEL(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETCURSEL: LB_SETCURSEL)
+#define WIN_GETCURSEL(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETCURSEL: LB_GETCURSEL)
+#define WIN_SETHORIZONTALEXTENT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETHORIZONTALEXTENT: LB_SETHORIZONTALEXTENT)
+#define WIN_SETITEMDATA(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETITEMDATA: LB_SETITEMDATA)
+#define WIN_GETITEMDATA(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETITEMDATA: LB_GETITEMDATA)
+#define WIN_SETTOPINDEX(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETTOPINDEX: LB_SETTOPINDEX)
+#define WIN_SETITEMHEIGHT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETITEMHEIGHT: LB_SETITEMHEIGHT)
+
+
+void iupdrvListAddItemSpace(Ihandle* ih, int *h)
+{
+ (void)ih;
+ (void)h;
+}
+
+void iupdrvListAddBorders(Ihandle* ih, int *x, int *y)
+{
+ int border_size = 2*4;
+ (*x) += border_size;
+ (*y) += border_size;
+
+ if (ih->data->is_dropdown)
+ {
+ (*x) += 3; /* extra space for the dropdown button */
+
+ if (ih->data->has_editbox)
+ {
+ /* extra border for the editbox */
+ int internal_border_size = 2*6;
+ (*x) += internal_border_size;
+ (*y) += internal_border_size;
+ }
+ }
+ else
+ {
+ if (ih->data->has_editbox)
+ (*y) += 2*3; /* internal border between editbox and list */
+ }
+}
+
+int iupdrvListGetCount(Ihandle* ih)
+{
+ return SendMessage(ih->handle, WIN_GETCOUNT(ih), 0, 0);
+}
+
+static int winListConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ int pos;
+
+ if (ih->data->has_editbox)
+ {
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+
+ pos = SendMessage(cbedit, EM_CHARFROMPOS, 0, MAKELPARAM(x, y));
+ pos = LOWORD(pos);
+ }
+
+ if (ih->data->has_editbox)
+ {
+ HWND cblist = (HWND)iupAttribGet(ih, "_IUPWIN_LISTBOX");
+ pos = SendMessage(cblist, LB_ITEMFROMPOINT, 0, MAKELPARAM(x, y))+1; /* IUP Starts at 1 */
+ pos = LOWORD(pos);
+ }
+ else
+ {
+ pos = SendMessage(ih->handle, LB_ITEMFROMPOINT, 0, MAKELPARAM(x, y))+1;
+ pos = LOWORD(pos);
+ }
+
+ return pos;
+}
+
+static int winListGetMaxWidth(Ihandle* ih)
+{
+ int i, item_w, max_w = 0,
+ count = SendMessage(ih->handle, WIN_GETCOUNT(ih), 0, 0);
+
+ for (i=0; i<count; i++)
+ {
+ item_w = SendMessage(ih->handle, WIN_GETITEMDATA(ih), i, 0);
+ if (item_w > max_w)
+ max_w = item_w;
+ }
+
+ return max_w;
+}
+
+static void winListUpdateScrollWidth(Ihandle* ih)
+{
+ if (ih->data->is_dropdown && iupAttribGetBoolean(ih, "DROPEXPAND"))
+ {
+ int w = 3+winListGetMaxWidth(ih)+iupdrvGetScrollbarSize()+3;
+ SendMessage(ih->handle, CB_SETDROPPEDWIDTH, w, 0);
+ }
+ else
+ SendMessage(ih->handle, WIN_SETHORIZONTALEXTENT(ih), winListGetMaxWidth(ih), 0);
+}
+
+void iupdrvListAppendItem(Ihandle* ih, const char* value)
+{
+ int pos = SendMessage(ih->handle, WIN_ADDSTRING(ih), 0, (LPARAM)value);
+ SendMessage(ih->handle, WIN_SETITEMDATA(ih), pos, (LPARAM)iupdrvFontGetStringWidth(ih, value));
+ winListUpdateScrollWidth(ih);
+}
+
+void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value)
+{
+ SendMessage(ih->handle, WIN_INSERTSTRING(ih), pos, (LPARAM)value);
+ SendMessage(ih->handle, WIN_SETITEMDATA(ih), pos, (LPARAM)iupdrvFontGetStringWidth(ih, value));
+ winListUpdateScrollWidth(ih);
+}
+
+void iupdrvListRemoveItem(Ihandle* ih, int pos)
+{
+ if (ih->data->is_dropdown && !ih->data->has_editbox)
+ {
+ /* must check if removing the current item */
+ int curpos = SendMessage(ih->handle, WIN_GETCURSEL(ih), 0, 0);
+ if (pos == curpos)
+ {
+ if (curpos > 0) curpos--;
+ else curpos++;
+
+ SendMessage(ih->handle, WIN_SETCURSEL(ih), curpos, 0);
+ }
+ }
+
+ SendMessage(ih->handle, WIN_DELETESTRING(ih), pos, 0L);
+ winListUpdateScrollWidth(ih);
+}
+
+void iupdrvListRemoveAllItems(Ihandle* ih)
+{
+ SendMessage(ih->handle, WIN_RESETCONTENT(ih), 0, 0L);
+ if (ih->data->is_dropdown && iupAttribGetBoolean(ih, "DROPEXPAND"))
+ SendMessage(ih->handle, CB_SETDROPPEDWIDTH, 0, 0);
+ else
+ SendMessage(ih->handle, WIN_SETHORIZONTALEXTENT(ih), 0, 0);
+}
+
+static int winListGetCaretPos(HWND cbedit)
+{
+ int pos = 0;
+ POINT point;
+
+ if (GetFocus() != cbedit || !GetCaretPos(&point))
+ {
+ /* if does not have the focus, or could not get caret position,
+ then use the selection start position */
+ SendMessage(cbedit, EM_GETSEL, (WPARAM)&pos, 0);
+ }
+ else
+ {
+ pos = SendMessage(cbedit, EM_CHARFROMPOS, 0, MAKELPARAM(point.x, point.y));
+ pos = LOWORD(pos);
+ }
+
+ return pos;
+}
+
+
+/*********************************************************************************/
+
+
+static void winListUpdateItemWidth(Ihandle* ih)
+{
+ int i, count = SendMessage(ih->handle, WIN_GETCOUNT(ih), 0, 0);
+ for (i=0; i<count; i++)
+ {
+ int len = SendMessage(ih->handle, WIN_GETTEXTLEN(ih), (WPARAM)i, 0);
+ char* str = iupStrGetMemory(len+1);
+ SendMessage(ih->handle, WIN_GETTEXT(ih), (WPARAM)i, (LPARAM)str);
+ SendMessage(ih->handle, WIN_SETITEMDATA(ih), i, (LPARAM)iupdrvFontGetStringWidth(ih, str));
+ }
+}
+
+static int winListSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ iupdrvSetStandardFontAttrib(ih, value);
+ winListUpdateItemWidth(ih);
+ winListUpdateScrollWidth(ih);
+ return 1;
+}
+
+static char* winListGetIdValueAttrib(Ihandle* ih, const char* name_id)
+{
+ int pos = iupListGetPos(ih, name_id);
+ if (pos != -1)
+ {
+ int len = SendMessage(ih->handle, WIN_GETTEXTLEN(ih), (WPARAM)pos, 0);
+ char* str = iupStrGetMemory(len+1);
+ SendMessage(ih->handle, WIN_GETTEXT(ih), (WPARAM)pos, (LPARAM)str);
+ return str;
+ }
+ return NULL;
+}
+
+static char* winListGetValueAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ int nc = GetWindowTextLength(ih->handle);
+ if (nc)
+ {
+ char* str = iupStrGetMemory(nc+1);
+ GetWindowText(ih->handle, str, nc+1);
+ return str;
+ }
+ }
+ else
+ {
+ if (ih->data->is_dropdown || !ih->data->is_multiple)
+ {
+ int pos = SendMessage(ih->handle, WIN_GETCURSEL(ih), 0, 0);
+ char* str = iupStrGetMemory(50);
+ sprintf(str, "%d", pos+1); /* IUP starts at 1 */
+ return str;
+ }
+ else
+ {
+ int i, count = SendMessage(ih->handle, LB_GETCOUNT, 0, 0);
+ int* pos = malloc(sizeof(int)*count);
+ int sel_count = SendMessage(ih->handle, LB_GETSELITEMS, count, (LPARAM)pos);
+ char* str = iupStrGetMemory(count+1);
+ memset(str, '-', count);
+ str[count]=0;
+ for (i=0; i<sel_count; i++)
+ str[pos[i]] = '+';
+ str[count]=0;
+ return str;
+ }
+ }
+
+ return NULL;
+}
+
+static int winListSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->has_editbox)
+ {
+ if (!value) value = "";
+ SetWindowText(ih->handle, value);
+ }
+ else
+ {
+ if (ih->data->is_dropdown || !ih->data->is_multiple)
+ {
+ int pos;
+ if (iupStrToInt(value, &pos)==1)
+ {
+ SendMessage(ih->handle, WIN_SETCURSEL(ih), pos-1, 0); /* IUP starts at 1 */
+ iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos);
+ }
+ else
+ {
+ SendMessage(ih->handle, WIN_SETCURSEL(ih), (WPARAM)-1, 0); /* no selection */
+ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL);
+ }
+ }
+ else
+ {
+ /* User has changed a multiple selection on a simple list. */
+ int i, len, count;
+
+ /* Clear all selections */
+ SendMessage(ih->handle, LB_SETSEL, FALSE, -1);
+
+ if (!value)
+ {
+ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL);
+ return 0;
+ }
+
+ count = SendMessage(ih->handle, LB_GETCOUNT, 0, 0L);
+ len = strlen(value);
+ if (len < count)
+ count = len;
+
+ /* update selection list */
+ for (i = 0; i<count; i++)
+ {
+ if (value[i]=='+')
+ SendMessage(ih->handle, LB_SETSEL, TRUE, i);
+ }
+
+ iupAttribStoreStr(ih, "_IUPLIST_OLDVALUE", value);
+ }
+ }
+
+ return 0;
+}
+
+static int winListSetShowDropdownAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->is_dropdown)
+ SendMessage(ih->handle, CB_SHOWDROPDOWN, iupStrBoolean(value), 0);
+ return 0;
+}
+
+static int winListSetTopItemAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->is_dropdown)
+ {
+ int pos = 1;
+ if (iupStrToInt(value, &pos))
+ SendMessage(ih->handle, WIN_SETTOPINDEX(ih), pos-1, 0); /* IUP starts at 1 */
+ }
+ return 0;
+}
+
+static int winListSetSpacingAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->is_dropdown)
+ return 0;
+
+ if (!iupStrToInt(value, &ih->data->spacing))
+ ih->data->spacing = 0;
+
+ if (ih->handle)
+ {
+ int height;
+ iupdrvFontGetCharSize(ih, NULL, &height);
+ height += 2*ih->data->spacing;
+ SendMessage(ih->handle, WIN_SETITEMHEIGHT(ih), 0, height);
+ return 0;
+ }
+ else
+ return 1; /* store until not mapped, when mapped will be set again */
+}
+
+static int winListSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_editbox)
+ return 0;
+
+ iupStrToIntInt(value, &(ih->data->horiz_padding), &(ih->data->vert_padding), 'x');
+ ih->data->vert_padding = 0;
+ if (ih->handle)
+ {
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN, MAKELPARAM(ih->data->horiz_padding, ih->data->horiz_padding));
+ return 0;
+ }
+ else
+ return 1; /* store until not mapped, when mapped will be set again */
+}
+
+static int winListSetFilterAttrib(Ihandle *ih, const char *value)
+{
+ int style = 0;
+
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (iupStrEqualNoCase(value, "LOWERCASE"))
+ style = ES_LOWERCASE;
+ else if (iupStrEqualNoCase(value, "NUMBER"))
+ style = ES_NUMBER;
+ else if (iupStrEqualNoCase(value, "UPPERCASE"))
+ style = ES_UPPERCASE;
+
+ if (style)
+ {
+ HWND old_handle = ih->handle;
+ ih->handle = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ iupwinMergeStyle(ih, ES_LOWERCASE|ES_NUMBER|ES_UPPERCASE, style);
+ ih->handle = old_handle;
+ }
+
+ return 1;
+}
+
+static int winListSetCueBannerAttrib(Ihandle *ih, const char *value)
+{
+ if (ih->data->has_editbox && iupwin_comctl32ver6)
+ {
+ WCHAR* wstr = iupwinStrChar2Wide(value);
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETCUEBANNER, (WPARAM)FALSE, (LPARAM)wstr);
+ free(wstr);
+ return 1;
+ }
+ return 0;
+}
+
+static int winListSetClipboardAttrib(Ihandle *ih, const char *value)
+{
+ UINT msg = 0;
+
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (iupStrEqualNoCase(value, "COPY"))
+ msg = WM_COPY;
+ else if (iupStrEqualNoCase(value, "CUT"))
+ msg = WM_CUT;
+ else if (iupStrEqualNoCase(value, "PASTE"))
+ msg = WM_PASTE;
+ else if (iupStrEqualNoCase(value, "CLEAR"))
+ msg = WM_CLEAR;
+ else if (iupStrEqualNoCase(value, "UNDO"))
+ msg = WM_UNDO;
+
+ if (msg)
+ {
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, msg, 0, 0);
+ }
+
+ return 0;
+}
+
+static int winListSetSelectedTextAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (value)
+ {
+ int start = 0, end = 0;
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return 0;
+ SendMessage(cbedit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)value);
+ }
+ return 0;
+}
+
+static char* winListGetSelectedTextAttrib(Ihandle* ih)
+{
+ int nc;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ nc = GetWindowTextLength(cbedit);
+ if (nc)
+ {
+ int start = 0, end = 0;
+ char* str;
+
+ SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return NULL;
+
+ str = iupStrGetMemory(nc+1);
+ GetWindowText(cbedit, str, nc+1);
+ str[end] = 0; /* returns only the selected text */
+ str += start;
+
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int winListSetNCAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!iupStrToInt(value, &ih->data->nc))
+ ih->data->nc = 0;
+
+ if (ih->handle)
+ {
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_LIMITTEXT, ih->data->nc, 0L);
+ }
+ return 0;
+}
+
+static int winListSetSelectionAttrib(Ihandle* ih, const char* value)
+{
+ HWND cbedit;
+ int start=1, end=1;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)-1, (LPARAM)0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
+ return 0;
+ }
+
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<1 || end<1)
+ return 0;
+
+ start--; /* IUP starts at 1 */
+ end--;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)start, (LPARAM)end);
+
+ return 0;
+}
+
+static char* winListGetSelectionAttrib(Ihandle* ih)
+{
+ int start = 0, end = 0;
+ char* str;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return NULL;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return NULL;
+
+ str = iupStrGetMemory(100);
+
+ start++; /* IUP starts at 1 */
+ end++;
+ sprintf(str, "%d:%d", start, end);
+
+ return str;
+}
+
+static int winListSetSelectionPosAttrib(Ihandle* ih, const char* value)
+{
+ int start=0, end=0;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)-1, (LPARAM)0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
+ return 0;
+ }
+
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<0 || end<0)
+ return 0;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)start, (LPARAM)end);
+
+ return 0;
+}
+
+static char* winListGetSelectionPosAttrib(Ihandle* ih)
+{
+ int start = 0, end = 0;
+ char* str;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return NULL;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return NULL;
+
+ str = iupStrGetMemory(100);
+ sprintf(str, "%d:%d", start, end);
+ return str;
+}
+
+static int winListSetInsertAttrib(Ihandle* ih, const char* value)
+{
+ if (value && ih->data->has_editbox)
+ {
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)value);
+ }
+ return 0;
+}
+
+static int winListSetAppendAttrib(Ihandle* ih, const char* value)
+{
+ int len;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value) value = "";
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ len = GetWindowTextLength(cbedit)+1;
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)len, (LPARAM)len);
+ SendMessage(cbedit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)value);
+
+ return 0;
+}
+
+static int winListSetReadOnlyAttrib(Ihandle* ih, const char* value)
+{
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETREADONLY, (WPARAM)iupStrBoolean(value), 0);
+ return 0;
+}
+
+static char* winListGetReadOnlyAttrib(Ihandle* ih)
+{
+ DWORD style;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return NULL;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ style = GetWindowLong(cbedit, GWL_STYLE);
+ if (style & ES_READONLY)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int winListSetCaretAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 1) pos = 1;
+ pos--; /* IUP starts at 1 */
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)pos, (LPARAM)pos);
+ SendMessage(cbedit, EM_SCROLLCARET, 0L, 0L);
+
+ return 0;
+}
+
+static char* winListGetCaretAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ char* str = iupStrGetMemory(100);
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ sprintf(str, "%d", winListGetCaretPos(cbedit)+1);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int winListSetCaretPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos); /* be permissive in SetCaret, do not abort if invalid */
+ if (pos < 0) pos = 0;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)pos, (LPARAM)pos);
+ SendMessage(cbedit, EM_SCROLLCARET, 0L, 0L);
+
+ return 0;
+}
+
+static char* winListGetCaretPosAttrib(Ihandle* ih)
+{
+ if (ih->data->has_editbox)
+ {
+ char* str = iupStrGetMemory(100);
+ HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ sprintf(str, "%d", winListGetCaretPos(cbedit));
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int winListSetScrollToAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 1) pos = 1;
+
+ pos--; /* return to Windows referece */
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_LINESCROLL, (WPARAM)pos, (LPARAM)0);
+
+ return 0;
+}
+
+static int winListSetScrollToPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+ HWND cbedit;
+ if (!ih->data->has_editbox)
+ return 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ SendMessage(cbedit, EM_LINESCROLL, (WPARAM)pos, (LPARAM)0);
+
+ return 0;
+}
+
+
+/*********************************************************************************/
+
+
+static int winListCtlColor(Ihandle* ih, HDC hdc, LRESULT *result)
+{
+ COLORREF cr;
+
+ if (iupwinGetColorRef(ih, "FGCOLOR", &cr))
+ SetTextColor(hdc, cr);
+
+ if (iupwinGetColorRef(ih, "BGCOLOR", &cr))
+ {
+ SetBkColor(hdc, cr);
+ SetDCBrushColor(hdc, cr);
+ *result = (LRESULT)GetStockObject(DC_BRUSH);
+ return 1;
+ }
+ return 0;
+}
+
+static int winListWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp)
+{
+ (void)lp;
+
+ if (ih->data->is_dropdown || ih->data->has_editbox)
+ {
+ switch (HIWORD(wp))
+ {
+ case CBN_EDITCHANGE:
+ {
+ iupBaseCallValueChangedCb(ih);
+ break;
+ }
+ case CBN_SETFOCUS:
+ iupwinWmSetFocus(ih);
+ break;
+ case CBN_KILLFOCUS:
+ iupCallKillFocusCb(ih);
+ break;
+ case CBN_CLOSEUP:
+ case CBN_DROPDOWN:
+ {
+ IFni cb = (IFni)IupGetCallback(ih, "DROPDOWN_CB");
+ if (cb)
+ cb(ih, HIWORD(wp)==CBN_DROPDOWN? 1: 0);
+ break;
+ }
+ case CBN_DBLCLK:
+ {
+ IFnis cb = (IFnis) IupGetCallback(ih, "DBLCLICK_CB");
+ if (cb)
+ {
+ int pos = SendMessage(ih->handle, CB_GETCURSEL, 0, 0);
+ pos++; /* IUP starts at 1 */
+ iupListSingleCallDblClickCallback(ih, cb, pos);
+ }
+ break;
+ }
+ case CBN_SELCHANGE:
+ {
+ IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ int pos = SendMessage(ih->handle, CB_GETCURSEL, 0, 0);
+ pos++; /* IUP starts at 1 */
+ iupListSingleCallActionCallback(ih, cb, pos);
+ }
+
+ iupBaseCallValueChangedCb(ih);
+ break;
+ }
+ }
+ }
+ else
+ {
+ switch (HIWORD(wp))
+ {
+ case LBN_DBLCLK:
+ {
+ IFnis cb = (IFnis) IupGetCallback(ih, "DBLCLICK_CB");
+ if (cb)
+ {
+ int pos = SendMessage(ih->handle, LB_GETCURSEL, 0, 0);
+ pos++; /* IUP starts at 1 */
+ iupListSingleCallDblClickCallback(ih, cb, pos);
+ }
+ break;
+ }
+ case LBN_SELCHANGE:
+ {
+ if (!ih->data->is_multiple)
+ {
+ IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ int pos = SendMessage(ih->handle, LB_GETCURSEL, 0, 0);
+ pos++; /* IUP starts at 1 */
+ iupListSingleCallActionCallback(ih, cb, pos);
+ }
+ }
+ else
+ {
+ IFns multi_cb = (IFns)IupGetCallback(ih, "MULTISELECT_CB");
+ IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION");
+ if (multi_cb || cb)
+ {
+ int sel_count = SendMessage(ih->handle, LB_GETSELCOUNT, 0, 0);
+ int* pos = malloc(sizeof(int)*sel_count);
+ SendMessage(ih->handle, LB_GETSELITEMS, sel_count, (LPARAM)pos);
+ iupListMultipleCallActionCallback(ih, cb, multi_cb, pos, sel_count);
+ free(pos);
+ }
+ }
+
+ iupBaseCallValueChangedCb(ih);
+ break;
+ }
+ }
+ }
+
+ return 0; /* not used */
+}
+
+static void winListCallCaretCb(Ihandle* ih, HWND cbedit)
+{
+ int pos;
+
+ IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB");
+ if (!cb) return;
+
+ pos = winListGetCaretPos(cbedit);
+
+ if (pos != ih->data->last_caret_pos)
+ {
+ ih->data->last_caret_pos = pos;
+ cb(ih, 1, pos+1, pos);
+ }
+}
+
+static int winListCallEditCb(Ihandle* ih, HWND cbedit, const char* insert_value, int key, int dir)
+{
+ int start, end, ret = 1;
+ char *value, *new_value;
+
+ IFnis cb = (IFnis)IupGetCallback(ih, "EDIT_CB");
+ if (!cb && !ih->data->mask)
+ return 1;
+
+ SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+
+ value = winListGetValueAttrib(ih);
+
+ if (!value)
+ new_value = iupStrDup(insert_value);
+ else if (insert_value)
+ new_value = iupStrInsert(value, insert_value, start, end);
+ else
+ {
+ new_value = value;
+ iupStrRemove(value, start, end, dir);
+ }
+
+ if (!new_value)
+ return 0; /* abort */
+
+ if (ih->data->nc && (int)strlen(new_value) > ih->data->nc)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (cb)
+ {
+ int cb_ret = cb(ih, key, (char*)new_value);
+ if (cb_ret==IUP_IGNORE)
+ ret = 0; /* abort processing */
+ else if (cb_ret==IUP_CLOSE)
+ {
+ IupExitLoop();
+ ret = 0; /* abort processing */
+ }
+ else if (cb_ret!=0 && key!=0 &&
+ cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE)
+ {
+ WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_EDITOLDPROC_CB");
+ CallWindowProc(oldProc, cbedit, WM_CHAR, cb_ret, 0); /* replace key */
+ ret = 0; /* abort processing */
+ }
+ }
+
+ if (new_value != value) free(new_value);
+ return ret;
+}
+
+static int winListEditProc(Ihandle* ih, HWND cbedit, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ int ret = 0;
+
+ if (msg==WM_KEYDOWN) /* process K_ANY before text callbacks */
+ {
+ ret = iupwinBaseProc(ih, msg, wp, lp, result);
+ if (ret) return 1;
+ }
+
+ switch (msg)
+ {
+ case WM_CHAR:
+ {
+ if ((char)wp == '\b')
+ {
+ if (!winListCallEditCb(ih, cbedit, NULL, 0, -1))
+ ret = 1;
+ }
+ else if ((char)wp == '\n' || (char)wp == '\r')
+ {
+ ret = 1;
+ }
+ else if (!(GetKeyState(VK_CONTROL) & 0x8000 ||
+ GetKeyState(VK_MENU) & 0x8000 ||
+ GetKeyState(VK_LWIN) & 0x8000 ||
+ GetKeyState(VK_RWIN) & 0x8000))
+ {
+ char insert_value[2];
+ insert_value[0] = (char)wp;
+ insert_value[1] = 0;
+
+ if (!winListCallEditCb(ih, cbedit, insert_value, wp, 1))
+ ret = 1;
+ }
+
+ PostMessage(cbedit, WM_CARET, 0, 0L);
+
+ if (wp==VK_TAB) /* the keys have the same definitions as the chars */
+ ret = 1; /* abort default processing to avoid beep */
+
+ break;
+ }
+ case WM_KEYDOWN:
+ {
+ if (wp == VK_DELETE) /* Del does not generates a WM_CHAR */
+ {
+ if (!winListCallEditCb(ih, cbedit, NULL, 0, 1))
+ ret = 1;
+ }
+ else if (wp == 'A' && GetKeyState(VK_CONTROL) & 0x8000) /* Ctrl+A = Select All */
+ {
+ SendMessage(cbedit, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
+ }
+
+ PostMessage(cbedit, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_CLEAR:
+ {
+ if (!winListCallEditCb(ih, cbedit, NULL, 0, 1))
+ ret = 1;
+
+ PostMessage(cbedit, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_CUT:
+ {
+ if (!winListCallEditCb(ih, cbedit, NULL, 0, 1))
+ ret = 1;
+
+ PostMessage(cbedit, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_PASTE:
+ {
+ if (IupGetCallback(ih, "EDIT_CB") || ih->data->mask) /* test before to avoid alocate clipboard text memory */
+ {
+ char* insert_value = iupwinGetClipboardText(ih);
+ if (insert_value)
+ {
+ if (!winListCallEditCb(ih, cbedit, insert_value, 0, 1))
+ ret = 1;
+ free(insert_value);
+ }
+ }
+
+ PostMessage(cbedit, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_UNDO:
+ {
+ IFnis cb = (IFnis)IupGetCallback(ih, "EDIT_CB");
+ if (cb)
+ {
+ char* value;
+ WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_EDITOLDPROC_CB");
+ CallWindowProc(oldProc, cbedit, WM_UNDO, 0, 0);
+
+ value = winListGetValueAttrib(ih);
+ cb(ih, 0, (char*)value);
+
+ ret = 1;
+ }
+
+ PostMessage(cbedit, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_KEYUP:
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_LBUTTONUP:
+ PostMessage(cbedit, WM_CARET, 0, 0L);
+ break;
+ case WM_CARET:
+ winListCallCaretCb(ih, cbedit);
+ break;
+ }
+
+ if (ret) /* if abort processing, then the result is 0 */
+ {
+ *result = 0;
+ return 1;
+ }
+ else
+ {
+ if (msg==WM_KEYDOWN)
+ return 0;
+ else
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+ }
+}
+
+static LRESULT CALLBACK winListEditWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ int ret = 0;
+ LRESULT result = 0;
+ WNDPROC oldProc;
+ Ihandle *ih;
+
+ ih = iupwinHandleGet(hwnd);
+ if (!ih)
+ return DefWindowProc(hwnd, msg, wp, lp); /* should never happen */
+
+ /* retrieve the control previous procedure for subclassing */
+ oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_EDITOLDPROC_CB");
+
+ ret = winListEditProc(ih, hwnd, msg, wp, lp, &result);
+
+ if (ret)
+ return result;
+ else
+ return CallWindowProc(oldProc, hwnd, msg, wp, lp);
+}
+
+static int winListComboListProc(Ihandle* ih, HWND cblist, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ (void)cblist;
+
+ switch (msg)
+ {
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ if (iupwinButtonDown(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+ break;
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_LBUTTONUP:
+ if (iupwinButtonUp(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+ break;
+ case WM_MOUSEMOVE:
+ iupwinMouseMove(ih, msg, wp, lp);
+ iupwinBaseProc(ih, msg, wp, lp, result); /* to process ENTER/LEAVE */
+ break;
+ case WM_MOUSELEAVE:
+ iupwinBaseProc(ih, msg, wp, lp, result); /* to process ENTER/LEAVE */
+ break;
+ }
+
+ return 0;
+}
+
+static LRESULT CALLBACK winListComboListWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ int ret = 0;
+ LRESULT result = 0;
+ WNDPROC oldProc;
+ Ihandle *ih;
+
+ ih = iupwinHandleGet(hwnd);
+ if (!ih)
+ return DefWindowProc(hwnd, msg, wp, lp); /* should never happen */
+
+ /* retrieve the control previous procedure for subclassing */
+ oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_LISTOLDPROC_CB");
+
+ ret = winListComboListProc(ih, hwnd, msg, wp, lp, &result);
+
+ if (ret)
+ return result;
+ else
+ return CallWindowProc(oldProc, hwnd, msg, wp, lp);
+}
+
+static int winListProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ if (!ih->data->is_dropdown && !ih->data->has_editbox)
+ {
+ switch (msg)
+ {
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ if (iupwinButtonDown(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+ break;
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_LBUTTONUP:
+ if (iupwinButtonUp(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+ break;
+ case WM_MOUSEMOVE:
+ iupwinMouseMove(ih, msg, wp, lp);
+ break;
+ }
+ }
+
+ switch (msg)
+ {
+ case WM_CHAR:
+ if (GetKeyState(VK_CONTROL) & 0x8000)
+ {
+ /* avoid item search when Ctrl is pressed */
+ *result = 0;
+ return 1;
+ }
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ case WM_MOUSELEAVE:
+ case WM_MOUSEMOVE:
+ if (ih->data->has_editbox)
+ return 0; /* do not call base procedure to avoid duplicate messages */
+ break;
+ }
+
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+
+/*********************************************************************************/
+
+
+static void winListLayoutUpdateMethod(Ihandle *ih)
+{
+ if (ih->data->is_dropdown)
+ {
+ /* Must add the dropdown area, or it will not be visible */
+ RECT rect;
+ int charheight, calc_h, win_h, win_w, voptions;
+
+ voptions = iupAttribGetInt(ih, "VISIBLE_ITEMS");
+ if (voptions <= 0)
+ voptions = 1;
+
+ iupdrvFontGetCharSize(ih, NULL, &charheight);
+ calc_h = ih->currentheight + voptions*charheight;
+
+ SendMessage(ih->handle, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rect);
+ win_h = rect.bottom-rect.top;
+ win_w = rect.right-rect.left;
+
+ if (ih->currentwidth != win_w || calc_h != win_h)
+ SetWindowPos(ih->handle, HWND_TOP, ih->x, ih->y, ih->currentwidth, calc_h,
+ SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOOWNERZORDER);
+ else
+ SetWindowPos(ih->handle, HWND_TOP, ih->x, ih->y, 0, 0,
+ SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOOWNERZORDER);
+ }
+ else
+ iupdrvBaseLayoutUpdateMethod(ih);
+}
+
+static int winListMapMethod(Ihandle* ih)
+{
+ char* class_name;
+ DWORD dwStyle = WS_CHILD,
+ dwExStyle = WS_EX_CLIENTEDGE;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (ih->data->is_dropdown || ih->data->has_editbox)
+ {
+ class_name = "COMBOBOX";
+
+ dwStyle |= CBS_NOINTEGRALHEIGHT;
+
+ if (ih->data->is_dropdown)
+ dwStyle |= WS_VSCROLL|WS_HSCROLL;
+ else if (ih->data->sb)
+ {
+ dwStyle |= WS_VSCROLL|WS_HSCROLL;
+
+ if (!iupAttribGetBoolean(ih, "AUTOHIDE"))
+ dwStyle |= CBS_DISABLENOSCROLL;
+ }
+
+ if (ih->data->has_editbox)
+ {
+ dwStyle |= CBS_AUTOHSCROLL;
+
+ if (ih->data->is_dropdown)
+ dwStyle |= CBS_DROPDOWN; /* hidden-list+edit */
+ else
+ dwStyle |= CBS_SIMPLE; /* visible-list+edit */
+ }
+ else
+ dwStyle |= CBS_DROPDOWNLIST; /* hidden-list */
+
+ if (iupAttribGetBoolean(ih, "SORT"))
+ dwStyle |= CBS_SORT;
+ }
+ else
+ {
+ class_name = "LISTBOX";
+
+ dwStyle |= LBS_NOINTEGRALHEIGHT|LBS_NOTIFY;
+
+ if (ih->data->is_multiple)
+ dwStyle |= LBS_EXTENDEDSEL;
+
+ if (ih->data->sb)
+ {
+ dwStyle |= WS_VSCROLL|WS_HSCROLL;
+
+ if (!iupAttribGetBoolean(ih, "AUTOHIDE"))
+ dwStyle |= LBS_DISABLENOSCROLL;
+ }
+
+ if (iupAttribGetBoolean(ih, "SORT"))
+ dwStyle |= LBS_SORT;
+ }
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ dwStyle |= WS_TABSTOP;
+
+ if (!iupwinCreateWindowEx(ih, class_name, dwExStyle, dwStyle))
+ return IUP_ERROR;
+
+ /* Custom Procedure */
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winListProc);
+
+ /* Process background color */
+ IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winListCtlColor);
+
+ /* Process WM_COMMAND */
+ IupSetCallback(ih, "_IUPWIN_COMMAND_CB", (Icallback)winListWmCommand);
+
+ if (ih->data->is_dropdown || ih->data->has_editbox)
+ {
+ COMBOBOXINFO boxinfo;
+
+ ZeroMemory(&boxinfo, sizeof(COMBOBOXINFO));
+ boxinfo.cbSize = sizeof(COMBOBOXINFO);
+
+ GetComboBoxInfo(ih->handle, &boxinfo);
+
+ iupwinHandleAdd(ih, boxinfo.hwndList);
+ iupAttribSetStr(ih, "_IUPWIN_LISTBOX", (char*)boxinfo.hwndList);
+
+ /* subclass the list box. */
+ IupSetCallback(ih, "_IUPWIN_LISTOLDPROC_CB", (Icallback)GetWindowLongPtr(boxinfo.hwndList, GWLP_WNDPROC));
+ SetWindowLongPtr(boxinfo.hwndList, GWLP_WNDPROC, (LONG_PTR)winListComboListWinProc);
+
+ if (ih->data->has_editbox)
+ {
+ iupwinHandleAdd(ih, boxinfo.hwndItem);
+ iupAttribSetStr(ih, "_IUPWIN_EDITBOX", (char*)boxinfo.hwndItem);
+
+ /* subclass the edit box. */
+ IupSetCallback(ih, "_IUPWIN_EDITOLDPROC_CB", (Icallback)GetWindowLongPtr(boxinfo.hwndItem, GWLP_WNDPROC));
+ SetWindowLongPtr(boxinfo.hwndItem, GWLP_WNDPROC, (LONG_PTR)winListEditWinProc);
+
+ /* set defaults */
+ SendMessage(ih->handle, CB_LIMITTEXT, 0, 0L);
+ }
+ }
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)winListConvertXYToPos);
+
+ iupListSetInitialItems(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvListInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winListMapMethod;
+ ic->LayoutUpdate = winListLayoutUpdateMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, winListSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_NOT_MAPPED);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_NOT_MAPPED);
+
+ /* IupList only */
+ iupClassRegisterAttributeId(ic, "IDVALUE", winListGetIdValueAttrib, iupListSetIdValueAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VALUE", winListGetValueAttrib, winListSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SHOWDROPDOWN", NULL, winListSetShowDropdownAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TOPITEM", NULL, winListSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VISIBLE_ITEMS", NULL, NULL, IUPAF_SAMEASSYSTEM, "5", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "DROPEXPAND", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPACING", iupListGetSpacingAttrib, winListSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+
+ iupClassRegisterAttribute(ic, "PADDING", iupListGetPaddingAttrib, winListSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "SELECTEDTEXT", winListGetSelectedTextAttrib, winListSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTION", winListGetSelectionAttrib, winListSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTIONPOS", winListGetSelectionPosAttrib, winListSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARET", winListGetCaretAttrib, winListSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARETPOS", winListGetCaretPosAttrib, winListSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "INSERT", NULL, winListSetInsertAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "APPEND", NULL, winListSetAppendAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "READONLY", winListGetReadOnlyAttrib, winListSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "NC", iupListGetNCAttrib, winListSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, winListSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTO", NULL, winListSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, winListSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "CUEBANNER", NULL, winListSetCueBannerAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILTER", NULL, winListSetFilterAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_loop.c b/iup/src/win/iupwin_loop.c
new file mode 100755
index 0000000..7c5dbe7
--- /dev/null
+++ b/iup/src/win/iupwin_loop.c
@@ -0,0 +1,135 @@
+/** \file
+ * \brief Windows Message Loop
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <windows.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+
+
+static IFidle win_idle_cb = NULL;
+static int win_main_loop = 0;
+
+
+void iupdrvSetIdleFunction(Icallback f)
+{
+ win_idle_cb = (IFidle)f;
+}
+
+void IupExitLoop(void)
+{
+ PostQuitMessage(0);
+}
+
+static int winLoopProcessMessage(MSG* msg)
+{
+ if (msg->message == WM_QUIT) /* IUP_CLOSE returned in a callback or IupHide in a popup dialog or all dialogs closed */
+ return IUP_CLOSE;
+ else
+ {
+ TranslateMessage(msg);
+ DispatchMessage(msg);
+ return IUP_DEFAULT;
+ }
+}
+
+int IupMainLoopLevel(void)
+{
+ return win_main_loop;
+}
+
+int IupMainLoop(void)
+{
+ MSG msg;
+ int ret;
+
+ win_main_loop++;
+
+ do
+ {
+ if (win_idle_cb)
+ {
+ ret = 1;
+ if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+ {
+ if (winLoopProcessMessage(&msg) == IUP_CLOSE)
+ {
+ win_main_loop--;
+ return IUP_CLOSE;
+ }
+ }
+ else
+ {
+ int ret = win_idle_cb();
+ if (ret == IUP_CLOSE)
+ {
+ win_idle_cb = NULL;
+ win_main_loop--;
+ return IUP_CLOSE;
+ }
+ if (ret == IUP_IGNORE)
+ win_idle_cb = NULL;
+ }
+ }
+ else
+ {
+ ret = GetMessage(&msg, NULL, 0, 0);
+ if (ret == -1) /* error */
+ {
+ win_main_loop--;
+ return IUP_ERROR;
+ }
+ if (ret == 0 || /* WM_QUIT */
+ winLoopProcessMessage(&msg) == IUP_CLOSE) /* ret != 0 */
+ {
+ win_main_loop--;
+ return IUP_NOERROR;
+ }
+ }
+ } while (ret);
+
+ win_main_loop--;
+ return IUP_NOERROR;
+}
+
+int IupLoopStep(void)
+{
+ MSG msg;
+ if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+ return winLoopProcessMessage(&msg);
+
+ return IUP_DEFAULT;
+}
+
+void IupFlush(void)
+{
+ int post_quit = 0;
+ MSG msg;
+
+ while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+ {
+ if (winLoopProcessMessage(&msg) == IUP_CLOSE)
+ {
+ post_quit = 1;
+ break;
+ }
+ }
+
+ /* re post the quit message if still inside MainLoop */
+ if (post_quit && win_main_loop>0)
+ PostQuitMessage(0);
+}
diff --git a/iup/src/win/iupwin_menu.c b/iup/src/win/iupwin_menu.c
new file mode 100755
index 0000000..74a8b52
--- /dev/null
+++ b/iup/src/win/iupwin_menu.c
@@ -0,0 +1,667 @@
+/** \file
+ * \brief Menu Resources
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_dialog.h"
+#include "iup_str.h"
+#include "iup_image.h"
+#include "iup_dlglist.h"
+#include "iup_focus.h"
+#include "iup_menu.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_brush.h"
+
+
+Ihandle* iupwinMenuGetHandle(HMENU hMenu)
+{
+ MENUINFO menuinfo;
+ menuinfo.cbSize = sizeof(MENUINFO);
+ menuinfo.fMask = MIM_MENUDATA;
+ if (GetMenuInfo(hMenu, &menuinfo))
+ return (Ihandle*)menuinfo.dwMenuData;
+ else
+ return NULL;
+}
+
+Ihandle* iupwinMenuGetItemHandle(HMENU hMenu, int menuId)
+{
+ MENUITEMINFO menuiteminfo;
+ menuiteminfo.cbSize = sizeof(MENUITEMINFO);
+ menuiteminfo.fMask = MIIM_DATA;
+
+ if (GetMenuItemInfo(hMenu, menuId, FALSE, &menuiteminfo))
+ return (Ihandle*)menuiteminfo.dwItemData;
+ else
+ return NULL;
+}
+
+int iupdrvMenuGetMenuBarSize(Ihandle* ih)
+{
+ (void)ih;
+ return GetSystemMetrics(SM_CYMENU);
+}
+
+static void winMenuUpdateBar(Ihandle* ih)
+{
+ if (iupMenuIsMenuBar(ih) && ih->parent->handle)
+ DrawMenuBar(ih->parent->handle);
+ else if (ih->parent)
+ {
+ ih = ih->parent; /* check also for children of a menu bar */
+ if (iupMenuIsMenuBar(ih) && ih->parent->handle)
+ DrawMenuBar(ih->parent->handle);
+ }
+}
+
+static void winMenuGetLastPos(Ihandle* ih, int *last_pos, int *pos)
+{
+ Ihandle* child;
+ *last_pos=0;
+ *pos=0;
+ for (child=ih->parent->firstchild; child; child=child->brother)
+ {
+ if (child == ih)
+ *pos = *last_pos;
+ (*last_pos)++;
+ }
+}
+
+static void winItemCheckToggle(Ihandle* ih)
+{
+ if (iupAttribGetBoolean(ih->parent, "RADIO"))
+ {
+ int last_pos, pos;
+ winMenuGetLastPos(ih, &last_pos, &pos);
+ CheckMenuRadioItem((HMENU)ih->handle, 0, last_pos, pos, MF_BYPOSITION);
+
+ winMenuUpdateBar(ih);
+ }
+ else if (iupAttribGetBoolean(ih, "AUTOTOGGLE"))
+ {
+ if (GetMenuState((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND) & MF_CHECKED)
+ CheckMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_UNCHECKED|MF_BYCOMMAND);
+ else
+ CheckMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_CHECKED|MF_BYCOMMAND);
+
+ winMenuUpdateBar(ih);
+ }
+}
+
+typedef struct _IchildId
+{
+ int id, menuid;
+ Ihandle* child;
+} IchildId;
+
+void iupwinMenuDialogProc(Ihandle* ih_dialog, UINT msg, WPARAM wp, LPARAM lp)
+{
+ /* called only from winDialogBaseProc */
+
+ switch (msg)
+ {
+ case WM_INITMENUPOPUP:
+ {
+ HMENU hMenu = (HMENU)wp;
+ Ihandle *ih = iupwinMenuGetHandle(hMenu);
+ if (ih)
+ {
+ Icallback cb = (Icallback)IupGetCallback(ih, "OPEN_CB");
+ if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "OPEN_CB"); /* check also in the Submenu */
+ if (cb) cb(ih);
+ }
+ break;
+ }
+ case WM_UNINITMENUPOPUP:
+ {
+ HMENU hMenu = (HMENU)wp;
+ Ihandle *ih = iupwinMenuGetHandle(hMenu);
+ if (ih)
+ {
+ Icallback cb = (Icallback)IupGetCallback(ih, "MENUCLOSE_CB");
+ if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "MENUCLOSE_CB"); /* check also in the Submenu */
+ if (cb) cb(ih);
+ }
+ break;
+ }
+ case WM_MENUSELECT:
+ {
+ HMENU hMenu = (HMENU)lp;
+ Ihandle *ih;
+
+ if (!lp)
+ break;
+
+ if ((HIWORD(wp) & MF_POPUP) || (HIWORD(wp) & MF_SYSMENU)) /* drop-down ih or submenu. */
+ {
+ UINT menuindex = LOWORD(wp);
+ HMENU hsubmenu = GetSubMenu(hMenu, menuindex);
+ ih = iupwinMenuGetHandle(hsubmenu); /* returns the handle of a IupMenu */
+ if (ih) ih = ih->parent; /* gets the submenu */
+ }
+ else /* ih item */
+ {
+ UINT menuID = LOWORD(wp);
+ ih = iupwinMenuGetItemHandle(hMenu, menuID);
+ }
+
+ if (ih)
+ {
+ Icallback cb = IupGetCallback(ih, "HIGHLIGHT_CB");
+ if (cb) cb(ih);
+ }
+ break;
+ }
+ case WM_MENUCOMMAND:
+ {
+ int menuId = GetMenuItemID((HMENU)lp, (int)wp);
+ Icallback cb;
+ Ihandle* ih;
+
+ if (menuId >= IUP_MDICHILD_START)
+ break;
+
+ ih = iupwinMenuGetItemHandle((HMENU)lp, menuId);
+ if (!ih)
+ break;
+
+ winItemCheckToggle(ih);
+
+ cb = IupGetCallback(ih, "ACTION");
+ if (cb && cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+
+ break;
+ }
+ case WM_ENTERMENULOOP:
+ {
+ /* Simulate WM_KILLFOCUS when the menu interaction is started */
+ Ihandle* lastfocus = (Ihandle*)iupAttribGet(ih_dialog, "_IUPWIN_LASTFOCUS");
+ if (lastfocus) iupCallKillFocusCb(lastfocus);
+ break;
+ }
+ case WM_EXITMENULOOP:
+ {
+ /* Simulate WM_GETFOCUS when the menu interaction is stopped */
+ Ihandle* lastfocus = (Ihandle*)iupAttribGet(ih_dialog, "_IUPWIN_LASTFOCUS");
+ if (lastfocus) iupCallGetFocusCb(lastfocus);
+ break;
+ }
+ }
+}
+
+int iupdrvMenuPopup(Ihandle* ih, int x, int y)
+{
+ HWND hWndActive = GetActiveWindow();
+ int tray_menu = 0;
+ int menuId;
+
+ if (!hWndActive)
+ {
+ /* search for a valid handle */
+ Ihandle* dlg = iupDlgListFirst();
+ do
+ {
+ if (dlg->handle)
+ {
+ hWndActive = dlg->handle; /* found a valid handle */
+
+ /* if not a "TRAY" dialog, keep searching, because TRAY is a special case */
+ if (iupAttribGetBoolean(dlg, "TRAY"))
+ break;
+ }
+ dlg = iupDlgListNext();
+ } while (dlg);
+ }
+
+ /* Necessary to avoid tray dialogs to lock popup menus (they get sticky after the 1st time) */
+ if (hWndActive)
+ {
+ Ihandle* dlg = iupwinHandleGet(hWndActive);
+ if (dlg && iupAttribGetBoolean(dlg, "TRAY"))
+ {
+ /* To display a context menu for a notification icon,
+ the current window must be the foreground window. */
+ SetForegroundWindow(hWndActive);
+ tray_menu = 1;
+ }
+ }
+
+ /* stop processing here. messages will not go to the message loop */
+ menuId = TrackPopupMenu((HMENU)ih->handle, TPM_LEFTALIGN|TPM_RIGHTBUTTON|TPM_RETURNCMD, x, y, 0, hWndActive, NULL);
+
+ if (tray_menu)
+ {
+ /* You must force a task switch to the application that
+ called TrackPopupMenu at some time in the near future.
+ This is done by posting a benign message to the window. */
+ PostMessage(hWndActive, WM_NULL, 0, 0);
+ }
+
+ if (menuId)
+ {
+ Icallback cb;
+ Ihandle* ih_item = iupwinMenuGetItemHandle((HMENU)ih->handle, menuId);
+ if (!ih_item) return IUP_NOERROR;
+
+ winItemCheckToggle(ih_item);
+
+ cb = IupGetCallback(ih_item, "ACTION");
+ if (cb && cb(ih_item) == IUP_CLOSE)
+ IupExitLoop();
+ }
+
+ return IUP_NOERROR;
+}
+
+
+/*******************************************************************************************/
+
+
+static int winMenuSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ /* must use IupGetAttribute to use inheritance */
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ MENUINFO menuinfo;
+ menuinfo.cbSize = sizeof(MENUINFO);
+ menuinfo.fMask = MIM_BACKGROUND;
+ menuinfo.hbrBack = iupwinBrushGet(RGB(r,g,b));
+ SetMenuInfo((HMENU)ih->handle, &menuinfo);
+ winMenuUpdateBar(ih);
+ }
+ return 1;
+}
+
+static void winMenuChildUnMapMethod(Ihandle* ih)
+{
+ RemoveMenu((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND);
+}
+
+static int winMenuAddParentSubmenu(Ihandle* ih)
+{
+ int pos;
+ MENUITEMINFO menuiteminfo;
+
+ pos = IupGetChildPos(ih->parent, ih);
+ ih->serial = iupMenuGetChildId(ih);
+
+ menuiteminfo.cbSize = sizeof(MENUITEMINFO);
+ menuiteminfo.fMask = MIIM_ID|MIIM_DATA|MIIM_SUBMENU|MIIM_STRING;
+ menuiteminfo.dwTypeData = ""; /* must set or it will be not possible to update */
+ menuiteminfo.cch = 0;
+ menuiteminfo.wID = (UINT)ih->serial;
+ menuiteminfo.dwItemData = (ULONG_PTR)ih;
+ menuiteminfo.hSubMenu = (HMENU)ih->firstchild->handle;
+
+ if (!InsertMenuItem((HMENU)ih->parent->handle, pos, TRUE, &menuiteminfo))
+ return IUP_ERROR;
+
+ ih->handle = ih->parent->handle; /* gets the HMENU of the parent */
+
+ /* must update attributes since submenu is actually created after it is mapped */
+ iupAttribUpdate(ih);
+ iupAttribUpdateFromParent(ih);
+
+ winMenuUpdateBar(ih);
+
+ return IUP_NOERROR;
+}
+
+static int winMenuMapMethod(Ihandle* ih)
+{
+ MENUINFO menuinfo;
+
+ if (iupMenuIsMenuBar(ih))
+ {
+ /* top level menu used for MENU attribute in IupDialog (a menu bar) */
+
+ ih->handle = (InativeHandle*)CreateMenu();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ SetMenu(ih->parent->handle, (HMENU)ih->handle);
+ }
+ else
+ {
+ if (ih->parent)
+ {
+ /* parent is a submenu */
+
+ ih->handle = (InativeHandle*)CreatePopupMenu();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ if (winMenuAddParentSubmenu(ih->parent) == IUP_ERROR)
+ {
+ DestroyMenu((HMENU)ih->handle);
+ return IUP_ERROR;
+ }
+ }
+ else
+ {
+ /* top level menu used for IupPopup */
+
+ ih->handle = (InativeHandle*)CreatePopupMenu();
+ if (!ih->handle)
+ return IUP_ERROR;
+
+ iupAttribSetStr(ih, "_IUPWIN_POPUP_MENU", "1");
+ }
+ }
+
+ menuinfo.cbSize = sizeof(MENUINFO);
+ menuinfo.fMask = MIM_MENUDATA;
+ menuinfo.dwMenuData = (ULONG_PTR)ih;
+
+ if (!iupAttribGetInherit(ih, "_IUPWIN_POPUP_MENU")) /* check in the top level menu using inheritance */
+ {
+ menuinfo.fMask |= MIM_STYLE;
+ menuinfo.dwStyle = MNS_NOTIFYBYPOS;
+ }
+
+ SetMenuInfo((HMENU)ih->handle, &menuinfo);
+
+ winMenuUpdateBar(ih);
+
+ return IUP_NOERROR;
+}
+
+static void winMenuUnMapMethod(Ihandle* ih)
+{
+ if (iupMenuIsMenuBar(ih))
+ SetMenu(ih->parent->handle, NULL);
+
+ DestroyMenu((HMENU)ih->handle); /* DestroyMenu is recursive */
+}
+
+void iupdrvMenuInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winMenuMapMethod;
+ ic->UnMap = winMenuUnMapMethod;
+
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winMenuSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "MENUBGCOLOR", IUPAF_DEFAULT);
+}
+
+
+/*******************************************************************************************/
+
+
+static int winItemSetImageAttrib(Ihandle* ih, const char* value)
+{
+ HBITMAP hBitmapUnchecked, hBitmapChecked;
+ char* impress;
+
+ if (ih->handle == (InativeHandle*)-1) /* check if submenu is actually created */
+ return 1;
+
+ hBitmapUnchecked = iupImageGetImage(value, ih, 0);
+
+ impress = iupAttribGet(ih, "IMPRESS");
+ if (impress)
+ hBitmapChecked = iupImageGetImage(impress, ih, 0);
+ else
+ hBitmapChecked = hBitmapUnchecked;
+
+ SetMenuItemBitmaps((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND, hBitmapUnchecked, hBitmapChecked);
+
+ winMenuUpdateBar(ih);
+
+ return 1;
+}
+
+static int winItemSetImpressAttrib(Ihandle* ih, const char* value)
+{
+ HBITMAP hBitmapUnchecked, hBitmapChecked;
+
+ char *image = iupAttribGet(ih, "IMPRESS");
+ hBitmapUnchecked = iupImageGetImage(image, ih, 0);
+
+ if (value)
+ hBitmapChecked = iupImageGetImage(value, ih, 0);
+ else
+ hBitmapChecked = hBitmapUnchecked;
+
+ SetMenuItemBitmaps((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND, hBitmapUnchecked, hBitmapChecked);
+
+ winMenuUpdateBar(ih);
+
+ return 1;
+}
+
+static int winItemSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ char *str;
+ MENUITEMINFO menuiteminfo;
+
+ if (ih->handle == (InativeHandle*)-1) /* check if submenu is actually created */
+ return 1;
+
+ if (!value)
+ {
+ str = " ";
+ value = str;
+ }
+ else
+ str = iupMenuProcessTitle(ih, value);
+
+ menuiteminfo.cbSize = sizeof(MENUITEMINFO);
+ menuiteminfo.fMask = MIIM_TYPE;
+ menuiteminfo.fType = MFT_STRING;
+ menuiteminfo.dwTypeData = str;
+ menuiteminfo.cch = strlen(str);
+
+ SetMenuItemInfo((HMENU)ih->handle, (UINT)ih->serial, FALSE, &menuiteminfo);
+
+ if (str != value) free(str);
+
+ winMenuUpdateBar(ih);
+
+ return 1;
+}
+
+static int winItemSetTitleImageAttrib(Ihandle* ih, const char* value)
+{
+ HBITMAP hBitmap;
+ MENUITEMINFO menuiteminfo;
+
+ if (ih->handle == (InativeHandle*)-1) /* check if submenu is actually created */
+ return 1;
+
+ hBitmap = iupImageGetImage(value, ih, 0);
+
+ menuiteminfo.cbSize = sizeof(MENUITEMINFO);
+ menuiteminfo.fMask = MIIM_BITMAP;
+ menuiteminfo.hbmpItem = hBitmap;
+
+ SetMenuItemInfo((HMENU)ih->handle, (UINT)ih->serial, FALSE, &menuiteminfo);
+
+ winMenuUpdateBar(ih);
+
+ return 1;
+}
+
+static int winItemSetActiveAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->handle == (InativeHandle*)-1) /* check if submenu is actually created */
+ return 1;
+
+ if (iupStrBoolean(value))
+ EnableMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_ENABLED|MF_BYCOMMAND);
+ else
+ EnableMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_GRAYED|MF_BYCOMMAND);
+
+ winMenuUpdateBar(ih);
+
+ return 0;
+}
+
+static char* winItemGetActiveAttrib(Ihandle* ih)
+{
+ if (ih->handle == (InativeHandle*)-1) /* check if submenu is actually created */
+ return NULL;
+
+ if (GetMenuState((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND) & MF_GRAYED)
+ return "NO";
+ else
+ return "YES";
+}
+
+static int winItemSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (iupAttribGetBoolean(ih->parent, "RADIO"))
+ {
+ int last_pos, pos;
+ winMenuGetLastPos(ih, &last_pos, &pos);
+ CheckMenuRadioItem((HMENU)ih->handle, 0, last_pos, pos, MF_BYPOSITION);
+ }
+ else
+ {
+ if (iupStrBoolean(value))
+ CheckMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_CHECKED|MF_BYCOMMAND);
+ else
+ CheckMenuItem((HMENU)ih->handle, (UINT)ih->serial, MF_UNCHECKED|MF_BYCOMMAND);
+ }
+
+ winMenuUpdateBar(ih);
+
+ return 0;
+}
+
+static char* winItemGetValueAttrib(Ihandle* ih)
+{
+ if (GetMenuState((HMENU)ih->handle, (UINT)ih->serial, MF_BYCOMMAND) & MF_CHECKED)
+ return "ON";
+ else
+ return "OFF";
+}
+
+static int winItemMapMethod(Ihandle* ih)
+{
+ int pos;
+ MENUITEMINFO menuiteminfo;
+
+ if (!ih->parent || !IsMenu((HMENU)ih->parent->handle))
+ return IUP_ERROR;
+
+ pos = IupGetChildPos(ih->parent, ih);
+ ih->serial = iupMenuGetChildId(ih);
+
+ menuiteminfo.cbSize = sizeof(MENUITEMINFO);
+ menuiteminfo.fMask = MIIM_ID|MIIM_DATA|MIIM_STRING;
+ menuiteminfo.dwTypeData = ""; /* must set or it will be not possible to update */
+ menuiteminfo.cch = 0;
+ menuiteminfo.wID = (UINT)ih->serial;
+ menuiteminfo.dwItemData = (ULONG_PTR)ih;
+
+ if (!InsertMenuItem((HMENU)ih->parent->handle, pos, TRUE, &menuiteminfo))
+ return IUP_ERROR;
+
+ ih->handle = ih->parent->handle; /* gets the HMENU of the parent */
+ winMenuUpdateBar(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvItemInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winItemMapMethod;
+ ic->UnMap = winMenuChildUnMapMethod;
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", winItemGetActiveAttrib, winItemSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "MENUBGCOLOR", IUPAF_DEFAULT); /* used by IupImage */
+
+ /* IupItem only */
+ iupClassRegisterAttribute(ic, "VALUE", winItemGetValueAttrib, winItemSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TITLE", NULL, winItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TITLEIMAGE", NULL, winItemSetTitleImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, winItemSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMPRESS", NULL, winItemSetImpressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* Used by iupdrvImageCreateImage */
+ /* necessary because it uses an old HBITMAP solution */
+ iupClassRegisterAttribute(ic, "FLAT_ALPHA", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+}
+
+
+/*******************************************************************************************/
+
+
+static int winSubmenuMapMethod(Ihandle* ih)
+{
+ if (!ih->parent || !IsMenu((HMENU)ih->parent->handle))
+ return IUP_ERROR;
+
+ return iupBaseTypeVoidMapMethod(ih);
+}
+
+void iupdrvSubmenuInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winSubmenuMapMethod;
+
+ /* IupSubmenu only */
+ iupClassRegisterAttribute(ic, "ACTIVE", winItemGetActiveAttrib, winItemSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "TITLE", NULL, winItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, winItemSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "MENUBGCOLOR", IUPAF_DEFAULT); /* used by IupImage */
+
+ /* Used by iupdrvImageCreateImage */
+ /* necessary because it uses an old HBITMAP solution */
+ iupClassRegisterAttribute(ic, "FLAT_ALPHA", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+}
+
+
+/*******************************************************************************************/
+
+
+static int winSeparatorMapMethod(Ihandle* ih)
+{
+ int pos;
+ MENUITEMINFO menuiteminfo;
+
+ if (!ih->parent || !IsMenu((HMENU)ih->parent->handle))
+ return IUP_ERROR;
+
+ pos = IupGetChildPos(ih->parent, ih);
+ ih->serial = iupMenuGetChildId(ih);
+
+ menuiteminfo.cbSize = sizeof(MENUITEMINFO);
+ menuiteminfo.fMask = MIIM_FTYPE|MIIM_ID|MIIM_DATA;
+ menuiteminfo.fType = MFT_SEPARATOR;
+ menuiteminfo.wID = (UINT)ih->serial;
+ menuiteminfo.dwItemData = (ULONG_PTR)ih;
+
+ if (!InsertMenuItem((HMENU)ih->parent->handle, pos, TRUE, &menuiteminfo))
+ return IUP_ERROR;
+
+ ih->handle = ih->parent->handle; /* gets the HMENU of the parent */
+ winMenuUpdateBar(ih);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvSeparatorInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winSeparatorMapMethod;
+ ic->UnMap = winMenuChildUnMapMethod;
+}
diff --git a/iup/src/win/iupwin_messagedlg.c b/iup/src/win/iupwin_messagedlg.c
new file mode 100755
index 0000000..63159aa
--- /dev/null
+++ b/iup/src/win/iupwin_messagedlg.c
@@ -0,0 +1,105 @@
+/** \file
+ * \brief Windows IupMessageDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+
+
+static void winMessageDlgHelpCallback(HELPINFO* HelpInfo)
+{
+ Ihandle* ih = (Ihandle*)HelpInfo->dwContextId;
+ Icallback cb = (Icallback)IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ {
+ if (iupStrEqualNoCase(iupAttribGetStr(ih, "BUTTONS"), "OK")) /* only one button */
+ EndDialog((HWND)HelpInfo->hItemHandle, IDOK);
+ else
+ EndDialog((HWND)HelpInfo->hItemHandle, IDCANCEL);
+ }
+}
+
+static int winMessageDlgPopup(Ihandle* ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ MSGBOXPARAMS MsgBoxParams;
+ int result, num_but = 2;
+ DWORD dwStyle = MB_TASKMODAL;
+ char *icon, *buttons;
+ (void)x;
+ (void)y;
+
+ if (!parent)
+ parent = GetActiveWindow();
+
+ icon = iupAttribGetStr(ih, "DIALOGTYPE");
+ if (iupStrEqualNoCase(icon, "ERROR"))
+ dwStyle |= MB_ICONERROR;
+ else if (iupStrEqualNoCase(icon, "WARNING"))
+ dwStyle |= MB_ICONWARNING;
+ else if (iupStrEqualNoCase(icon, "INFORMATION"))
+ dwStyle |= MB_ICONINFORMATION;
+ else if (iupStrEqualNoCase(icon, "QUESTION"))
+ dwStyle |= MB_ICONQUESTION;
+
+ buttons = iupAttribGetStr(ih, "BUTTONS");
+ if (iupStrEqualNoCase(buttons, "OKCANCEL"))
+ dwStyle |= MB_OKCANCEL;
+ else if (iupStrEqualNoCase(buttons, "YESNO"))
+ dwStyle |= MB_YESNO;
+ else
+ {
+ dwStyle |= MB_OK;
+ num_but = 1;
+ }
+
+ if (IupGetCallback(ih, "HELP_CB"))
+ dwStyle |= MB_HELP;
+
+ if (num_but == 2 && iupAttribGetInt(ih, "BUTTONDEFAULT") == 2)
+ dwStyle |= MB_DEFBUTTON2;
+ else
+ dwStyle |= MB_DEFBUTTON1;
+
+ MsgBoxParams.cbSize = sizeof(MSGBOXPARAMS);
+ MsgBoxParams.hwndOwner = parent;
+ MsgBoxParams.hInstance = NULL;
+ MsgBoxParams.lpszText = iupAttribGet(ih, "VALUE");
+ MsgBoxParams.lpszCaption = iupAttribGet(ih, "TITLE");
+ MsgBoxParams.dwStyle = dwStyle;
+ MsgBoxParams.lpszIcon = NULL;
+ MsgBoxParams.dwContextHelpId = (DWORD_PTR)ih;
+ MsgBoxParams.lpfnMsgBoxCallback = (MSGBOXCALLBACK)winMessageDlgHelpCallback;
+ MsgBoxParams.dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
+
+ result = MessageBoxIndirect(&MsgBoxParams);
+ if (result == 0)
+ {
+ iupAttribSetStr(ih, "BUTTONRESPONSE", NULL);
+ return IUP_ERROR;
+ }
+
+ if (result == IDNO || result == IDCANCEL)
+ iupAttribSetStr(ih, "BUTTONRESPONSE", "2");
+ else
+ iupAttribSetStr(ih, "BUTTONRESPONSE", "1");
+
+ return IUP_NOERROR;
+}
+
+void iupdrvMessageDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = winMessageDlgPopup;
+}
+
+/*
+In Windows it will always sound a beep. The beep is different for each dialog type.
+*/
diff --git a/iup/src/win/iupwin_open.c b/iup/src/win/iupwin_open.c
new file mode 100755
index 0000000..7357cde
--- /dev/null
+++ b/iup/src/win/iupwin_open.c
@@ -0,0 +1,124 @@
+/** \file
+ * \brief Windows Driver Core
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_globalattrib.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_info.h"
+#include "iupwin_handle.h"
+#include "iupwin_brush.h"
+#include "iupwin_draw.h"
+
+
+HINSTANCE iupwin_hinstance = 0;
+int iupwin_comctl32ver6 = 0;
+
+void* iupdrvGetDisplay(void)
+{
+ return NULL;
+}
+
+void iupwinShowLastError(void)
+{
+ int error = GetLastError();
+ if (error)
+ {
+ LPVOID lpMsgBuf;
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
+ MessageBox(NULL, (LPCTSTR)lpMsgBuf, "GetLastError:", MB_OK|MB_ICONERROR);
+ LocalFree(lpMsgBuf);
+ }
+}
+
+static void winSetGlobalColor(int index, const char* name)
+{
+ COLORREF color = GetSysColor(index);
+ iupGlobalSetDefaultColorAttrib(name, (int)GetRValue(color),
+ (int)GetGValue(color),
+ (int)GetBValue(color));
+}
+
+int iupdrvOpen(int *argc, char ***argv)
+{
+ (void)argc; /* unused in the Windows driver */
+ (void)argv;
+
+ if (iupwinGetSystemMajorVersion() < 5) /* older than Windows 2000 */
+ return IUP_ERROR;
+
+ IupSetGlobal("DRIVER", "Win32");
+
+ {
+#ifdef __MINGW32__
+ /* MingW fails to create windows if using a console and HINSTANCE is not from the console */
+ HWND win = GetConsoleWindow();
+ if (win)
+ iupwin_hinstance = (HINSTANCE)GetWindowLongPtr(win, GWLP_HINSTANCE);
+ else
+#endif
+ iupwin_hinstance = GetModuleHandle(NULL);
+ IupSetGlobal("HINSTANCE", (char*)iupwin_hinstance);
+ }
+
+ CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+ {
+ INITCOMMONCONTROLSEX InitCtrls;
+ InitCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ InitCtrls.dwICC = ICC_WIN95_CLASSES; /* trackbar, tooltips, updown, tab, progress */
+ InitCommonControlsEx(&InitCtrls);
+ }
+
+ iupwin_comctl32ver6 = (iupwinGetComCtl32Version() >= 0x060000)? 1: 0;
+ if (iupwin_comctl32ver6 && !iupwinIsAppThemed()) /* When the user seleted the Windows Classic theme */
+ iupwin_comctl32ver6 = 0;
+
+ IupSetGlobal("SYSTEMLANGUAGE", iupwinGetSystemLanguage());
+
+ /* default colors */
+ winSetGlobalColor(COLOR_BTNFACE, "DLGBGCOLOR");
+ winSetGlobalColor(COLOR_BTNTEXT, "DLGFGCOLOR");
+ winSetGlobalColor(COLOR_WINDOW, "TXTBGCOLOR");
+ winSetGlobalColor(COLOR_WINDOWTEXT, "TXTFGCOLOR");
+ winSetGlobalColor(COLOR_MENU, "MENUBGCOLOR");
+ winSetGlobalColor(COLOR_MENUTEXT, "MENUFGCOLOR");
+
+ iupwinHandleInit();
+ iupwinBrushInit();
+ iupwinDrawInit();
+
+#ifdef __WATCOMC__
+ {
+ /* this is used to force Watcom to link the winmain.c module. */
+ void iupwinMainDummy(void);
+ iupwinMainDummy();
+ }
+#endif
+
+ return IUP_NOERROR;
+}
+
+void iupdrvClose(void)
+{
+ iupwinHandleFinish();
+ iupwinBrushFinish();
+
+ CoUninitialize();
+}
diff --git a/iup/src/win/iupwin_progressbar.c b/iup/src/win/iupwin_progressbar.c
new file mode 100755
index 0000000..9038d79
--- /dev/null
+++ b/iup/src/win/iupwin_progressbar.c
@@ -0,0 +1,164 @@
+/** \file
+ * \brief Progress bar Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_progressbar.h"
+#include "iup_drv.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+
+
+#ifndef PBS_MARQUEE /* it is defined only when _WIN32_WINNT >= 0x0501 */
+#define PBS_MARQUEE 0x08
+#define PBM_SETMARQUEE (WM_USER+10)
+#endif
+
+#define IUP_PB_MAX 32000
+
+
+static int winProgressBarSetMarqueeAttrib(Ihandle* ih, const char* value)
+{
+ /* MARQUEE only works when using XP Styles */
+ if (!iupwin_comctl32ver6)
+ return 0;
+
+ if (iupStrBoolean(value))
+ SendMessage(ih->handle, PBM_SETMARQUEE, TRUE, 100);
+ else
+ SendMessage(ih->handle, PBM_SETMARQUEE, FALSE, 0);
+
+ return 1;
+}
+
+static int winProgressBarSetValueAttrib(Ihandle* ih, const char* value)
+{
+ if (!value)
+ ih->data->value = 0;
+ else
+ ih->data->value = atof(value);
+
+ iProgressBarCropValue(ih);
+
+ /* Shows when the marquee style is not set */
+ if (!ih->data->marquee)
+ {
+ double factor = (ih->data->value - ih->data->vmin) / (ih->data->vmax - ih->data->vmin);
+ int val = (int)(IUP_PB_MAX * factor);
+ SendMessage(ih->handle, PBM_SETPOS, (WPARAM)val, 0);
+ }
+
+ return 0;
+}
+
+static int winProgressBarSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+
+ /* Only works when using Classic style */
+ if (iupwin_comctl32ver6)
+ return 0;
+
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ COLORREF color = RGB(r,g,b);
+ SendMessage(ih->handle, PBM_SETBKCOLOR, 0, (LPARAM)color);
+ }
+ else
+ SendMessage(ih->handle, PBM_SETBKCOLOR, 0, (LPARAM)CLR_DEFAULT);
+ return 1;
+}
+
+static int winProgressBarSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+
+ /* Only works when using Classic style */
+ if (iupwin_comctl32ver6)
+ return 0;
+
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ COLORREF color = RGB(r,g,b);
+ SendMessage(ih->handle, PBM_SETBARCOLOR, 0, (LPARAM)color);
+ }
+ else
+ SendMessage(ih->handle, PBM_SETBARCOLOR, 0, (LPARAM)CLR_DEFAULT);
+ return 1;
+}
+
+static int winProgressBarMapMethod(Ihandle* ih)
+{
+ DWORD dwStyle = WS_CHILD;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (iupStrEqualNoCase(iupAttribGetStr(ih, "ORIENTATION"), "VERTICAL"))
+ {
+ dwStyle |= PBS_VERTICAL;
+
+ if (ih->currentheight < ih->currentwidth)
+ {
+ int tmp = ih->currentheight;
+ ih->currentheight = ih->currentwidth;
+ ih->currentwidth = tmp;
+ }
+ }
+
+ if (!iupwin_comctl32ver6 && !iupAttribGetBoolean(ih, "DASHED"))
+ dwStyle |= PBS_SMOOTH;
+
+ if (iupwin_comctl32ver6 && iupAttribGetBoolean(ih, "MARQUEE"))
+ {
+ dwStyle |= PBS_MARQUEE;
+ ih->data->marquee = 1;
+ }
+
+ if (!iupwinCreateWindowEx(ih, PROGRESS_CLASS, 0, dwStyle))
+ return IUP_ERROR;
+
+ /* configure the native range */
+ SendMessage(ih->handle, PBM_SETRANGE, 0, MAKELPARAM(0, IUP_PB_MAX));
+
+ return IUP_NOERROR;
+}
+
+void iupdrvProgressBarInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winProgressBarMapMethod;
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winProgressBarSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ /* Only works when using Classic style */
+ if (iupwin_comctl32ver6)
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, winProgressBarSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT);
+ else
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED);
+
+ /* IupProgressBar only */
+ iupClassRegisterAttribute(ic, "VALUE", iProgressBarGetValueAttrib, winProgressBarSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ORIENTATION", NULL, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MARQUEE", NULL, winProgressBarSetMarqueeAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DASHED", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_tabs.c b/iup/src/win/iupwin_tabs.c
new file mode 100755
index 0000000..682f451
--- /dev/null
+++ b/iup/src/win/iupwin_tabs.c
@@ -0,0 +1,680 @@
+/** \file
+* \brief Tabs Control
+*
+* See Copyright Notice in "iup.h"
+*/
+
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_stdcontrols.h"
+#include "iup_tabs.h"
+#include "iup_image.h"
+#include "iup_array.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_draw.h"
+#include "iupwin_info.h"
+
+
+int iupdrvTabsExtraDecor(Ihandle* ih)
+{
+ (void)ih;
+ return 0;
+}
+
+int iupdrvTabsGetLineCountAttrib(Ihandle* ih)
+{
+ return (int)SendMessage(ih->handle, TCM_GETROWCOUNT, 0, 0);
+}
+
+static HWND winTabsGetPageWindow(Ihandle* ih, int pos)
+{
+ TCITEM tie;
+ tie.mask = TCIF_PARAM;
+ SendMessage(ih->handle, TCM_GETITEM, pos, (LPARAM)&tie);
+ return (HWND)tie.lParam;
+}
+
+void iupdrvTabsSetCurrentTab(Ihandle* ih, int pos)
+{
+ int prev_pos = SendMessage(ih->handle, TCM_GETCURSEL, 0, 0);
+ HWND tab_page = winTabsGetPageWindow(ih, prev_pos);
+ ShowWindow(tab_page, SW_HIDE);
+
+ SendMessage(ih->handle, TCM_SETCURSEL, pos, 0);
+
+ tab_page = winTabsGetPageWindow(ih, pos);
+ ShowWindow(tab_page, SW_SHOW);
+}
+
+int iupdrvTabsGetCurrentTab(Ihandle* ih)
+{
+ return (int)SendMessage(ih->handle, TCM_GETCURSEL, 0, 0);
+}
+
+static int winTabsGetImageIndex(Ihandle* ih, const char* name)
+{
+ HIMAGELIST image_list;
+ int count, i, bpp, ret;
+ Iarray* bmp_array;
+ HBITMAP *bmp_array_data, hMask=NULL;
+ HBITMAP bmp = iupImageGetImage(name, ih, 0);
+ if (!bmp)
+ return -1;
+
+ /* the array is used to avoi adding the same bitmap twice */
+ bmp_array = (Iarray*)iupAttribGet(ih, "_IUPWIN_BMPARRAY");
+ if (!bmp_array)
+ {
+ /* create the array if does not exist */
+ bmp_array = iupArrayCreate(50, sizeof(HBITMAP));
+ iupAttribSetStr(ih, "_IUPWIN_BMPARRAY", (char*)bmp_array);
+ }
+
+ bmp_array_data = iupArrayGetData(bmp_array);
+
+ image_list = (HIMAGELIST)SendMessage(ih->handle, TCM_GETIMAGELIST, 0, 0);
+ if (!image_list)
+ {
+ int width, height;
+ UINT flags = ILC_COLOR32|ILC_MASK;
+
+ /* must use this info, since image can be a driver image loaded from resources */
+ iupdrvImageGetInfo(bmp, &width, &height, &bpp);
+
+ /* create the image list if does not exist */
+ image_list = ImageList_Create(width, height, flags, 0, 50);
+ SendMessage(ih->handle, TCM_SETIMAGELIST, 0, (LPARAM)image_list);
+ }
+ else
+ iupdrvImageGetInfo(bmp, NULL, NULL, &bpp);
+
+ /* check if that bitmap is already added to the list,
+ but we can not compare with the actual bitmap at the list since it is a copy */
+ count = ImageList_GetImageCount(image_list);
+ for (i=0; i<count; i++)
+ {
+ if (bmp_array_data[i] == bmp)
+ return i;
+ }
+
+ if (bpp == 8)
+ {
+ Ihandle* image = IupGetHandle(name);
+ if (image)
+ {
+ iupAttribSetStr(image, "_IUPIMG_NO_INVERT", "1");
+ hMask = iupdrvImageCreateMask(image);
+ iupAttribSetStr(image, "_IUPIMG_NO_INVERT", NULL);
+ }
+ }
+
+ bmp_array_data = iupArrayInc(bmp_array);
+ bmp_array_data[i] = bmp;
+ ret = ImageList_Add(image_list, bmp, hMask); /* the bmp is duplicated at the list */
+ DeleteObject(hMask);
+ return ret;
+}
+
+static int winTabsGetPageWindowPos(Ihandle* ih, HWND tab_page)
+{
+ TCITEM tie;
+ int pos, num_tabs;
+
+ num_tabs = (int)SendMessage(ih->handle, TCM_GETITEMCOUNT, 0, 0);
+ tie.mask = TCIF_PARAM;
+
+ for (pos=0; pos<num_tabs; pos++)
+ {
+ SendMessage(ih->handle, TCM_GETITEM, pos, (LPARAM)&tie);
+ if (tab_page == (HWND)tie.lParam)
+ return pos;
+ }
+
+ return -1;
+}
+
+static void winTabsPlacePageWindows(Ihandle* ih, int w, int h)
+{
+ TCITEM tie;
+ int pos, num_tabs;
+ RECT rect;
+
+ num_tabs = (int)SendMessage(ih->handle, TCM_GETITEMCOUNT, 0, 0);
+ tie.mask = TCIF_PARAM;
+
+ /* Calculate the display rectangle, assuming the
+ tab control is the size of the client area. */
+ SetRect(&rect, 0, 0, w, h);
+ SendMessage(ih->handle, TCM_ADJUSTRECT, FALSE, (LPARAM)&rect);
+
+ for (pos=0; pos<num_tabs; pos++)
+ {
+ SendMessage(ih->handle, TCM_GETITEM, pos, (LPARAM)&tie);
+
+ SetWindowPos((HWND)tie.lParam, NULL,
+ rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top,
+ SWP_NOACTIVATE|SWP_NOZORDER);
+ }
+}
+
+static int winTabsUsingXPStyles(Ihandle* ih)
+{
+ return iupwin_comctl32ver6 && ih->data->type == ITABS_TOP;
+}
+
+static void winTabsDrawPageBackground(Ihandle* ih, HDC hDC, RECT* rect)
+{
+ unsigned char r=0, g=0, b=0;
+ char* color = iupAttribGetInheritNativeParent(ih, "BGCOLOR");
+ if (!color) color = iupAttribGetInheritNativeParent(ih, "BACKGROUND");
+ if (!color) color = iupAttribGet(ih, "BACKGROUND");
+ if (!color) color = IupGetGlobal("DLGBGCOLOR");
+ iupStrToRGB(color, &r, &g, &b);
+ SetDCBrushColor(hDC, RGB(r,g,b));
+ FillRect(hDC, rect, (HBRUSH)GetStockObject(DC_BRUSH));
+}
+
+static LRESULT CALLBACK winTabsPageWinProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ switch (msg)
+ {
+ case WM_ERASEBKGND:
+ {
+ RECT rect;
+ HDC hDC = (HDC)wp;
+ Ihandle* ih = iupwinHandleGet(hWnd);
+ GetClientRect(ih->handle, &rect);
+ winTabsDrawPageBackground(ih, hDC, &rect);
+
+ /* return non zero value */
+ return 1;
+ }
+ case WM_COMMAND:
+ case WM_CTLCOLORSCROLLBAR:
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLORSTATIC:
+ case WM_DRAWITEM:
+ case WM_HSCROLL:
+ case WM_NOTIFY:
+ case WM_VSCROLL:
+ /* Forward the container messages to its parent. */
+ return SendMessage(GetParent(hWnd), msg, wp, lp);
+ }
+
+ return DefWindowProc(hWnd, msg, wp, lp);
+}
+
+static HWND winTabCreatePageWindow(Ihandle* ih)
+{
+ HWND hWnd;
+ DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS,
+ dwExStyle = 0;
+
+ if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED"))
+ dwExStyle |= WS_EX_COMPOSITED;
+ else
+ dwStyle |= WS_CLIPCHILDREN;
+
+ hWnd = CreateWindowEx(dwExStyle, "IupTabsPage", NULL, dwStyle,
+ 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
+ ih->handle, NULL, iupwin_hinstance, NULL);
+
+ iupwinHandleAdd(ih, hWnd);
+
+ return hWnd;
+}
+
+/* ------------------------------------------------------------------------- */
+/* winTabs - Sets and Gets accessors */
+/* ------------------------------------------------------------------------- */
+
+static int winTabsSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+
+ if (ih->handle)
+ SendMessage(ih->handle, TCM_SETPADDING, 0, MAKELPARAM(ih->data->horiz_padding, ih->data->vert_padding));
+
+ return 0;
+}
+
+static int winTabsSetMultilineAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->handle) /* allow to set only before mapping */
+ return 0;
+
+ if (iupStrBoolean(value))
+ ih->data->is_multiline = 1;
+ else
+ {
+ if (ih->data->type == ITABS_BOTTOM || ih->data->type == ITABS_TOP)
+ ih->data->is_multiline = 0;
+ else
+ ih->data->is_multiline = 1; /* always true if left/right */
+ }
+
+ return 0;
+}
+
+static char* winTabsGetMultilineAttrib(Ihandle* ih)
+{
+ if (ih->data->is_multiline)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int winTabsSetTabTypeAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->handle) /* allow to set only before mapping */
+ return 0;
+
+ if(iupStrEqualNoCase(value, "BOTTOM"))
+ {
+ ih->data->is_multiline = 0;
+ ih->data->type = ITABS_BOTTOM;
+ ih->data->orientation = ITABS_HORIZONTAL;
+ }
+ else if(iupStrEqualNoCase(value, "LEFT"))
+ {
+ ih->data->type = ITABS_LEFT;
+ ih->data->orientation = ITABS_VERTICAL;
+ ih->data->is_multiline = 1; /* VERTICAL works only with MULTILINE */
+ }
+ else if(iupStrEqualNoCase(value, "RIGHT"))
+ {
+ ih->data->is_multiline = 1; /* VERTICAL works only with MULTILINE */
+ ih->data->type = ITABS_RIGHT;
+ ih->data->orientation = ITABS_VERTICAL;
+ }
+ else /* "TOP" */
+ {
+ ih->data->is_multiline = 0;
+ ih->data->type = ITABS_TOP;
+ ih->data->orientation = ITABS_HORIZONTAL;
+ }
+
+ return 0;
+}
+
+static int winTabsSetTabTitleAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ int pos;
+ if (value && iupStrToInt(name_id, &pos)==1)
+ {
+ TCITEM tie;
+
+ tie.mask = TCIF_TEXT;
+ tie.pszText = (char*)value;
+ tie.cchTextMax = strlen(value);
+
+ SendMessage(ih->handle, TCM_SETITEM, pos, (LPARAM)&tie);
+ }
+ return 1;
+}
+
+static int winTabsSetTabImageAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ int pos;
+ if (value && iupStrToInt(name_id, &pos)==1)
+ {
+ TCITEM tie;
+
+ tie.mask = TCIF_IMAGE;
+ tie.iImage = winTabsGetImageIndex(ih, value);
+
+ SendMessage(ih->handle, TCM_SETITEM, pos, (LPARAM)&tie);
+ }
+ return 1;
+}
+
+static char* winTabsGetBgColorAttrib(Ihandle* ih)
+{
+ /* the most important use of this is to provide
+ the correct background for images */
+ if (iupwin_comctl32ver6)
+ {
+ COLORREF cr;
+ if (iupwinDrawGetThemeTabsBgColor(ih->handle, &cr))
+ {
+ char* str = iupStrGetMemory(20);
+ sprintf(str, "%d %d %d", (int)GetRValue(cr), (int)GetGValue(cr), (int)GetBValue(cr));
+ return str;
+ }
+ }
+
+ return IupGetGlobal("DLGBGCOLOR");
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* winTabs - Calls the user callback to change of tab */
+/* ------------------------------------------------------------------------- */
+
+static int winTabsCtlColor(Ihandle* ih, HDC hdc, LRESULT *result)
+{
+ /* works only when NOT winTabsUsingXPStyles */
+ unsigned char r, g, b;
+ char* color = iupBaseNativeParentGetBgColorAttrib(ih);
+ if (iupStrToRGB(color, &r, &g, &b))
+ {
+ SetDCBrushColor(hdc, RGB(r,g,b));
+ *result = (LRESULT)GetStockObject(DC_BRUSH);
+ return 1;
+ }
+ return 0;
+}
+
+static int winTabsWmNotify(Ihandle* ih, NMHDR* msg_info, int *result)
+{
+ (void)result;
+
+ if (msg_info->code == TCN_SELCHANGING)
+ {
+ IFnnn cb = (IFnnn)IupGetCallback(ih, "TABCHANGE_CB");
+ int prev_pos = SendMessage(ih->handle, TCM_GETCURSEL, 0, 0);
+ iupAttribSetInt(ih, "_IUPTABS_PREV_CHILD_POS", prev_pos);
+
+ if (cb)
+ {
+ Ihandle* prev_child = IupGetChild(ih, prev_pos);
+ iupAttribSetStr(ih, "_IUPTABS_PREV_CHILD", (char*)prev_child);
+ }
+ }
+
+ if (msg_info->code == TCN_SELCHANGE)
+ {
+ IFnnn cb = (IFnnn)IupGetCallback(ih, "TABCHANGE_CB");
+ int pos = SendMessage(ih->handle, TCM_GETCURSEL, 0, 0);
+ int prev_pos = iupAttribGetInt(ih, "_IUPTABS_PREV_CHILD_POS");
+ HWND tab_page = winTabsGetPageWindow(ih, pos);
+ ShowWindow(tab_page, SW_SHOW);
+ tab_page = winTabsGetPageWindow(ih, prev_pos);
+ ShowWindow(tab_page, SW_HIDE);
+
+ if (cb)
+ {
+ Ihandle* child = IupGetChild(ih, pos);
+ Ihandle* prev_child = (Ihandle*)iupAttribGet(ih, "_IUPTABS_PREV_CHILD");
+ iupAttribSetStr(ih, "_IUPTABS_PREV_CHILD", NULL);
+
+ cb(ih, child, prev_child);
+ }
+ }
+
+ return 0; /* result not used */
+}
+
+static int winTabsProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ switch(msg)
+ {
+ case WM_SIZE:
+ {
+ WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB");
+ CallWindowProc(oldProc, ih->handle, msg, wp, lp);
+
+ winTabsPlacePageWindows(ih, LOWORD(lp), HIWORD(lp));
+
+ *result = 0;
+ return 1;
+ }
+ }
+
+ return iupwinBaseContainerProc(ih, msg, wp, lp, result);
+}
+
+/* ------------------------------------------------------------------------- */
+/* winTabs - Methods and Init Class */
+/* ------------------------------------------------------------------------- */
+
+static void winTabsChildAddedMethod(Ihandle* ih, Ihandle* child)
+{
+ if (IupGetName(child) == NULL)
+ iupAttribSetHandleName(child);
+
+ if (ih->handle)
+ {
+ TCITEM tie;
+ HWND tab_page;
+ char *tabtitle, *tabimage;
+ int pos, old_rowcount;
+ RECT rect;
+
+ pos = IupGetChildPos(ih, child);
+
+ tab_page = winTabCreatePageWindow(ih);
+
+ if (pos == 0)
+ ShowWindow(tab_page, SW_SHOW);
+
+ tabtitle = iupAttribGet(child, "TABTITLE");
+ if (!tabtitle) tabtitle = iupTabsAttribGetStrId(ih, "TABTITLE", pos);
+ tabimage = iupAttribGet(child, "TABIMAGE");
+ if (!tabimage) tabimage = iupTabsAttribGetStrId(ih, "TABIMAGE", pos);
+ if (!tabtitle && !tabimage)
+ tabtitle = " ";
+
+ old_rowcount = (int)SendMessage(ih->handle, TCM_GETROWCOUNT, 0, 0);
+
+ tie.mask = TCIF_PARAM;
+
+ if (tabtitle)
+ {
+ tie.mask |= TCIF_TEXT;
+ tie.pszText = tabtitle;
+ tie.cchTextMax = strlen(tabtitle);
+ }
+
+ if (tabimage)
+ {
+ tie.mask |= TCIF_IMAGE;
+ tie.iImage = winTabsGetImageIndex(ih, tabimage);
+ }
+
+ /* create tabs and label them */
+ tie.lParam = (LPARAM)tab_page;
+ SendMessage(ih->handle, TCM_INSERTITEM, pos, (LPARAM)&tie);
+
+ /* Calculate the display rectangle, assuming the
+ tab control is the size of the client area. */
+ GetClientRect(ih->handle, &rect);
+ SendMessage(ih->handle, TCM_ADJUSTRECT, FALSE, (LPARAM)&rect);
+
+ SetWindowPos(tab_page, NULL,
+ rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top,
+ SWP_NOACTIVATE|SWP_NOZORDER);
+
+ iupAttribSetStr(child, "_IUPTAB_CONTAINER", (char*)tab_page);
+
+ if (ih->data->is_multiline)
+ {
+ if (ih->data->type == ITABS_LEFT || ih->data->type == ITABS_RIGHT)
+ {
+ int rowcount = (int)SendMessage(ih->handle, TCM_GETROWCOUNT, 0, 0);
+ if (rowcount != old_rowcount)
+ {
+ GetClientRect(ih->handle, &rect);
+ winTabsPlacePageWindows(ih, rect.right - rect.left, rect.bottom - rect.top);
+ }
+ }
+
+ iupdrvDisplayRedraw(ih);
+ }
+ }
+}
+
+static void winTabsChildRemovedMethod(Ihandle* ih, Ihandle* child)
+{
+ if (ih->handle)
+ {
+ HWND tab_page = (HWND)iupAttribGet(child, "_IUPTAB_CONTAINER");
+ if (tab_page)
+ {
+ int pos = winTabsGetPageWindowPos(ih, tab_page);
+ SendMessage(ih->handle, TCM_DELETEITEM, pos, 0);
+ DestroyWindow(tab_page);
+
+ if (pos==0) pos++;
+ iupdrvTabsSetCurrentTab(ih, pos-1);
+
+ iupAttribSetStr(child, "_IUPTAB_CONTAINER", NULL);
+ }
+ }
+}
+
+static int winTabsMapMethod(Ihandle* ih)
+{
+ DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | TCS_HOTTRACK | WS_TABSTOP,
+ dwExStyle = 0;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (ih->data->type == ITABS_BOTTOM)
+ dwStyle |= TCS_BOTTOM;
+ else if (ih->data->type == ITABS_RIGHT)
+ dwStyle |= TCS_VERTICAL|TCS_RIGHT;
+ else if (ih->data->type == ITABS_LEFT)
+ dwStyle |= TCS_VERTICAL;
+
+ if (ih->data->is_multiline)
+ dwStyle |= TCS_MULTILINE;
+
+ if (iupAttribGetBoolean(IupGetDialog(ih), "COMPOSITED"))
+ {
+ dwExStyle |= WS_EX_COMPOSITED;
+
+ if (!ih->data->is_multiline && iupwinIsVista())
+ {
+ /* workaround for composite bug in Vista */
+ ih->data->is_multiline = 1;
+ dwStyle |= TCS_MULTILINE;
+ }
+ }
+ else
+ dwStyle |= WS_CLIPCHILDREN;
+
+ if (!iupwinCreateWindowEx(ih, WC_TABCONTROL, dwExStyle, dwStyle))
+ return IUP_ERROR;
+
+ /* replace the WinProc to handle other messages */
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winTabsProc);
+
+ /* Process WM_NOTIFY */
+ IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winTabsWmNotify);
+
+ /* Process background color */
+ IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winTabsCtlColor);
+
+ if (iupwin_comctl32ver6 && ih->data->type != ITABS_TOP)
+ {
+ /* XP Styles support only TABTYPE=TOP */
+ iupwinDrawRemoveTheme(ih->handle);
+ }
+
+ /* Change children background */
+ if (winTabsUsingXPStyles(ih))
+ {
+ char* color = iupAttribGetInheritNativeParent(ih, "BGCOLOR");
+ if (!color)
+ color = iupAttribGetInheritNativeParent(ih, "BACKGROUND");
+ if (!color)
+ {
+ COLORREF cr;
+ if (iupwinDrawGetThemeTabsBgColor(ih->handle, &cr))
+ iupAttribSetStrf(ih, "BACKGROUND", "%d %d %d", (int)GetRValue(cr), (int)GetGValue(cr), (int)GetBValue(cr));
+ }
+ }
+
+ /* Create pages and tabs */
+ if (ih->firstchild)
+ {
+ Ihandle* child;
+ for (child = ih->firstchild; child; child = child->brother)
+ winTabsChildAddedMethod(ih, child);
+ }
+
+ return IUP_NOERROR;
+}
+
+static void winTabsUnMapMethod(Ihandle* ih)
+{
+ Iarray* bmp_array;
+
+ HIMAGELIST image_list = (HIMAGELIST)SendMessage(ih->handle, TCM_GETIMAGELIST, 0, 0);
+ if (image_list)
+ ImageList_Destroy(image_list);
+
+ bmp_array = (Iarray*)iupAttribGet(ih, "_IUPWIN_BMPARRAY");
+ if (bmp_array)
+ iupArrayDestroy(bmp_array);
+
+ iupdrvBaseUnMapMethod(ih);
+}
+
+static void winTabsRegisterClass(void)
+{
+ WNDCLASS wndclass;
+ ZeroMemory(&wndclass, sizeof(WNDCLASS));
+
+ wndclass.hInstance = iupwin_hinstance;
+ wndclass.lpszClassName = "IupTabsPage";
+ wndclass.lpfnWndProc = (WNDPROC)winTabsPageWinProc;
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.style = CS_PARENTDC;
+ wndclass.hbrBackground = NULL; /* remove the background to optimize redraw */
+
+ RegisterClass(&wndclass);
+}
+
+void iupdrvTabsInitClass(Iclass* ic)
+{
+ if (!iupwinClassExist("IupTabsPage"))
+ winTabsRegisterClass();
+
+ /* Driver Dependent Class functions */
+ ic->Map = winTabsMapMethod;
+ ic->UnMap = winTabsUnMapMethod;
+ ic->ChildAdded = winTabsChildAddedMethod;
+ ic->ChildRemoved = winTabsChildRemovedMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", winTabsGetBgColorAttrib, NULL, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_NOT_MAPPED);
+
+ /* IupTabs only */
+ iupClassRegisterAttribute(ic, "TABTYPE", iupTabsGetTabTypeAttrib, winTabsSetTabTypeAttrib, IUPAF_SAMEASSYSTEM, "TOP", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TABORIENTATION", iupTabsGetTabOrientationAttrib, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); /* can not be set, depends on TABTYPE in Windows */
+ iupClassRegisterAttribute(ic, "MULTILINE", winTabsGetMultilineAttrib, winTabsSetMultilineAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "TABTITLE", NULL, winTabsSetTabTitleAttrib, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "TABIMAGE", NULL, winTabsSetTabImageAttrib, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, winTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+}
diff --git a/iup/src/win/iupwin_text.c b/iup/src/win/iupwin_text.c
new file mode 100755
index 0000000..dfe489a
--- /dev/null
+++ b/iup/src/win/iupwin_text.c
@@ -0,0 +1,1993 @@
+/** \file
+ * \brief Text Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+#include <richedit.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_mask.h"
+#include "iup_drv.h"
+#include "iup_drvfont.h"
+#include "iup_array.h"
+#include "iup_text.h"
+#include "iup_key.h"
+#include "iup_dialog.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+
+/* Cygwin and MingW Win32api does not define these */
+
+#ifndef PFN_ARABIC
+#define PFN_ARABIC 2
+#define PFN_LCLETTER 3
+#define PFN_UCLETTER 4
+#define PFN_LCROMAN 5
+#define PFN_UCROMAN 6
+#endif
+
+#ifndef PFNS_PAREN
+#define PFNS_PAREN 0x000
+#define PFNS_PARENS 0x100
+#define PFNS_PERIOD 0x200
+#define PFNS_PLAIN 0x300
+#define PFNS_NONUMBER 0x400
+#endif
+
+#ifndef CFM_BACKCOLOR
+#define CFM_BACKCOLOR 0x04000000
+#define CFM_UNDERLINETYPE 0x00800000
+#define CFM_WEIGHT 0x00400000
+#define CFM_DISABLED 0x2000
+#define CFE_DISABLED CFM_DISABLED
+#endif
+
+#ifndef CFU_UNDERLINEDOTTED
+#define CFU_UNDERLINEDOTTED 4
+#define CFU_UNDERLINEDOUBLE 3
+#define CFU_UNDERLINE 1
+#define CFU_UNDERLINENONE 0
+#endif
+
+#ifndef SES_UPPERCASE
+#define SES_UPPERCASE 512
+#define SES_LOWERCASE 1024
+#endif
+/* End Cygwin/MingW */
+
+#ifndef EM_SETCUEBANNER /* defined only if _WIN32_WINNT >= 0x501 */
+#define ECM_FIRST 0x1500 /* Edit control messages */
+#define EM_SETCUEBANNER (ECM_FIRST + 1)
+#endif
+
+#define WM_CARET WM_APP+1 /* Custom IUP message */
+
+
+void iupdrvTextAddSpin(int *w, int h)
+{
+ *w += h;
+}
+
+void iupdrvTextAddBorders(int *w, int *h)
+{
+ int border_size = 2*3;
+ (*w) += border_size;
+ (*h) += border_size;
+}
+
+static void winTextParseParagraphFormat(Ihandle* formattag, PARAFORMAT2 *paraformat, int convert2twips)
+{
+ int val;
+ char* format;
+
+ ZeroMemory(paraformat, sizeof(PARAFORMAT2));
+ paraformat->cbSize = sizeof(PARAFORMAT2);
+
+ format = iupAttribGet(formattag, "NUMBERING");
+ if (format)
+ {
+ paraformat->dwMask |= PFM_NUMBERING;
+
+ if (iupStrEqualNoCase(format, "BULLET"))
+ paraformat->wNumbering = PFN_BULLET;
+ else if (iupStrEqualNoCase(format, "ARABIC"))
+ paraformat->wNumbering = PFN_ARABIC;
+ else if (iupStrEqualNoCase(format, "LCLETTER"))
+ paraformat->wNumbering = PFN_LCLETTER;
+ else if (iupStrEqualNoCase(format, "UCLETTER"))
+ paraformat->wNumbering = PFN_UCLETTER;
+ else if (iupStrEqualNoCase(format, "LCROMAN"))
+ paraformat->wNumbering = PFN_LCROMAN;
+ else if (iupStrEqualNoCase(format, "UCROMAN"))
+ paraformat->wNumbering = PFN_UCROMAN;
+ else
+ paraformat->wNumbering = 0; /* "NONE" */
+
+ format = iupAttribGet(formattag, "NUMBERINGSTYLE");
+ if (format)
+ {
+ paraformat->dwMask |= PFM_NUMBERINGSTYLE;
+
+ if (iupStrEqualNoCase(format, "RIGHTPARENTESES"))
+ paraformat->wNumberingStyle = PFNS_PAREN;
+ else if (iupStrEqualNoCase(format, "PARENTESES"))
+ paraformat->wNumberingStyle = PFNS_PARENS;
+ else if (iupStrEqualNoCase(format, "PERIOD"))
+ paraformat->wNumberingStyle = PFNS_PERIOD;
+ else if (iupStrEqualNoCase(format, "NONUMBER"))
+ paraformat->wNumberingStyle = PFNS_NONUMBER;
+ else
+ paraformat->wNumberingStyle = PFNS_PLAIN; /* "NONE" */
+ }
+
+ format = iupAttribGet(formattag, "NUMBERINGTAB");
+ if (format && iupStrToInt(format, &val))
+ {
+ paraformat->dwMask |= PFM_NUMBERINGTAB;
+ paraformat->wNumberingTab = (WORD)(val*convert2twips);
+ }
+ }
+
+ format = iupAttribGet(formattag, "INDENT");
+ if (format && iupStrToInt(format, &val))
+ {
+ paraformat->dwMask |= PFM_STARTINDENT|PFM_RIGHTINDENT|PFM_OFFSET;
+ paraformat->dxStartIndent = val*convert2twips;
+
+ format = iupAttribGet(formattag, "INDENTRIGHT");
+ if (format && iupStrToInt(format, &val))
+ paraformat->dxRightIndent = val*convert2twips;
+ else
+ paraformat->dxRightIndent = paraformat->dxStartIndent;
+
+ format = iupAttribGet(formattag, "INDENTOFFSET");
+ if (format && iupStrToInt(format, &val))
+ paraformat->dxOffset = val*convert2twips;
+ else
+ paraformat->dxOffset = 0;
+ }
+
+ format = iupAttribGet(formattag, "ALIGNMENT");
+ if (format)
+ {
+ paraformat->dwMask |= PFM_ALIGNMENT;
+
+ if (iupStrEqualNoCase(format, "JUSTIFY"))
+ paraformat->wAlignment = PFA_JUSTIFY;
+ else if (iupStrEqualNoCase(format, "RIGHT"))
+ paraformat->wAlignment = PFA_RIGHT;
+ else if (iupStrEqualNoCase(format, "CENTER"))
+ paraformat->wAlignment = PFA_CENTER;
+ else
+ paraformat->wAlignment = PFA_LEFT; /* "LEFT" */
+ }
+
+ format = iupAttribGet(formattag, "TABSARRAY");
+ if (format)
+ {
+ int pos, align, i = 0;
+ LONG tab;
+ char* str;
+
+ paraformat->dwMask |= PFM_TABSTOPS;
+
+ while (format)
+ {
+ str = iupStrCopyUntil((char**)&format, ' ');
+ if (!str) break;
+ pos = atoi(str)*convert2twips;
+ free(str);
+
+ str = iupStrCopyUntil((char**)&format, ' ');
+ if (!str) break;
+
+ if (iupStrEqualNoCase(str, "DECIMAL"))
+ align = 3;
+ else if (iupStrEqualNoCase(str, "RIGHT"))
+ align = 2;
+ else if (iupStrEqualNoCase(str, "CENTER"))
+ align = 1;
+ else /* "LEFT" */
+ align = 0;
+ free(str);
+
+ tab = (pos&0xFFF)|(align<<24);
+ paraformat->rgxTabs[i] = tab;
+ i++;
+ if (i == 32) break;
+ }
+ paraformat->cTabCount = (SHORT)i;
+ }
+
+ format = iupAttribGet(formattag, "SPACEBEFORE");
+ if (format && iupStrToInt(format, &val))
+ {
+ paraformat->dwMask |= PFM_SPACEBEFORE;
+ paraformat->dySpaceBefore = val*convert2twips;
+ }
+
+ format = iupAttribGet(formattag, "SPACEAFTER");
+ if (format && iupStrToInt(format, &val))
+ {
+ paraformat->dwMask |= PFM_SPACEAFTER;
+ paraformat->dySpaceAfter = val*convert2twips;
+ }
+
+ format = iupAttribGet(formattag, "LINESPACING");
+ if (format)
+ {
+ paraformat->dwMask |= PFM_LINESPACING;
+
+ if (iupStrEqualNoCase(format, "SINGLE"))
+ paraformat->bLineSpacingRule = 0;
+ else if (iupStrEqualNoCase(format, "ONEHALF"))
+ paraformat->bLineSpacingRule = 1;
+ else if (iupStrEqualNoCase(format, "DOUBLE"))
+ paraformat->bLineSpacingRule = 2;
+ else if (iupStrToInt(format, &val))
+ {
+ paraformat->bLineSpacingRule = 3;
+ paraformat->dyLineSpacing = val*convert2twips;
+ }
+ }
+}
+
+static void winTextParseCharacterFormat(Ihandle* formattag, CHARFORMAT2 *charformat, int pixel2twips)
+{
+ int val;
+ char* format;
+
+ ZeroMemory(charformat, sizeof(CHARFORMAT2));
+ charformat->cbSize = sizeof(CHARFORMAT2);
+
+ format = iupAttribGet(formattag, "DISABLED");
+ if (format)
+ {
+ charformat->dwMask |= CFM_DISABLED;
+ if (iupStrBoolean(format))
+ charformat->dwEffects |= CFE_DISABLED;
+ }
+
+ format = iupAttribGet(formattag, "RISE");
+ if (format)
+ {
+ if (iupStrEqualNoCase(format, "SUPERSCRIPT"))
+ {
+ charformat->dwMask |= CFM_SUPERSCRIPT;
+ charformat->dwEffects |= CFE_SUPERSCRIPT;
+ }
+ else if (iupStrEqualNoCase(format, "SUBSCRIPT"))
+ {
+ charformat->dwMask |= CFM_SUBSCRIPT;
+ charformat->dwEffects |= CFE_SUBSCRIPT;
+ }
+ else if (iupStrToInt(format, &val))
+ {
+ charformat->dwMask |= CFM_OFFSET;
+ charformat->yOffset = val;
+ }
+ }
+
+ format = iupAttribGet(formattag, "ITALIC");
+ if (format)
+ {
+ charformat->dwMask |= CFM_ITALIC;
+ if (iupStrBoolean(format))
+ charformat->dwEffects |= CFE_ITALIC;
+ }
+
+ format = iupAttribGet(formattag, "STRIKEOUT");
+ if (format)
+ {
+ charformat->dwMask |= CFM_STRIKEOUT;
+ if (iupStrBoolean(format))
+ charformat->dwEffects |= CFE_STRIKEOUT;
+ }
+
+ format = iupAttribGet(formattag, "PROTECTED");
+ if (format)
+ {
+ charformat->dwMask |= CFM_PROTECTED;
+ if (iupStrBoolean(format))
+ charformat->dwEffects |= CFE_PROTECTED;
+ }
+
+ format = iupAttribGet(formattag, "FONTSIZE");
+ if (format && iupStrToInt(format, &val))
+ {
+ /* (1/1440 of an inch, or 1/20 of a printer's point) */
+ charformat->dwMask |= CFM_SIZE;
+ if (val < 0) /* in pixels */
+ charformat->yHeight = (-val)*pixel2twips;
+ else
+ charformat->yHeight = val*20;
+ }
+
+ format = iupAttribGet(formattag, "FONTSCALE");
+ if (format && charformat->yHeight != 0)
+ {
+ float fval = 0;
+ if (iupStrEqualNoCase(format, "XX-SMALL"))
+ fval = 0.5787037037037f;
+ else if (iupStrEqualNoCase(format, "X-SMALL"))
+ fval = 0.6444444444444f;
+ else if (iupStrEqualNoCase(format, "SMALL"))
+ fval = 0.8333333333333f;
+ else if (iupStrEqualNoCase(format, "MEDIUM"))
+ fval = 1.0f;
+ else if (iupStrEqualNoCase(format, "LARGE"))
+ fval = 1.2f;
+ else if (iupStrEqualNoCase(format, "X-LARGE"))
+ fval = 1.4399999999999f;
+ else if (iupStrEqualNoCase(format, "XX-LARGE"))
+ fval = 1.728f;
+ else
+ iupStrToFloat(format, &fval);
+
+ if (fval > 0)
+ {
+ fval = ((float)charformat->yHeight)*fval;
+ charformat->yHeight = iupROUND(fval);
+ }
+ }
+
+ format = iupAttribGet(formattag, "FONTFACE");
+ if (format)
+ {
+ charformat->dwMask |= CFM_FACE;
+ strcpy(charformat->szFaceName, format);
+ }
+
+ format = iupAttribGet(formattag, "FGCOLOR");
+ if (format)
+ {
+ unsigned char r, g, b;
+ if (iupStrToRGB(format, &r, &g, &b))
+ {
+ charformat->dwMask |= CFM_COLOR;
+ charformat->crTextColor = RGB(r, g, b);
+ }
+ }
+
+ format = iupAttribGet(formattag, "BGCOLOR");
+ if (format)
+ {
+ unsigned char r, g, b;
+ if (iupStrToRGB(format, &r, &g, &b))
+ {
+ charformat->dwMask |= CFM_BACKCOLOR;
+ charformat->crBackColor = RGB(r, g, b);
+ }
+ }
+
+ format = iupAttribGet(formattag, "UNDERLINE");
+ if (format)
+ {
+ charformat->dwMask |= CFM_UNDERLINETYPE;
+
+ if (iupStrEqualNoCase(format, "SINGLE"))
+ charformat->bUnderlineType = CFU_UNDERLINE;
+ else if (iupStrEqualNoCase(format, "DOUBLE"))
+ charformat->bUnderlineType = CFU_UNDERLINEDOUBLE;
+ else if (iupStrEqualNoCase(format, "DOTTED"))
+ charformat->bUnderlineType = CFU_UNDERLINEDOTTED;
+ else /* "NONE" */
+ charformat->bUnderlineType = CFU_UNDERLINENONE;
+
+ if (charformat->bUnderlineType != CFU_UNDERLINENONE)
+ {
+ charformat->dwMask |= CFM_UNDERLINE;
+ charformat->dwEffects |= CFE_UNDERLINE;
+ }
+ }
+
+ format = iupAttribGet(formattag, "WEIGHT");
+ if (format)
+ {
+ charformat->dwMask |= CFM_WEIGHT;
+
+ if (iupStrEqualNoCase(format, "EXTRALIGHT"))
+ charformat->wWeight = FW_EXTRALIGHT;
+ else if (iupStrEqualNoCase(format, "LIGHT"))
+ charformat->wWeight = FW_LIGHT;
+ else if (iupStrEqualNoCase(format, "SEMIBOLD"))
+ charformat->wWeight = FW_SEMIBOLD;
+ else if (iupStrEqualNoCase(format, "BOLD"))
+ charformat->wWeight = FW_BOLD;
+ else if (iupStrEqualNoCase(format, "EXTRABOLD"))
+ charformat->wWeight = FW_EXTRABOLD;
+ else if (iupStrEqualNoCase(format, "HEAVY"))
+ charformat->wWeight = FW_HEAVY;
+ else /* "NORMAL" */
+ charformat->wWeight = FW_NORMAL;
+
+ if (charformat->wWeight != FW_NORMAL)
+ {
+ charformat->dwMask |= CFM_BOLD;
+ charformat->dwEffects |= CFE_BOLD;
+ }
+ }
+}
+
+static int winTextSetLinColToPosition(Ihandle *ih, int lin, int col)
+{
+ int linmax, colmax, lineindex;
+
+ lin--; /* IUP starts at 1 */
+ col--;
+
+ linmax = SendMessage(ih->handle, EM_GETLINECOUNT, 0, 0L);
+ if (lin > linmax)
+ lin = linmax;
+
+ lineindex = SendMessage(ih->handle, EM_LINEINDEX, (WPARAM)lin, 0L);
+
+ colmax = SendMessage(ih->handle, EM_LINELENGTH, (WPARAM)lineindex, 0L);
+ if (col > colmax)
+ col = colmax; /* after the last character */
+
+ return lineindex + col;
+}
+
+static void winTextGetLinColFromPosition(Ihandle* ih, int pos, int* lin, int* col)
+{
+ /* here "pos" must contains the extra chars if the case */
+ int lineindex;
+
+ if (ih->data->has_formatting)
+ *lin = SendMessage(ih->handle, EM_EXLINEFROMCHAR, (WPARAM)0, (LPARAM)pos);
+ else
+ *lin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L);
+
+ lineindex = SendMessage(ih->handle, EM_LINEINDEX, (WPARAM)(*lin), (LPARAM)0L);
+ *col = pos - lineindex; /* lineindex is at the first character of the line */
+
+ (*lin)++; /* IUP starts at 1 */
+ (*col)++;
+}
+
+static int winTextRemoveExtraChars(Ihandle* ih, int pos)
+{
+ /* called only if not single line and not formatting */
+ int lin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L);
+ pos -= lin; /* remove \r characters from count */
+ return pos;
+}
+
+static int winTextAddExtraChars(Ihandle* ih, int pos)
+{
+ /* called only if not single line and not formatting */
+ int lin, clin;
+
+ clin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L);
+
+ /* pos is smaller than the actual pos (missing the \r count),
+ so we must calculate the line until the returned value is the same as the expected. */
+ do
+ {
+ lin = clin;
+ clin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)(pos+lin+1), (LPARAM)0L); /* add one because we can be at the last character */
+ } while (clin != lin); /* and it will not change to the next line by 1 */
+
+ pos += lin; /* add \r characters from count */
+ return pos;
+}
+
+static int winTextGetCaretPos(Ihandle* ih)
+{
+ int pos = 0;
+ POINT point;
+
+ if (GetFocus() != ih->handle || !GetCaretPos(&point))
+ {
+ /* if does not have the focus, or could not get caret position,
+ then use the selection start position */
+ SendMessage(ih->handle, EM_GETSEL, (WPARAM)&pos, 0);
+ }
+ else
+ {
+ if (ih->data->has_formatting)
+ pos = SendMessage(ih->handle, EM_CHARFROMPOS, 0, (LPARAM)&point);
+ else
+ {
+ LRESULT ret;
+
+ /* Workaround for weird behavior because of the return value in GetCaretPos */
+ if (ih->data->is_multiline && point.y < 5)
+ point.y += 5;
+
+ ret = SendMessage(ih->handle, EM_CHARFROMPOS, 0, MAKELPARAM(point.x, point.y));
+ pos = LOWORD(ret);
+ }
+ }
+
+ return pos;
+}
+
+static int winTextGetCaret(Ihandle* ih, int *lin, int *col)
+{
+ int pos = winTextGetCaretPos(ih);
+
+ if (ih->data->is_multiline)
+ {
+ winTextGetLinColFromPosition(ih, pos, lin, col);
+
+ if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ pos = winTextRemoveExtraChars(ih, pos);
+ }
+ else
+ {
+ *col = pos;
+ (*col)++; /* IUP starts at 1 */
+ *lin = 1;
+ }
+
+ return pos;
+}
+
+static void winTextGetSelection(Ihandle* ih, int *start, int *end)
+{
+ *start = 0;
+ *end = 0;
+
+ SendMessage(ih->handle, EM_GETSEL, (WPARAM)start, (LPARAM)end);
+
+ if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ {
+ (*start) = winTextRemoveExtraChars(ih, *start);
+ (*end) = winTextRemoveExtraChars(ih, *end);
+ }
+}
+
+void iupdrvTextConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos)
+{
+ *pos = winTextSetLinColToPosition(ih, lin, col);
+
+ if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ *pos = winTextRemoveExtraChars(ih, *pos);
+}
+
+void iupdrvTextConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col)
+{
+ if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ pos = winTextAddExtraChars(ih, pos);
+
+ winTextGetLinColFromPosition(ih, pos, lin, col);
+}
+
+static int winTextConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ int pos;
+
+ if (ih->data->has_formatting)
+ {
+ POINT point;
+ point.x = x;
+ point.y = y;
+ pos = (int)SendMessage(ih->handle, EM_CHARFROMPOS, 0, (LPARAM)&point);
+ }
+ else
+ {
+ LRESULT ret = SendMessage(ih->handle, EM_CHARFROMPOS, 0, MAKELPARAM(x, y));
+ pos = LOWORD(ret);
+ }
+
+ if (ih->data->is_multiline)
+ {
+ if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ pos = winTextRemoveExtraChars(ih, pos);
+ }
+
+ return pos;
+}
+
+
+/***********************************************************************************************/
+
+
+static int winTextSetValueAttrib(Ihandle* ih, const char* value)
+{
+ char* str;
+ if (!value) value = "";
+ str = (char*)value;
+ if (ih->data->is_multiline)
+ {
+ if (ih->data->has_formatting)
+ str = iupStrToMac(str);
+ else
+ str = iupStrToDos(str);
+ }
+ iupAttribSetStr(ih, "IUPWIN_IGNORECHANGE", "1");
+ SetWindowText(ih->handle, str);
+ iupAttribSetStr(ih, "IUPWIN_IGNORECHANGE", NULL);
+ if (str != value) free(str);
+ return 0;
+}
+
+static char* winTextGetValueAttrib(Ihandle* ih)
+{
+ int nc = GetWindowTextLength(ih->handle);
+ if (nc)
+ {
+ char* str = iupStrGetMemory(nc+1);
+ GetWindowText(ih->handle, str, nc+1); /* notice that this function always returns in DOS format */
+ if (ih->data->is_multiline)
+ iupStrToUnix(str);
+ return str;
+ }
+ else
+ return "";
+}
+
+static int winTextSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &(ih->data->horiz_padding), &(ih->data->vert_padding), 'x');
+ ih->data->vert_padding = 0;
+ if (ih->handle)
+ SendMessage(ih->handle, EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN, MAKELPARAM(ih->data->horiz_padding, ih->data->horiz_padding));
+ return 0;
+}
+
+static int winTextSetSelectedTextAttrib(Ihandle* ih, const char* value)
+{
+ if (value)
+ {
+ int start = 0, end = 0;
+ char* str;
+
+ SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return 0;
+
+ str = (char*)value;
+ if (ih->data->is_multiline)
+ {
+ if (ih->data->has_formatting)
+ str = iupStrToMac(str);
+ else
+ str = iupStrToDos(str);
+ }
+ SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)str);
+ if (str != value) free(str);
+ }
+ return 0;
+}
+
+static char* winTextGetSelectedTextAttrib(Ihandle* ih)
+{
+ int nc = GetWindowTextLength(ih->handle);
+ if (nc)
+ {
+ int start = 0, end = 0;
+ char* str;
+
+ SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return NULL;
+
+ if (ih->data->has_formatting)
+ {
+ str = iupStrGetMemory(end-start+1);
+ SendMessage(ih->handle, EM_GETSELTEXT, 0, (LPARAM)str);
+ }
+ else
+ {
+ str = iupStrGetMemory(nc+1);
+ GetWindowText(ih->handle, str, nc+1); /* notice that this function always returns in DOS format */
+ /* returns only the selected text */
+ str[end] = 0;
+ str += start;
+ }
+
+ if (ih->data->is_multiline)
+ iupStrToUnix(str);
+ return str;
+ }
+ else
+ return NULL;
+}
+
+static int winTextSetNCAttrib(Ihandle* ih, const char* value)
+{
+ if (!iupStrToInt(value, &ih->data->nc))
+ ih->data->nc = 0;
+
+ if (ih->handle)
+ {
+ if (ih->data->has_formatting)
+ SendMessage(ih->handle, EM_EXLIMITTEXT, 0, ih->data->nc); /* so it can be larger than 64k */
+ else
+ SendMessage(ih->handle, EM_LIMITTEXT, ih->data->nc, 0L);
+ }
+ return 0;
+}
+
+static int winTextSetSelectionAttrib(Ihandle* ih, const char* value)
+{
+ int start=1, end=1;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)-1, (LPARAM)0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
+ return 0;
+ }
+
+ if (ih->data->is_multiline)
+ {
+ int lin_start=1, col_start=1, lin_end=1, col_end=1;
+
+ if (sscanf(value, "%d,%d:%d,%d", &lin_start, &col_start, &lin_end, &col_end)!=4) return 0;
+ if (lin_start<1 || col_start<1 || lin_end<1 || col_end<1) return 0;
+
+ start = winTextSetLinColToPosition(ih, lin_start, col_start);
+ end = winTextSetLinColToPosition(ih, lin_end, col_end);
+ }
+ else
+ {
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<1 || end<1)
+ return 0;
+
+ start--; /* IUP starts at 1 */
+ end--;
+ }
+
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)start, (LPARAM)end);
+
+ return 0;
+}
+
+static char* winTextGetSelectionAttrib(Ihandle* ih)
+{
+ int start = 0, end = 0;
+ char* str;
+
+ SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return NULL;
+
+ str = iupStrGetMemory(100);
+
+ if (ih->data->is_multiline)
+ {
+ int start_col, start_lin, end_col, end_lin;
+ winTextGetLinColFromPosition(ih, start, &start_lin, &start_col);
+ winTextGetLinColFromPosition(ih, end, &end_lin, &end_col);
+ sprintf(str,"%d,%d:%d,%d", start_lin, start_col, end_lin, end_col);
+ }
+ else
+ {
+ start++; /* IUP starts at 1 */
+ end++;
+ sprintf(str, "%d:%d", start, end);
+ }
+
+ return str;
+}
+
+static int winTextSetSelectionPosAttrib(Ihandle* ih, const char* value)
+{
+ int start=0, end=0;
+
+ if (!value || iupStrEqualNoCase(value, "NONE"))
+ {
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)-1, (LPARAM)0);
+ return 0;
+ }
+
+ if (iupStrEqualNoCase(value, "ALL"))
+ {
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
+ return 0;
+ }
+
+ if (iupStrToIntInt(value, &start, &end, ':')!=2)
+ return 0;
+
+ if(start<0 || end<0)
+ return 0;
+
+ if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ {
+ start = winTextAddExtraChars(ih, start);
+ end = winTextAddExtraChars(ih, end);
+ }
+
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)start, (LPARAM)end);
+
+ return 0;
+}
+
+static char* winTextGetSelectionPosAttrib(Ihandle* ih)
+{
+ int start = 0, end = 0;
+ char* str;
+
+ SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
+ if (start == end)
+ return NULL;
+
+ if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ {
+ start = winTextRemoveExtraChars(ih, start);
+ end = winTextRemoveExtraChars(ih, end);
+ }
+
+ str = iupStrGetMemory(100);
+
+ sprintf(str, "%d:%d", start, end);
+
+ return str;
+}
+
+static int winTextSetInsertAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ if (value)
+ {
+ char* str = (char*)value;
+ if (ih->data->is_multiline)
+ {
+ if (ih->data->has_formatting)
+ str = iupStrToMac(str);
+ else
+ str = iupStrToDos(str);
+ }
+
+ SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)str);
+
+ if (str != value) free(str);
+ }
+ return 0;
+}
+
+static int winTextSetAppendAttrib(Ihandle* ih, const char* value)
+{
+ int len;
+ char* str;
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ if (!value) value = "";
+ str = (char*)value;
+ if (ih->data->is_multiline)
+ {
+ if (ih->data->has_formatting)
+ str = iupStrToMac(str);
+ else
+ str = iupStrToDos(str);
+ }
+
+ len = GetWindowTextLength(ih->handle)+1;
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)len, (LPARAM)len);
+ if (ih->data->is_multiline && ih->data->append_newline)
+ {
+ if (ih->data->has_formatting)
+ SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)"\r");
+ else
+ SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)"\r\n");
+ }
+ SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)str);
+
+ if (str != value) free(str);
+ return 0;
+}
+
+static int winTextSetReadOnlyAttrib(Ihandle* ih, const char* value)
+{
+ SendMessage(ih->handle, EM_SETREADONLY, (WPARAM)iupStrBoolean(value), 0);
+ return 0;
+}
+
+static char* winTextGetReadOnlyAttrib(Ihandle* ih)
+{
+ DWORD style = GetWindowLong(ih->handle, GWL_STYLE);
+ if (style & ES_READONLY)
+ return "YES";
+ else
+ return "NO";
+}
+
+static int winTextSetTabSizeAttrib(Ihandle* ih, const char* value)
+{
+ int tabsize;
+ if (!ih->data->is_multiline)
+ return 0;
+
+ iupStrToInt(value, &tabsize);
+ tabsize *= 4;
+ SendMessage(ih->handle, EM_SETTABSTOPS, (WPARAM)1L, (LPARAM)&tabsize);
+ iupdrvDisplayRedraw(ih);
+ return 1;
+}
+
+static int winTextSetCaretAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 1;
+
+ if (!value)
+ return 0;
+
+ if (ih->data->is_multiline)
+ {
+ int lin = 1, col = 1;
+ iupStrToIntInt(value, &lin, &col, ','); /* be permissive in SetCaret, do not abort if invalid */
+ if (lin < 1) lin = 1;
+ if (col < 1) col = 1;
+
+ pos = winTextSetLinColToPosition(ih, lin, col);
+ }
+ else
+ {
+ sscanf(value,"%i",&pos);
+ if (pos < 1) pos = 1;
+ pos--; /* IUP starts at 1 */
+ }
+
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)pos, (LPARAM)pos);
+ SendMessage(ih->handle, EM_SCROLLCARET, 0L, 0L);
+
+ return 0;
+}
+
+static char* winTextGetCaretAttrib(Ihandle* ih)
+{
+ int col, lin;
+ char* str;
+
+ str = iupStrGetMemory(100);
+
+ winTextGetCaret(ih, &lin, &col);
+
+ if (ih->data->is_multiline)
+ sprintf(str, "%d,%d", lin, col);
+ else
+ sprintf(str, "%d", col);
+
+ return str;
+}
+
+static int winTextSetCaretPosAttrib(Ihandle* ih, const char* value)
+{
+ int pos = 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos); /* be permissive in SetCaret, do not abort if invalid */
+ if (pos < 0) pos = 0;
+
+ if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ pos = winTextAddExtraChars(ih, pos);
+
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)pos, (LPARAM)pos);
+ SendMessage(ih->handle, EM_SCROLLCARET, 0L, 0L);
+
+ return 0;
+}
+
+static char* winTextGetCaretPosAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(100);
+ int pos = winTextGetCaretPos(ih);
+ if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ pos = winTextRemoveExtraChars(ih, pos);
+ sprintf(str, "%d", pos);
+ return str;
+}
+
+static int winTextSetScrollToAttrib(Ihandle* ih, const char* value)
+{
+ int lin = 1, col = 1;
+
+ if (!value)
+ return 0;
+
+ if (ih->data->is_multiline)
+ {
+ iupStrToIntInt(value, &lin, &col, ',');
+ if (lin < 1) lin = 1;
+ if (col < 1) col = 1;
+ }
+ else
+ {
+ sscanf(value,"%i",&col);
+ if (col < 1) col = 1;
+ }
+
+ lin--; /* return to Windows referece */
+ col--;
+
+ if (ih->data->has_formatting)
+ SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)0, (LPARAM)lin);
+ else
+ SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)col, (LPARAM)lin);
+
+ return 0;
+}
+
+static int winTextSetScrollToPosAttrib(Ihandle* ih, const char* value)
+{
+ int lin, col, pos = 0;
+
+ if (!value)
+ return 0;
+
+ sscanf(value,"%i",&pos);
+ if (pos < 0) pos = 0;
+
+ if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */
+ pos = winTextAddExtraChars(ih, pos);
+
+ winTextGetLinColFromPosition(ih, pos, &lin, &col);
+ lin--; /* return to Windows referece */
+ col--;
+
+ if (ih->data->has_formatting)
+ SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)0, (LPARAM)lin);
+ else
+ SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)col, (LPARAM)lin);
+
+ return 0;
+}
+
+static int winTextSetFilterAttrib(Ihandle *ih, const char *value)
+{
+ int style = 0;
+
+ if (iupStrEqualNoCase(value, "LOWERCASE"))
+ {
+ if (ih->data->has_formatting)
+ {
+ SendMessage(ih->handle, EM_SETEDITSTYLE, SES_LOWERCASE, SES_LOWERCASE);
+ return 1;
+ }
+ style = ES_LOWERCASE;
+ }
+ else if (iupStrEqualNoCase(value, "NUMBER"))
+ style = ES_NUMBER;
+ else if (iupStrEqualNoCase(value, "UPPERCASE"))
+ {
+ if (ih->data->has_formatting)
+ {
+ SendMessage(ih->handle, EM_SETEDITSTYLE, SES_UPPERCASE, SES_UPPERCASE);
+ return 1;
+ }
+ style = ES_UPPERCASE;
+ }
+
+ if (style)
+ iupwinMergeStyle(ih, ES_LOWERCASE|ES_NUMBER|ES_UPPERCASE, style);
+
+ return 1;
+}
+
+static int winTextSetClipboardAttrib(Ihandle *ih, const char *value)
+{
+ UINT msg = 0;
+
+ if (iupStrEqualNoCase(value, "COPY"))
+ msg = WM_COPY;
+ else if (iupStrEqualNoCase(value, "CUT"))
+ msg = WM_CUT;
+ else if (iupStrEqualNoCase(value, "PASTE"))
+ msg = WM_PASTE;
+ else if (iupStrEqualNoCase(value, "CLEAR"))
+ msg = WM_CLEAR;
+ else if (iupStrEqualNoCase(value, "UNDO"))
+ msg = WM_UNDO;
+ else if (ih->data->has_formatting && iupStrEqualNoCase(value, "REDO"))
+ msg = EM_REDO;
+
+ if (msg)
+ SendMessage(ih->handle, msg, 0, 0);
+
+ return 0;
+}
+
+static int winTextSetBgColorAttrib(Ihandle *ih, const char *value)
+{
+ if (ih->data->has_formatting)
+ {
+ unsigned char r, g, b;
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ COLORREF color;
+ color = RGB(r,g,b);
+ SendMessage(ih->handle, EM_SETBKGNDCOLOR, 0, (LPARAM)color);
+ }
+ }
+ return 1;
+}
+
+static int winTextSetCueBannerAttrib(Ihandle *ih, const char *value)
+{
+ if (!ih->data->is_multiline && iupwin_comctl32ver6)
+ {
+ WCHAR* wstr = iupwinStrChar2Wide(value);
+ SendMessage(ih->handle, EM_SETCUEBANNER, (WPARAM)FALSE, (LPARAM)wstr);
+ free(wstr);
+ return 1;
+ }
+ return 0;
+}
+
+static int winTextSetAlignmentAttrib(Ihandle* ih, const char* value)
+{
+ int new_style;
+
+ if (iupStrEqualNoCase(value, "ARIGHT"))
+ new_style = ES_RIGHT;
+ else if (iupStrEqualNoCase(value, "ACENTER"))
+ new_style = ES_CENTER;
+ else /* "ALEFT" */
+ new_style = ES_LEFT;
+
+ iupwinMergeStyle(ih, ES_LEFT|ES_CENTER|ES_RIGHT, new_style);
+
+ return 1;
+}
+
+static int winTextSetStandardFontAttrib(Ihandle* ih, const char* value)
+{
+ /* ignore the first call that is done in IupMap,
+ it is already done before calling iupTextUpdateFormatTags. */
+ if (ih->data->has_formatting && iupAttribGet(ih, "_IUPWIN_IGNORE_FONT"))
+ {
+ iupAttribSetStr(ih, "_IUPWIN_IGNORE_FONT", NULL);
+ return 0;
+ }
+ return iupdrvSetStandardFontAttrib(ih, value);
+}
+
+void iupdrvTextAddFormatTag(Ihandle* ih, Ihandle* formattag)
+{
+ int convert2twips, pixel2twips;
+ char *selection, *units;
+ PARAFORMAT2 paraformat;
+ CHARFORMAT2 charformat;
+
+ /* one twip is 1/1440 inch */
+ /* twip = (pixel*1440)/(pixel/inch) */
+ pixel2twips = 1440/iupwinGetScreenRes();
+
+ /* default is PIXELS */
+ convert2twips = pixel2twips;
+ units = iupAttribGet(formattag, "UNITS");
+ if (units)
+ {
+ int val;
+ if (iupStrEqualNoCase(units, "TWIPS"))
+ convert2twips = 1;
+ else if (iupStrToInt(units, &val))
+ convert2twips = val;
+ }
+
+ selection = iupAttribGet(formattag, "SELECTION");
+ if (selection)
+ {
+ /* In Windows, the format message use the current selection */
+ winTextSetSelectionAttrib(ih, selection);
+ iupAttribSetStr(ih, "SELECTION", NULL);
+ }
+ else
+ {
+ char* selectionpos = iupAttribGet(formattag, "SELECTIONPOS");
+ if (selectionpos)
+ {
+ /* In Windows, the format message use the current selection */
+ winTextSetSelectionPosAttrib(ih, selectionpos);
+ iupAttribSetStr(ih, "SELECTIONPOS", NULL);
+ }
+ }
+
+ if (iupAttribGet(formattag, "FONTSCALE") && !iupAttribGet(formattag, "FONTSIZE"))
+ iupAttribSetStr(formattag, "FONTSIZE", iupGetFontSizeAttrib(ih));
+
+ winTextParseParagraphFormat(formattag, &paraformat, convert2twips);
+ if (paraformat.dwMask != 0)
+ SendMessage(ih->handle, EM_SETPARAFORMAT, 0, (LPARAM)&paraformat);
+
+ winTextParseCharacterFormat(formattag, &charformat, pixel2twips);
+ if (charformat.dwMask != 0)
+ SendMessage(ih->handle, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charformat);
+
+ /* reset the selection, if changed here */
+ if (selection)
+ winTextSetSelectionAttrib(ih, NULL);
+}
+
+static int winTextSetRemoveFormattingAttrib(Ihandle* ih, const char* value)
+{
+ PARAFORMAT2 paraformat;
+ CHARFORMAT2 charformat;
+ COLORREF colorref;
+ int val;
+
+ if (!ih->data->has_formatting)
+ return 0;
+
+ ZeroMemory(&paraformat, sizeof(PARAFORMAT2));
+ paraformat.cbSize = sizeof(PARAFORMAT2);
+ paraformat.dwMask = PFM_NUMBERING|PFM_STARTINDENT|PFM_RIGHTINDENT|PFM_OFFSET|
+ PFM_ALIGNMENT|PFM_SPACEBEFORE|PFM_SPACEAFTER|PFM_LINESPACING;
+ paraformat.wAlignment = PFA_LEFT;
+
+ ZeroMemory(&charformat, sizeof(CHARFORMAT2));
+ charformat.cbSize = sizeof(CHARFORMAT2);
+ charformat.dwMask = CFM_DISABLED|CFM_OFFSET|CFM_ITALIC|CFM_STRIKEOUT|CFM_PROTECTED|
+ CFM_UNDERLINETYPE|CFM_UNDERLINE|CFM_WEIGHT|CFM_FACE;
+ charformat.wWeight = FW_NORMAL;
+ strcpy(charformat.szFaceName, iupGetFontFaceAttrib(ih));
+
+ if (iupwinGetColorRef(ih, "FGCOLOR", &colorref))
+ {
+ charformat.dwMask |= CFM_COLOR;
+ charformat.crTextColor = colorref;
+ }
+
+ if (iupwinGetColorRef(ih, "BGCOLOR", &colorref))
+ {
+ charformat.dwMask |= CFM_BACKCOLOR;
+ charformat.crBackColor = colorref;
+ }
+
+ if (iupStrToInt(iupGetFontSizeAttrib(ih), &val))
+ {
+ /* (1/1440 of an inch, or 1/20 of a printer's point) */
+ charformat.dwMask |= CFM_SIZE;
+ if (val < 0) /* in pixels */
+ {
+ int pixel2twips = 1440/iupwinGetScreenRes();
+ charformat.yHeight = (-val)*pixel2twips;
+ }
+ else
+ charformat.yHeight = val*20;
+ }
+
+ SendMessage(ih->handle, EM_SETPARAFORMAT, 0, (LPARAM)&paraformat);
+ SendMessage(ih->handle, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charformat);
+
+ (void)value;
+ return 0;
+}
+
+static int winTextSetOverwriteAttrib(Ihandle* ih, const char* value)
+{
+ if (!ih->data->has_formatting)
+ return 0;
+
+ if (iupAttribGetBoolean(ih, "OVERWRITE"))
+ {
+ if (!iupStrBoolean(value))
+ SendMessage(ih->handle, WM_KEYDOWN, VK_INSERT, 0); /* toggle from ON to OFF */
+ }
+ else
+ {
+ if (iupStrBoolean(value))
+ SendMessage(ih->handle, WM_KEYDOWN, VK_INSERT, 0); /* toggle from OFF to ON */
+ }
+ return 1;
+}
+
+
+static int winTextSetVisibleAttrib(Ihandle* ih, const char* value)
+{
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ if (hSpin)
+ ShowWindow(hSpin, iupStrBoolean(value)? SW_SHOWNORMAL: SW_HIDE);
+
+ return iupBaseSetVisibleAttrib(ih, value);
+}
+
+static void winTextCropSpinValue(HWND hSpin, int min, int max)
+{
+ /* refresh if internally cropped, but text still shows an invalid value */
+ int pos = SendMessage(hSpin, UDM_GETPOS32, 0, 0);
+ if (pos <= min)
+ SendMessage(hSpin, UDM_SETPOS32, 0, min);
+ if (pos >= max)
+ SendMessage(hSpin, UDM_SETPOS32, 0, max);
+}
+
+static int winTextSetSpinMinAttrib(Ihandle* ih, const char* value)
+{
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ if (hSpin)
+ {
+ int min;
+ if (iupStrToInt(value, &min))
+ {
+ int max = iupAttribGetInt(ih, "SPINMAX");
+ SendMessage(hSpin, UDM_SETRANGE32, min, max);
+
+ winTextCropSpinValue(hSpin, min, max);
+ }
+ }
+ return 1;
+}
+
+static int winTextSetSpinMaxAttrib(Ihandle* ih, const char* value)
+{
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ if (hSpin)
+ {
+ int max;
+ if (iupStrToInt(value, &max))
+ {
+ int min = iupAttribGetInt(ih, "SPINMIN");
+ SendMessage(hSpin, UDM_SETRANGE32, min, max);
+
+ winTextCropSpinValue(hSpin, min, max);
+ }
+ }
+ return 1;
+}
+
+static int winTextSetSpinIncAttrib(Ihandle* ih, const char* value)
+{
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ if (hSpin)
+ {
+ int inc;
+ if (iupStrToInt(value, &inc))
+ {
+ UDACCEL paAccels[3];
+ paAccels[0].nInc = inc;
+ paAccels[0].nSec = 0;
+ paAccels[1].nInc = inc*5;
+ paAccels[1].nSec = 2;
+ paAccels[2].nInc = inc*20;
+ paAccels[2].nSec = 5;
+ SendMessage(hSpin, UDM_SETACCEL, 3, (LPARAM)paAccels);
+ }
+ }
+ return 1;
+}
+
+static int winTextSetSpinValueAttrib(Ihandle* ih, const char* value)
+{
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ if (hSpin)
+ {
+ int pos;
+ if (iupStrToInt(value, &pos))
+ SendMessage(hSpin, UDM_SETPOS32, 0, pos);
+ }
+ return 1;
+}
+
+static char* winTextGetSpinValueAttrib(Ihandle* ih)
+{
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ if (hSpin)
+ {
+ int pos = SendMessage(hSpin, UDM_GETPOS32, 0, 0);
+ char *str = iupStrGetMemory(50);
+ sprintf(str, "%d", pos);
+ return str;
+ }
+ return NULL;
+}
+
+
+/****************************************************************************************/
+
+
+static int winTextCtlColor(Ihandle* ih, HDC hdc, LRESULT *result)
+{
+ COLORREF cr;
+
+ if (iupwinGetColorRef(ih, "FGCOLOR", &cr))
+ SetTextColor(hdc, cr);
+
+ if (iupwinGetColorRef(ih, "BGCOLOR", &cr))
+ {
+ SetBkColor(hdc, cr);
+ SetDCBrushColor(hdc, cr);
+ *result = (LRESULT)GetStockObject(DC_BRUSH);
+ return 1;
+ }
+ return 0;
+}
+
+static void winTextCallCaretCb(Ihandle* ih)
+{
+ int col, lin, pos;
+
+ IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB");
+ if (!cb) return;
+
+ pos = winTextGetCaret(ih, &lin, &col);
+
+ if (pos != ih->data->last_caret_pos)
+ {
+ ih->data->last_caret_pos = pos;
+
+ cb(ih, lin, col, pos);
+ }
+}
+
+static int winTextCallActionCb(Ihandle* ih, const char* insert_value, int key, int dir)
+{
+ int start, end, ret = 1;
+ char *value, *new_value;
+
+ IFnis cb = (IFnis)IupGetCallback(ih, "ACTION");
+ if (!cb && !ih->data->mask)
+ return 1;
+
+ winTextGetSelection(ih, &start, &end);
+
+ value = winTextGetValueAttrib(ih);
+
+ if (value[0]==0)
+ new_value = iupStrDup(insert_value);
+ else if (insert_value)
+ new_value = iupStrInsert(value, insert_value, start, end);
+ else
+ {
+ new_value = value;
+ iupStrRemove(value, start, end, dir);
+ }
+
+ if (!new_value)
+ return 0; /* abort */
+
+ if (ih->data->nc && (int)strlen(new_value) > ih->data->nc)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0)
+ {
+ if (new_value != value) free(new_value);
+ return 0; /* abort */
+ }
+
+ if (cb)
+ {
+ int cb_ret = cb(ih, key, (char*)new_value);
+ if (cb_ret==IUP_IGNORE)
+ ret = 0; /* abort processing */
+ else if (cb_ret==IUP_CLOSE)
+ {
+ IupExitLoop();
+ ret = 0; /* abort processing */
+ }
+ else if (cb_ret!=0 && key!=0 &&
+ cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE)
+ {
+ WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB");
+ CallWindowProc(oldProc, ih->handle, WM_CHAR, cb_ret, 0); /* replace key */
+ ret = 0; /* abort processing */
+ }
+ }
+
+ if (new_value != value) free(new_value);
+ return ret;
+}
+
+static int winTextSpinWmNotify(Ihandle* ih, NMHDR* msg_info, int *result)
+{
+ if (msg_info->code == UDN_DELTAPOS)
+ {
+ NMUPDOWN *updown = (NMUPDOWN*)msg_info;
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ int pos = updown->iPos+updown->iDelta;
+ int min, max;
+ SendMessage(hSpin, UDM_GETRANGE32, (WPARAM)&min, (LPARAM)&max);
+ if (pos>=min && pos<=max)
+ {
+ IFni cb = (IFni) IupGetCallback(ih, "SPIN_CB");
+ if (cb)
+ {
+ int ret = cb(ih, pos);
+ if (ret == IUP_IGNORE)
+ {
+ *result = 1;
+ return 1;
+ }
+ }
+ }
+ }
+
+ (void)result;
+ return 0; /* result not used */
+}
+
+static int winTextProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ int ret = 0;
+
+ if (msg==WM_KEYDOWN) /* process K_ANY before text callbacks */
+ {
+ ret = iupwinBaseProc(ih, msg, wp, lp, result);
+ if (ret)
+ {
+ *result = 0;
+ return 1;
+ }
+ }
+
+ switch (msg)
+ {
+ case WM_CHAR:
+ {
+ if ((char)wp == '\b')
+ {
+ if (!winTextCallActionCb(ih, NULL, 0, -1))
+ ret = 1;
+ }
+ else if ((char)wp == '\n' || (char)wp == '\r')
+ {
+ if (!ih->data->has_formatting && !(GetKeyState(VK_CONTROL) & 0x8000)) /* when formatting is processed in WM_KEYDOWN */
+ {
+ char insert_value[2];
+ insert_value[0] = '\n';
+ insert_value[1] = 0;
+
+ if (!winTextCallActionCb(ih, insert_value, wp, 1))
+ ret = 1;
+ }
+ }
+ else if (!(GetKeyState(VK_CONTROL) & 0x8000 ||
+ GetKeyState(VK_MENU) & 0x8000 ||
+ GetKeyState(VK_LWIN) & 0x8000 ||
+ GetKeyState(VK_RWIN) & 0x8000))
+ {
+ char insert_value[2];
+ insert_value[0] = (char)wp;
+ insert_value[1] = 0;
+
+ if (!winTextCallActionCb(ih, insert_value, wp, 1))
+ ret = 1;
+ }
+
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+
+ if (!ih->data->is_multiline &&
+ (wp==VK_RETURN || wp==VK_ESCAPE || wp==VK_TAB)) /* the keys have the same definitions as the chars */
+ ret = 1; /* abort default processing to avoid beep */
+
+ if (ih->data->is_multiline &&
+ (wp=='\n' && (GetKeyState(VK_CONTROL) & 0x8000)))
+ ret = 1; /* abort default processing to avoid inserting a new line */
+
+ break;
+ }
+ case WM_KEYDOWN:
+ {
+ if (wp == VK_DELETE) /* Del does not generates a WM_CHAR */
+ {
+ if (!winTextCallActionCb(ih, NULL, 0, 1))
+ ret = 1;
+ }
+ else if (wp == VK_INSERT && ih->data->has_formatting)
+ {
+ if (iupAttribGetBoolean(ih, "OVERWRITE"))
+ iupAttribSetStr(ih, "OVERWRITE", "OFF"); /* toggle from ON to OFF */
+ else
+ iupAttribSetStr(ih, "OVERWRITE", "ON"); /* toggle from OFF to ON */
+ }
+ else if (wp == 'A' && GetKeyState(VK_CONTROL) & 0x8000) /* Ctrl+A = Select All */
+ {
+ SendMessage(ih->handle, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
+ }
+ else if (wp == VK_RETURN && ih->data->has_formatting && !(GetKeyState(VK_CONTROL) & 0x8000))
+ {
+ char insert_value[2];
+ insert_value[0] = '\n';
+ insert_value[1] = 0;
+
+ if (!winTextCallActionCb(ih, insert_value, '\n', 1))
+ ret = 1;
+ }
+
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+
+ if (ret) /* if abort processing, then the result is 0 */
+ {
+ *result = 0;
+ return 1;
+ }
+ else
+ return 0; /* already processed at the begining of this function */
+ }
+ case WM_KEYUP:
+ {
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_CLEAR:
+ {
+ if (!winTextCallActionCb(ih, NULL, 0, 1))
+ ret = 1;
+
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_CUT:
+ {
+ if (!winTextCallActionCb(ih, NULL, 0, 1))
+ ret = 1;
+
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_PASTE:
+ {
+ if (IupGetCallback(ih,"ACTION") || ih->data->mask) /* test before to avoid alocate clipboard text memory */
+ {
+ char* insert_value = iupwinGetClipboardText(ih);
+ if (insert_value)
+ {
+ if (!winTextCallActionCb(ih, insert_value, 0, 1))
+ ret = 1;
+ free(insert_value);
+ }
+ }
+
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_UNDO:
+ {
+ IFnis cb = (IFnis)IupGetCallback(ih, "ACTION");
+ if (cb)
+ {
+ char* value;
+ WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB");
+ CallWindowProc(oldProc, ih->handle, WM_UNDO, 0, 0);
+
+ value = winTextGetValueAttrib(ih);
+ cb(ih, 0, (char*)value);
+
+ ret = 1;
+ }
+
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ {
+ if (iupwinButtonDown(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_LBUTTONUP:
+ {
+ if (iupwinButtonUp(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+ PostMessage(ih->handle, WM_CARET, 0, 0L);
+ break;
+ }
+ case WM_CARET:
+ {
+ winTextCallCaretCb(ih);
+ break;
+ }
+ case WM_MOUSEMOVE:
+ {
+ iupwinMouseMove(ih, msg, wp, lp);
+ break;
+ }
+ case WM_VSCROLL:
+ case WM_HSCROLL:
+ {
+ if (ih->data->has_formatting)
+ {
+ /* fix weird behavior when dialog has COMPOSITE=YES,
+ scrollbars are not updated when dragging */
+ if (LOWORD(wp) == SB_THUMBTRACK)
+ SendMessage(ih->handle, EM_SHOWSCROLLBAR, msg==WM_VSCROLL? SB_VERT: SB_HORZ, TRUE);
+ }
+ break;
+ }
+ }
+
+ if (ret) /* if abort processing, then the result is 0 */
+ {
+ *result = 0;
+ return 1;
+ }
+ else
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+static void winTextCreateSpin(Ihandle* ih)
+{
+ HWND hSpin;
+ DWORD dwStyle = WS_CHILD|UDS_ARROWKEYS|UDS_HOTTRACK|UDS_NOTHOUSANDS;
+ int serial = iupDialogGetChildId(ih);
+
+ if (iupStrEqualNoCase(iupAttribGetStr(ih, "SPINALIGN"), "LEFT"))
+ dwStyle |= UDS_ALIGNLEFT;
+ else
+ dwStyle |= UDS_ALIGNRIGHT;
+
+ if (iupAttribGetBoolean(ih, "SPINWRAP"))
+ dwStyle |= UDS_WRAP;
+
+ if (iupAttribGetBoolean(ih, "SPINAUTO"))
+ dwStyle |= UDS_SETBUDDYINT;
+
+ hSpin = CreateWindowEx(0, /* extended window style */
+ UPDOWN_CLASS, /* window class */
+ NULL, /* title */
+ dwStyle, /* window style */
+ 0, /* x-position */
+ 0, /* y-position */
+ 10, /* default width to avoid 0 */
+ 10, /* default height to avoid 0 */
+ GetParent(ih->handle), /* window parent */
+ (HMENU)serial, /* child identifier */
+ iupwin_hinstance, /* instance of app. */
+ NULL);
+
+ if (!hSpin)
+ return;
+
+ iupwinHandleAdd(ih, hSpin);
+
+ /* Process WM_NOTIFY */
+ IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winTextSpinWmNotify);
+
+ SendMessage(hSpin, UDM_SETBUDDY, (WPARAM)ih->handle, 0);
+ iupAttribSetStr(ih, "_IUPWIN_SPIN", (char*)hSpin);
+
+ /* default values */
+ SendMessage(hSpin, UDM_SETRANGE32, 0, 100);
+ SendMessage(hSpin, UDM_SETPOS32, 0, 0);
+}
+
+static int winTextWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp)
+{
+ int cmd = HIWORD(wp);
+ switch (cmd)
+ {
+ case EN_CHANGE:
+ {
+ if (iupAttribGetStr(ih, "IUPWIN_IGNORECHANGE"))
+ return 0;
+
+ iupBaseCallValueChangedCb(ih);
+ break;
+ }
+ }
+
+ (void)lp;
+ return 0; /* not used */
+}
+
+static void winTextLayoutUpdateMethod(Ihandle* ih)
+{
+ HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN");
+ if (hSpin)
+ {
+ if (iupStrEqualNoCase(iupAttribGetStr(ih, "SPINALIGN"), "LEFT"))
+ {
+ SetWindowPos(ih->handle, NULL, ih->x+ih->currentheight-1, ih->y, ih->currentwidth-ih->currentheight, ih->currentheight,
+ SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
+
+ SetWindowPos(hSpin, NULL, ih->x, ih->y, ih->currentheight, ih->currentheight,
+ SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
+ }
+ else
+ {
+ SetWindowPos(ih->handle, NULL, ih->x, ih->y, ih->currentwidth-ih->currentheight, ih->currentheight,
+ SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
+
+ SetWindowPos(hSpin, NULL, ih->x+ih->currentwidth-ih->currentheight-1, ih->y, ih->currentheight, ih->currentheight,
+ SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
+ }
+ }
+ else
+ iupdrvBaseLayoutUpdateMethod(ih);
+}
+
+static int winTextMapMethod(Ihandle* ih)
+{
+ DWORD dwStyle = WS_CHILD,
+ dwExStyle = 0;
+ char* winclass = "EDIT", *value;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ dwStyle |= WS_TABSTOP;
+
+ if (ih->data->has_formatting)
+ {
+ /* enable richedit 3.0 */
+ static HMODULE richedit = NULL;
+ if (!richedit)
+ richedit = LoadLibrary("Riched20.dll");
+ if (!richedit)
+ return IUP_ERROR;
+
+ winclass = RICHEDIT_CLASS;
+ }
+
+ if (ih->data->is_multiline)
+ {
+ dwStyle |= ES_AUTOVSCROLL|ES_MULTILINE|ES_WANTRETURN;
+
+ if (iupAttribGetBoolean(ih, "WORDWRAP"))
+ {
+ ih->data->sb &= ~IUP_SB_HORIZ; /* must remove the horizontal scroolbar */
+ /* and do not specify ES_AUTOHSCROLL, the control automatically wraps words */
+ }
+ else
+ dwStyle |= ES_AUTOHSCROLL;
+
+ if (ih->data->sb & IUP_SB_HORIZ)
+ dwStyle |= WS_HSCROLL;
+ if (ih->data->sb & IUP_SB_VERT)
+ dwStyle |= WS_VSCROLL;
+
+ if (ih->data->has_formatting && ih->data->sb != IUP_SB_NONE)
+ {
+ if (!iupAttribGetBoolean(ih, "AUTOHIDE"))
+ dwStyle |= ES_DISABLENOSCROLL;
+ }
+ }
+ else
+ {
+ dwStyle |= ES_AUTOHSCROLL|ES_NOHIDESEL;
+
+ if (iupAttribGetBoolean(ih, "PASSWORD"))
+ dwStyle |= ES_PASSWORD;
+ }
+
+ value = iupAttribGet(ih, "ALIGNMENT");
+ if (value)
+ {
+ if (iupStrEqualNoCase(value, "ARIGHT"))
+ dwStyle |= ES_RIGHT;
+ else if (iupStrEqualNoCase(value, "ACENTER"))
+ dwStyle |= ES_CENTER;
+ else /* default "ALEFT" */
+ dwStyle |= ES_LEFT;
+ }
+
+ if (iupAttribGetBoolean(ih, "BORDER"))
+ dwExStyle |= WS_EX_CLIENTEDGE;
+
+ if (!iupwinCreateWindowEx(ih, winclass, dwExStyle, dwStyle))
+ return IUP_ERROR;
+
+ /* Process ACTION_CB and CARET_CB */
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winTextProc);
+
+ /* Process background color */
+ IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winTextCtlColor);
+
+ /* Process WM_COMMAND */
+ IupSetCallback(ih, "_IUPWIN_COMMAND_CB", (Icallback)winTextWmCommand);
+
+ /* set defaults */
+ SendMessage(ih->handle, EM_LIMITTEXT, 0, 0L);
+ {
+ int tabsize = 8*4;
+ SendMessage(ih->handle, EM_SETTABSTOPS, (WPARAM)1L, (LPARAM)&tabsize);
+ }
+
+ if (!ih->data->is_multiline && iupAttribGetBoolean(ih, "SPIN"))
+ winTextCreateSpin(ih);
+
+ /* configure for DRAG&DROP */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ if (ih->data->has_formatting)
+ {
+ SendMessage(ih->handle, EM_SETTEXTMODE, (WPARAM)(TM_RICHTEXT|TM_MULTILEVELUNDO|TM_SINGLECODEPAGE), 0);
+ SendMessage(ih->handle, EM_SETEVENTMASK, 0, ENM_CHANGE);
+ }
+
+ if (ih->data->formattags)
+ {
+ /* must update FONT before updating the format during map */
+ iupUpdateStandardFontAttrib(ih);
+ iupAttribSetStr(ih, "_IUPWIN_IGNORE_FONT", "1");
+
+ iupTextUpdateFormatTags(ih);
+ }
+
+ IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)winTextConvertXYToPos);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvTextInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winTextMapMethod;
+ ic->LayoutUpdate = winTextLayoutUpdateMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, winTextSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winTextSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, winTextSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_NOT_MAPPED); /* usually black */
+
+ /* IupText only */
+ iupClassRegisterAttribute(ic, "PADDING", iupTextGetPaddingAttrib, winTextSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "VALUE", winTextGetValueAttrib, winTextSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTEDTEXT", winTextGetSelectedTextAttrib, winTextSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTION", winTextGetSelectionAttrib, winTextSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SELECTIONPOS", winTextGetSelectionPosAttrib, winTextSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARET", winTextGetCaretAttrib, winTextSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "CARETPOS", winTextGetCaretPosAttrib, winTextSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "INSERT", NULL, winTextSetInsertAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "APPEND", NULL, winTextSetAppendAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "READONLY", winTextGetReadOnlyAttrib, winTextSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "NC", iupTextGetNCAttrib, winTextSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, winTextSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTO", NULL, winTextSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, winTextSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINMIN", NULL, winTextSetSpinMinAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINMAX", NULL, winTextSetSpinMaxAttrib, IUPAF_SAMEASSYSTEM, "100", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPININC", NULL, winTextSetSpinIncAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPINVALUE", winTextGetSpinValueAttrib, winTextSetSpinValueAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT);
+
+ /* IupText Windows and GTK only */
+ iupClassRegisterAttribute(ic, "ADDFORMATTAG", NULL, iupTextSetAddFormatTagAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ADDFORMATTAG_HANDLE", NULL, iupTextSetAddFormatTagHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, winTextSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ALEFT", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FORMATTING", iupTextGetFormattingAttrib, iupTextSetFormattingAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "OVERWRITE", NULL, winTextSetOverwriteAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "REMOVEFORMATTING", NULL, winTextSetRemoveFormattingAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "TABSIZE", NULL, winTextSetTabSizeAttrib, IUPAF_SAMEASSYSTEM, "8", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "PASSWORD", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+
+ /* IupText Windows only */
+ iupClassRegisterAttribute(ic, "CUEBANNER", NULL, winTextSetCueBannerAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILTER", NULL, winTextSetFilterAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_timer.c b/iup/src/win/iupwin_timer.c
new file mode 100755
index 0000000..f2bb9c5
--- /dev/null
+++ b/iup/src/win/iupwin_timer.c
@@ -0,0 +1,88 @@
+/** \file
+ * \brief Timer for the Windows Driver.
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_assert.h"
+#include "iup_timer.h"
+
+
+static Itable* wintimer_id_table = NULL; /* table indexed by ID containing Ihandle* address */
+
+static void CALLBACK winTimerProc(HWND hwnd, UINT msg, UINT_PTR wid, DWORD time)
+{
+ Icallback cb;
+ Ihandle *ih;
+
+ (void)time;
+ (void)msg;
+ (void)hwnd;
+
+ ih = (Ihandle*)iupTableGet(wintimer_id_table, (char*)wid);
+
+ if (!iupObjectCheck(ih)) /* control could be destroyed before timer callback */
+ return;
+
+ cb = IupGetCallback(ih, "ACTION_CB");
+ if(cb)
+ {
+ if (cb(ih) == IUP_CLOSE)
+ IupExitLoop();
+ }
+}
+
+void iupdrvTimerRun(Ihandle *ih)
+{
+ unsigned int time_ms;
+
+ if (ih->serial > 0) /* timer already started */
+ return;
+
+ time_ms = iupAttribGetInt(ih, "TIME");
+ if (time_ms > 0)
+ {
+ ih->serial = SetTimer(NULL, 0, time_ms, (TIMERPROC)winTimerProc);
+ iupTableSet(wintimer_id_table, (const char*)ih->serial, ih, IUPTABLE_POINTER);
+ }
+}
+
+void iupdrvTimerStop(Ihandle* ih)
+{
+ if (ih->serial > 0)
+ {
+ KillTimer(NULL, ih->serial);
+ iupTableRemove(wintimer_id_table, (const char*)ih->serial);
+ ih->serial = -1;
+ }
+}
+
+static void winTimerRelease(Iclass* ic)
+{
+ (void)ic;
+
+ if (wintimer_id_table)
+ {
+ iupTableDestroy(wintimer_id_table);
+ wintimer_id_table = NULL;
+ }
+}
+
+void iupdrvTimerInitClass(Iclass* ic)
+{
+ ic->Release = winTimerRelease;
+
+ if (!wintimer_id_table)
+ wintimer_id_table = iupTableCreate(IUPTABLE_POINTERINDEXED);
+}
diff --git a/iup/src/win/iupwin_tips.c b/iup/src/win/iupwin_tips.c
new file mode 100755
index 0000000..f717ace
--- /dev/null
+++ b/iup/src/win/iupwin_tips.c
@@ -0,0 +1,191 @@
+/** \file
+ * \brief Windows Driver TIPS management
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include "iup.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+
+
+#ifndef TTM_POPUP /* it is defined only when _WIN32_WINNT >= 0x0501 */
+#define TTM_POPUP (WM_USER + 34)
+#endif
+
+static HWND winTipsCreate(HWND hParent)
+{
+ RECT rect = {1,1,1,1};
+ HWND tips_hwnd = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, (LPSTR) NULL, TTS_ALWAYSTIP,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ hParent, (HMENU)NULL, iupwin_hinstance, NULL);
+ SendMessage(tips_hwnd, TTM_SETMAXTIPWIDTH, 0, (LPARAM)(INT)3000);
+ SendMessage(tips_hwnd, TTM_SETMARGIN, (WPARAM)0, (LPARAM)&rect);
+ return tips_hwnd;
+}
+
+static int winTipsSendMessage(Ihandle* ih, HWND tips_hwnd, UINT msg)
+{
+ TOOLINFO ti;
+ ZeroMemory(&ti, sizeof(TOOLINFO));
+ ti.cbSize = sizeof(TOOLINFO);
+ ti.uFlags = TTF_SUBCLASS;
+ ti.hinst = iupwin_hinstance;
+ ti.uId = 0;
+ ti.hwnd = ih->handle;
+ ti.lpszText = LPSTR_TEXTCALLBACK;
+ ti.rect.right = 3000;
+ ti.rect.bottom = 3000;
+
+ return SendMessage(tips_hwnd, msg, 0, (LPARAM)&ti);
+}
+
+int iupdrvBaseSetTipAttrib(Ihandle* ih, const char* value)
+{
+ HWND tips_hwnd = (HWND)iupAttribGet(ih, "_IUPWIN_TIPSWIN");
+ if (!tips_hwnd)
+ {
+ tips_hwnd = winTipsCreate(ih->handle);
+ iupAttribSetStr(ih, "_IUPWIN_TIPSWIN", (char*)tips_hwnd);
+ iupwinHandleAdd(ih, tips_hwnd);
+ }
+
+ if (value)
+ winTipsSendMessage(ih, tips_hwnd, TTM_ADDTOOL);
+ else
+ winTipsSendMessage(ih, tips_hwnd, TTM_DELTOOL);
+
+ return 1;
+}
+
+int iupdrvBaseSetTipVisibleAttrib(Ihandle* ih, const char* value)
+{
+ HWND tips_hwnd = (HWND)iupAttribGet(ih, "_IUPWIN_TIPSWIN");
+ if (!tips_hwnd)
+ return 0;
+
+ /* must use IupGetAttribute to use inheritance */
+ if (!IupGetAttribute(ih, "TIP"))
+ return 0;
+
+ if (iupStrBoolean(value))
+ SendMessage(tips_hwnd, TTM_POPUP, 0, 0); /* XP Only */
+ else
+ SendMessage(tips_hwnd, TTM_POP, 0, 0);
+
+ return 0;
+}
+
+void iupwinTipsGetDispInfo(LPARAM lp)
+{
+ COLORREF color, tip_color;
+ NMTTDISPINFO* tips_info;
+ Ihandle* ih;
+ HWND tips_hwnd;
+ char* value;
+
+ if (!lp) return;
+
+ tips_info = (NMTTDISPINFO*)lp;
+ ih = iupwinHandleGet(tips_info->hdr.hwndFrom); /* hwndFrom is the tooltip window */
+ if (!ih) return;
+
+ tips_hwnd = (HWND)iupAttribGet(ih, "_IUPWIN_TIPSWIN");
+ if (tips_hwnd != tips_info->hdr.hwndFrom) return;
+
+ tips_info->hinst = NULL;
+ tips_info->lpszText = IupGetAttribute(ih, "TIP"); /* must use IupGetAttribute to use inheritance */
+
+ {
+ HFONT hfont;
+ value = iupAttribGetStr(ih, "TIPFONT");
+ if (value)
+ {
+ if (iupStrEqualNoCase(value, "SYSTEM"))
+ hfont = NULL;
+ else
+ hfont = iupwinGetHFont(value);
+ }
+ else
+ hfont = (HFONT)iupwinGetHFontAttrib(ih);
+
+ if (hfont)
+ {
+ HFONT tip_hfont = (HFONT)SendMessage(tips_hwnd, WM_GETFONT, 0, 0);
+ if (tip_hfont != hfont)
+ SendMessage(tips_hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE,0));
+ }
+ }
+
+ iupwinGetColorRef(ih, "TIPBGCOLOR", &color);
+ tip_color = (COLORREF)SendMessage(tips_hwnd, TTM_GETTIPBKCOLOR, 0, 0);
+ if (color != tip_color)
+ SendMessage(tips_hwnd, TTM_SETTIPBKCOLOR, (WPARAM)color, 0);
+
+ iupwinGetColorRef(ih, "TIPFGCOLOR", &color);
+ tip_color = (COLORREF)SendMessage(tips_hwnd, TTM_GETTIPTEXTCOLOR, 0, 0);
+ if (color != tip_color)
+ SendMessage(tips_hwnd, TTM_SETTIPTEXTCOLOR, (WPARAM)color, 0);
+
+ {
+ int ballon = IupGetInt(ih, "TIPBALLON"); /* must use IupGetInt to use inheritance */
+ DWORD style = GetWindowLong(tips_hwnd, GWL_STYLE);
+ int tip_ballon = style & TTS_BALLOON? 1: 0;
+ if (tip_ballon != ballon)
+ {
+ if (ballon)
+ style |= TTS_BALLOON;
+ else
+ style &= ~TTS_BALLOON;
+ SetWindowLong(tips_hwnd, GWL_STYLE, style);
+ }
+
+ if (ballon)
+ {
+ char* ballon_title = IupGetAttribute(ih, "TIPBALLONTITLE"); /* must use IupGetAttribute to use inheritance */
+ int ballon_icon = IupGetInt(ih, "TIPBALLONTITLEICON"); /* must use IupGetInt to use inheritance */
+ SendMessage(tips_hwnd, TTM_SETTITLEA, ballon_icon, (LPARAM)ballon_title);
+ }
+ else
+ SendMessage(tips_hwnd, TTM_SETTITLEA, 0, 0);
+ }
+
+ {
+ int delay = IupGetInt(ih, "TIPDELAY"); /* must use IupGetInt to use inheritance */
+ int tip_delay = SendMessage(tips_hwnd, TTM_GETDELAYTIME, TTDT_AUTOPOP, 0);
+ if (delay != tip_delay)
+ SendMessage(tips_hwnd, TTM_SETDELAYTIME, TTDT_AUTOPOP, (LPARAM)MAKELONG(delay, 0));
+ }
+
+ {
+ TOOLINFO ti;
+
+ ZeroMemory(&ti, sizeof(TOOLINFO));
+ ti.cbSize = sizeof(TOOLINFO);
+ ti.uId = 0;
+ ti.hwnd = ih->handle;
+
+ value = iupAttribGet(ih, "TIPRECT");
+ if (value)
+ {
+ int x1, x2, y1, y2;
+ sscanf(value, "%d %d %d %d", &x1, &y1, &x2, &y2);
+ ti.rect.left = x1; ti.rect.right = x2;
+ ti.rect.top = y1; ti.rect.bottom = y2;
+ }
+ else
+ GetClientRect(ih->handle, &ti.rect);
+
+ SendMessage(tips_hwnd, TTM_NEWTOOLRECT, 0, (LPARAM)&ti);
+ }
+}
diff --git a/iup/src/win/iupwin_toggle.c b/iup/src/win/iupwin_toggle.c
new file mode 100755
index 0000000..fcaa438
--- /dev/null
+++ b/iup/src/win/iupwin_toggle.c
@@ -0,0 +1,693 @@
+/** \file
+ * \brief Toggle Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_toggle.h"
+#include "iup_drv.h"
+#include "iup_image.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_draw.h"
+
+
+#ifndef CDIS_SHOWKEYBOARDCUES
+#define CDIS_SHOWKEYBOARDCUES 0x0200 /* it is defined only when _WIN32_WINNT >= 0x0501 */
+#endif
+
+
+void iupdrvToggleAddCheckBox(int *x, int *y)
+{
+ (*x) += 16+6;
+ if ((*y) < 16) (*y) = 16; /* minimum height */
+}
+
+static int winToggleIsActive(Ihandle* ih)
+{
+ return iupAttribGetInt(ih, "_IUPWIN_ACTIVE");
+}
+
+static void winToggleSetBitmap(Ihandle* ih, const char* name, int make_inactive)
+{
+ if (name)
+ {
+ HBITMAP bitmap = iupImageGetImage(name, ih, make_inactive);
+ SendMessage(ih->handle, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)bitmap);
+ }
+ else
+ SendMessage(ih->handle, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)NULL); /* if not defined */
+}
+
+static void winToggleUpdateImage(Ihandle* ih, int active, int check)
+{
+ /* called only when (ih->data->type == IUP_TOGGLE_IMAGE && !iupwin_comctl32ver6) */
+ char* name;
+
+ if (!active)
+ {
+ name = iupAttribGet(ih, "IMINACTIVE");
+ if (name)
+ winToggleSetBitmap(ih, name, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ name = iupAttribGet(ih, "IMAGE");
+ winToggleSetBitmap(ih, name, 1); /* make_inactive */
+ }
+ }
+ else
+ {
+ /* must restore the normal image */
+ if (check)
+ {
+ name = iupAttribGet(ih, "IMPRESS");
+ if (name)
+ winToggleSetBitmap(ih, name, 0);
+ else
+ {
+ /* if not defined then automaticaly create one based on IMAGE */
+ name = iupAttribGet(ih, "IMAGE");
+ winToggleSetBitmap(ih, name, 0);
+ }
+ }
+ else
+ {
+ name = iupAttribGet(ih, "IMAGE");
+ if (name)
+ winToggleSetBitmap(ih, name, 0);
+ }
+ }
+}
+
+static void winToggleGetAlignment(Ihandle* ih, int *horiz_alignment, int *vert_alignment)
+{
+ char value1[30]="", value2[30]="";
+
+ iupStrToStrStr(iupAttribGetStr(ih, "ALIGNMENT"), value1, value2, ':');
+
+ if (iupStrEqualNoCase(value1, "ARIGHT"))
+ *horiz_alignment = IUP_ALIGN_ARIGHT;
+ else if (iupStrEqualNoCase(value1, "ALEFT"))
+ *horiz_alignment = IUP_ALIGN_ALEFT;
+ else /* "ACENTER" */
+ *horiz_alignment = IUP_ALIGN_ACENTER;
+
+ if (iupStrEqualNoCase(value2, "ABOTTOM"))
+ *vert_alignment = IUP_ALIGN_ABOTTOM;
+ else if (iupStrEqualNoCase(value2, "ATOP"))
+ *vert_alignment = IUP_ALIGN_ATOP;
+ else /* "ACENTER" */
+ *vert_alignment = IUP_ALIGN_ACENTER;
+}
+
+static void winToggleDrawImage(Ihandle* ih, HDC hDC, int rect_width, int rect_height, int border, UINT itemState)
+{
+ int xpad = ih->data->horiz_padding + border,
+ ypad = ih->data->vert_padding + border;
+ int horiz_alignment, vert_alignment;
+ int x, y, width, height, bpp, shift = 1;
+ HBITMAP hBitmap, hMask = NULL;
+ char *name;
+ int make_inactive = 0;
+
+ if (itemState & ODS_DISABLED)
+ {
+ name = iupAttribGet(ih, "IMINACTIVE");
+ if (!name)
+ {
+ name = iupAttribGet(ih, "IMAGE");
+ make_inactive = 1;
+ }
+ }
+ else
+ {
+ name = iupAttribGet(ih, "IMPRESS");
+ if (itemState & ODS_SELECTED && name)
+ shift = 0;
+ else
+ name = iupAttribGet(ih, "IMAGE");
+ }
+
+ hBitmap = iupImageGetImage(name, ih, make_inactive);
+ if (!hBitmap)
+ return;
+
+ /* must use this info, since image can be a driver image loaded from resources */
+ iupdrvImageGetInfo(hBitmap, &width, &height, &bpp);
+
+ winToggleGetAlignment(ih, &horiz_alignment, &vert_alignment);
+ if (horiz_alignment == IUP_ALIGN_ARIGHT)
+ x = rect_width - (width + 2*xpad);
+ else if (horiz_alignment == IUP_ALIGN_ACENTER)
+ x = (rect_width - (width + 2*xpad))/2;
+ else /* ALEFT */
+ x = 0;
+
+ if (vert_alignment == IUP_ALIGN_ABOTTOM)
+ y = rect_height - (height + 2*ypad);
+ else if (vert_alignment == IUP_ALIGN_ATOP)
+ y = 0;
+ else /* ACENTER */
+ y = (rect_height - (height + 2*ypad))/2;
+
+ x += xpad;
+ y += ypad;
+
+ if (itemState & ODS_SELECTED && !iupwin_comctl32ver6 && shift)
+ {
+ x++;
+ y++;
+ }
+
+ if (bpp == 8)
+ hMask = iupdrvImageCreateMask(IupGetHandle(name));
+
+ iupwinDrawBitmap(hDC, hBitmap, hMask, x, y, width, height, bpp);
+
+ if (hMask)
+ DeleteObject(hMask);
+}
+
+static void winToggleDrawItem(Ihandle* ih, DRAWITEMSTRUCT *drawitem)
+{
+ int width, height, border = 4, check;
+ HDC hDC;
+ iupwinBitmapDC bmpDC;
+
+ width = drawitem->rcItem.right - drawitem->rcItem.left;
+ height = drawitem->rcItem.bottom - drawitem->rcItem.top;
+
+ hDC = iupwinDrawCreateBitmapDC(&bmpDC, drawitem->hDC, width, height);
+
+ iupwinDrawParentBackground(ih, hDC, &drawitem->rcItem);
+
+ check = SendMessage(ih->handle, BM_GETCHECK, 0, 0L);
+ if (check)
+ drawitem->itemState |= ODS_SELECTED;
+ else
+ drawitem->itemState |= ODS_DEFAULT; /* use default mark for NOT checked */
+
+ iupwinDrawButtonBorder(ih->handle, hDC, &drawitem->rcItem, drawitem->itemState);
+
+ winToggleDrawImage(ih, hDC, width, height, border, drawitem->itemState);
+
+ if (drawitem->itemState & ODS_FOCUS)
+ {
+ border--;
+ iupdrvDrawFocusRect(ih, hDC, border, border, width-2*border, height-2*border);
+ }
+
+ iupwinDrawDestroyBitmapDC(&bmpDC);
+}
+
+
+/***********************************************************************************************/
+
+
+static int winToggleSetImageAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (value != iupAttribGet(ih, "IMAGE"))
+ iupAttribSetStr(ih, "IMAGE", (char*)value);
+
+ if (iupwin_comctl32ver6)
+ iupdrvDisplayRedraw(ih);
+ else
+ {
+ int check = SendMessage(ih->handle, BM_GETCHECK, 0L, 0L);
+ winToggleUpdateImage(ih, winToggleIsActive(ih), check);
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int winToggleSetImInactiveAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (value != iupAttribGet(ih, "IMINACTIVE"))
+ iupAttribSetStr(ih, "IMINACTIVE", (char*)value);
+
+ if (iupwin_comctl32ver6)
+ iupdrvDisplayRedraw(ih);
+ else
+ {
+ int check = SendMessage(ih->handle, BM_GETCHECK, 0L, 0L);
+ winToggleUpdateImage(ih, winToggleIsActive(ih), check);
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int winToggleSetImPressAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (value != iupAttribGet(ih, "IMPRESS"))
+ iupAttribSetStr(ih, "IMPRESS", (char*)value);
+
+ if (iupwin_comctl32ver6)
+ iupdrvDisplayRedraw(ih);
+ else
+ {
+ int check = SendMessage(ih->handle, BM_GETCHECK, 0L, 0L);
+ winToggleUpdateImage(ih, winToggleIsActive(ih), check);
+ }
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static int winToggleSetValueAttrib(Ihandle* ih, const char* value)
+{
+ Ihandle *radio;
+ int check;
+
+ if (iupStrEqualNoCase(value,"NOTDEF"))
+ check = BST_INDETERMINATE;
+ else if (iupStrBoolean(value))
+ check = BST_CHECKED;
+ else
+ check = BST_UNCHECKED;
+
+ /* This is necessary because Windows does not handle the radio state
+ when a toggle is programatically changed. */
+ radio = iupRadioFindToggleParent(ih);
+ if (radio)
+ {
+ int oldcheck = (int)SendMessage(ih->handle, BM_GETCHECK, 0, 0L);
+
+ Ihandle* last_tg = (Ihandle*)iupAttribGet(radio, "_IUPWIN_LASTTOGGLE");
+ if (check)
+ {
+ if (iupObjectCheck(last_tg) && last_tg != ih)
+ SendMessage(last_tg->handle, BM_SETCHECK, BST_UNCHECKED, 0L);
+ iupAttribSetStr(radio, "_IUPWIN_LASTTOGGLE", (char*)ih);
+ }
+
+ if (last_tg != ih && oldcheck != check)
+ SendMessage(ih->handle, BM_SETCHECK, check, 0L);
+ }
+ else
+ SendMessage(ih->handle, BM_SETCHECK, check, 0L);
+
+ if (ih->data->type == IUP_TOGGLE_IMAGE && !iupwin_comctl32ver6)
+ winToggleUpdateImage(ih, winToggleIsActive(ih), check);
+
+ return 0;
+}
+
+static char* winToggleGetValueAttrib(Ihandle* ih)
+{
+ int check = (int)SendMessage(ih->handle, BM_GETCHECK, 0, 0L);
+ if (check == BST_INDETERMINATE)
+ return "NOTDEF";
+ else if (check == BST_CHECKED)
+ return "ON";
+ else
+ return "OFF";
+}
+
+static int winToggleSetActiveAttrib(Ihandle* ih, const char* value)
+{
+ /* update the inactive image if necessary */
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (iupwin_comctl32ver6)
+ {
+ iupBaseSetActiveAttrib(ih, value);
+ iupdrvDisplayRedraw(ih);
+ return 0;
+ }
+ else
+ {
+ int active = iupStrBoolean(value);
+ int check = SendMessage(ih->handle, BM_GETCHECK, 0, 0L);
+ if (active)
+ iupAttribSetStr(ih, "_IUPWIN_ACTIVE", "YES");
+ else
+ iupAttribSetStr(ih, "_IUPWIN_ACTIVE", "NO");
+ winToggleUpdateImage(ih, active, check);
+ return 0;
+ }
+ }
+
+ return iupBaseSetActiveAttrib(ih, value);
+}
+
+static char* winToggleGetActiveAttrib(Ihandle* ih)
+{
+ if (ih->data->type == IUP_TOGGLE_IMAGE && !iupwin_comctl32ver6)
+ return iupAttribGet(ih, "_IUPWIN_ACTIVE");
+ else
+ return iupBaseGetActiveAttrib(ih);
+}
+
+static int winToggleSetTitleAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ {
+ if (!value)
+ value = "";
+ SetWindowText(ih->handle, value);
+ }
+ return 0;
+}
+
+static int winToggleSetPaddingAttrib(Ihandle* ih, const char* value)
+{
+ iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x');
+
+ if (ih->handle && iupwin_comctl32ver6 && ih->data->type == IUP_TOGGLE_IMAGE)
+ iupdrvDisplayRedraw(ih);
+
+ return 0;
+}
+
+static int winToggleSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ (void)value;
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ /* update internal image cache for controls that have the IMAGE attribute */
+ iupAttribSetStr(ih, "BGCOLOR", value);
+ iupImageUpdateParent(ih);
+ iupdrvDisplayRedraw(ih);
+ }
+ return 1;
+}
+
+static char* winToggleGetBgColorAttrib(Ihandle* ih)
+{
+ /* the most important use of this is to provide
+ the correct background for images */
+ if (iupwin_comctl32ver6 && ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ COLORREF cr;
+ if (iupwinDrawGetThemeButtonBgColor(ih->handle, &cr))
+ {
+ char* str = iupStrGetMemory(20);
+ sprintf(str, "%d %d %d", (int)GetRValue(cr), (int)GetGValue(cr), (int)GetBValue(cr));
+ return str;
+ }
+ }
+
+ if (ih->data->type == IUP_TOGGLE_TEXT)
+ return iupBaseNativeParentGetBgColorAttrib(ih);
+ else
+ return IupGetGlobal("DLGBGCOLOR");
+}
+
+
+/****************************************************************************************/
+
+
+static int winToggleCtlColor(Ihandle* ih, HDC hdc, LRESULT *result)
+{
+ COLORREF cr;
+
+ SetBkMode(hdc, TRANSPARENT);
+
+ if (iupwinGetColorRef(ih, "FGCOLOR", &cr))
+ SetTextColor(hdc, cr);
+
+ if (iupwinGetParentBgColor(ih, &cr))
+ {
+ SetDCBrushColor(hdc, cr);
+ *result = (LRESULT)GetStockObject(DC_BRUSH);
+ return 1;
+ }
+ return 0;
+}
+
+static int winToggleWmNotify(Ihandle* ih, NMHDR* msg_info, int *result)
+{
+ if (msg_info->code == NM_CUSTOMDRAW)
+ {
+ /* called only when iupwin_comctl32ver6 AND (ih->data->type==IUP_TOGGLE_IMAGE) */
+ NMCUSTOMDRAW *customdraw = (NMCUSTOMDRAW*)msg_info;
+
+ if (customdraw->dwDrawStage==CDDS_PREERASE)
+ {
+ DRAWITEMSTRUCT drawitem;
+ drawitem.itemState = 0;
+
+ if (customdraw->uItemState & CDIS_DISABLED)
+ drawitem.itemState |= ODS_DISABLED;
+ else if (customdraw->uItemState & CDIS_SELECTED)
+ drawitem.itemState |= ODS_SELECTED;
+ else if (customdraw->uItemState & CDIS_HOT)
+ drawitem.itemState |= ODS_HOTLIGHT;
+ else if (customdraw->uItemState & CDIS_DEFAULT)
+ drawitem.itemState |= ODS_DEFAULT;
+
+ if (customdraw->uItemState & CDIS_FOCUS && (customdraw->uItemState & CDIS_SHOWKEYBOARDCUES))
+ drawitem.itemState |= ODS_FOCUS;
+
+ drawitem.hDC = customdraw->hdc;
+ drawitem.rcItem = customdraw->rc;
+
+ winToggleDrawItem(ih, (void*)&drawitem); /* Simulate a WM_DRAWITEM */
+
+ *result = CDRF_SKIPDEFAULT;
+ return 1;
+ }
+ }
+
+ return 0; /* result not used */
+}
+
+static int winToggleProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ (void)lp;
+ (void)wp;
+
+ switch (msg)
+ {
+ case WM_MOUSEACTIVATE:
+ if (!winToggleIsActive(ih))
+ {
+ *result = MA_NOACTIVATEANDEAT;
+ return 1;
+ }
+ break;
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_ACTIVATE:
+ case WM_SETFOCUS:
+ if (!winToggleIsActive(ih))
+ {
+ *result = 0;
+ return 1;
+ }
+ break;
+ }
+
+ if (msg == WM_LBUTTONDOWN)
+ winToggleUpdateImage(ih, 1, 1);
+ else if (msg == WM_LBUTTONUP)
+ winToggleUpdateImage(ih, 1, 0);
+
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+static int winToggleWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp)
+{
+ (void)lp;
+
+ switch (HIWORD(wp))
+ {
+ case BN_DOUBLECLICKED:
+ case BN_CLICKED:
+ {
+ Ihandle *radio;
+ IFni cb;
+ int check = SendMessage(ih->handle, BM_GETCHECK, 0, 0L);
+
+ if (ih->data->type == IUP_TOGGLE_IMAGE && !iupwin_comctl32ver6)
+ {
+ int active = winToggleIsActive(ih);
+ winToggleUpdateImage(ih, active, check);
+ if (!active)
+ return 0;
+ }
+
+ radio = iupRadioFindToggleParent(ih);
+ if (radio)
+ {
+ /* This is necessary because Windows does not send a message
+ when a toggle is unchecked in a Radio.
+ Also if the toggle is already checked in a radio,
+ a click will call the callback again. */
+
+ Ihandle* last_tg = (Ihandle*)iupAttribGet(radio, "_IUPWIN_LASTTOGGLE");
+ if (iupObjectCheck(last_tg) && last_tg != ih)
+ {
+ /* uncheck last toggle */
+ SendMessage(last_tg->handle, BM_SETCHECK, BST_UNCHECKED, 0L);
+
+ cb = (IFni) IupGetCallback(last_tg, "ACTION");
+ if (cb && cb(last_tg, 0) == IUP_CLOSE)
+ IupExitLoop();
+
+ iupBaseCallValueChangedCb(last_tg);
+ }
+ iupAttribSetStr(radio, "_IUPWIN_LASTTOGGLE", (char*)ih);
+
+ if (last_tg != ih)
+ {
+ /* check new toggle */
+ SendMessage(ih->handle, BM_SETCHECK, BST_CHECKED, 0L);
+
+ cb = (IFni)IupGetCallback(ih, "ACTION");
+ if (cb && cb (ih, 1) == IUP_CLOSE)
+ IupExitLoop();
+
+ iupBaseCallValueChangedCb(ih);
+ }
+ }
+ else
+ {
+ if (check == BST_INDETERMINATE)
+ check = -1;
+
+ cb = (IFni)IupGetCallback(ih, "ACTION");
+ if (cb && cb (ih, check) == IUP_CLOSE)
+ IupExitLoop();
+
+ iupBaseCallValueChangedCb(ih);
+ }
+ }
+ }
+
+
+ return 0; /* not used */
+}
+
+static int winToggleMapMethod(Ihandle* ih)
+{
+ Ihandle* radio = iupRadioFindToggleParent(ih);
+ char* value;
+ DWORD dwStyle = WS_CHILD |
+ BS_NOTIFY; /* necessary because of the base messages */
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (radio)
+ ih->data->radio = 1;
+
+ value = iupAttribGet(ih, "IMAGE");
+ if (value)
+ {
+ ih->data->type = IUP_TOGGLE_IMAGE;
+ dwStyle |= BS_BITMAP|BS_PUSHLIKE;
+ }
+ else
+ {
+ ih->data->type = IUP_TOGGLE_TEXT;
+ dwStyle |= BS_TEXT|BS_MULTILINE;
+
+ if (iupAttribGetBoolean(ih, "RIGHTBUTTON"))
+ dwStyle |= BS_RIGHTBUTTON;
+ }
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ dwStyle |= WS_TABSTOP;
+
+ if (radio)
+ {
+ dwStyle |= BS_RADIOBUTTON;
+
+ if (!iupAttribGet(radio, "_IUPWIN_LASTTOGGLE"))
+ {
+ /* this is the first toggle in the radio, and the last toggle with VALUE=ON */
+ iupAttribSetStr(ih, "VALUE","ON");
+ }
+ }
+ else
+ {
+ if (ih->data->type == IUP_TOGGLE_TEXT && iupAttribGetBoolean(ih, "3STATE"))
+ dwStyle |= BS_AUTO3STATE;
+ else
+ dwStyle |= BS_AUTOCHECKBOX;
+ }
+
+ if (!iupwinCreateWindowEx(ih, "BUTTON", 0, dwStyle))
+ return IUP_ERROR;
+
+ /* Process WM_COMMAND */
+ IupSetCallback(ih, "_IUPWIN_COMMAND_CB", (Icallback)winToggleWmCommand);
+
+ /* Process background color */
+ IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winToggleCtlColor);
+
+ if (ih->data->type == IUP_TOGGLE_IMAGE)
+ {
+ if (iupwin_comctl32ver6)
+ IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winToggleWmNotify); /* Process WM_NOTIFY */
+ else
+ {
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winToggleProc);
+ iupAttribSetStr(ih, "_IUPWIN_ACTIVE", "YES");
+ }
+ }
+
+ return IUP_NOERROR;
+}
+
+void iupdrvToggleInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winToggleMapMethod;
+
+ /* Driver Dependent Attribute functions */
+
+ /* Overwrite Visual */
+ iupClassRegisterAttribute(ic, "ACTIVE", winToggleGetActiveAttrib, winToggleSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", winToggleGetBgColorAttrib, winToggleSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);
+
+ /* Special */
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, "DLGFGCOLOR", NULL, IUPAF_NOT_MAPPED); /* force the new default value */
+ iupClassRegisterAttribute(ic, "TITLE", iupdrvBaseGetTitleAttrib, winToggleSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupToggle only */
+ iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, NULL, IUPAF_SAMEASSYSTEM, "ACENTER:ACENTER", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGE", NULL, winToggleSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, winToggleSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMPRESS", NULL, winToggleSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "VALUE", winToggleGetValueAttrib, winToggleSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "PADDING", iupToggleGetPaddingAttrib, winToggleSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED);
+
+ /* IupToggle Windows only */
+ iupClassRegisterAttribute(ic, "RIGHTBUTTON", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+
+ /* necessary because it uses an old HBITMAP solution when NOT using styles */
+ if (!iupwin_comctl32ver6) /* Used by iupdrvImageCreateImage */
+ iupClassRegisterAttribute(ic, "FLAT_ALPHA", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_tree.c b/iup/src/win/iupwin_tree.c
new file mode 100755
index 0000000..e6877dc
--- /dev/null
+++ b/iup/src/win/iupwin_tree.c
@@ -0,0 +1,2542 @@
+/** \file
+ * \brief Tree Control
+ *
+ * See Copyright Notice in iup.h
+ */
+
+#undef NOTREEVIEW
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_drv.h"
+#include "iup_stdcontrols.h"
+#include "iup_tree.h"
+#include "iup_image.h"
+#include "iup_array.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_draw.h"
+#include "iupwin_info.h"
+
+typedef struct _winTreeItemData
+{
+ COLORREF color;
+ unsigned char kind;
+ void* userdata;
+ HFONT hFont;
+ short image;
+ short image_expanded;
+} winTreeItemData;
+
+#ifndef TVN_ITEMCHANGING /* Vista Only */
+typedef struct tagNMTVITEMCHANGE {
+ NMHDR hdr;
+ UINT uChanged;
+ HTREEITEM hItem;
+ UINT uStateNew;
+ UINT uStateOld;
+ LPARAM lParam;
+} NMTVITEMCHANGE;
+#define TVN_ITEMCHANGINGA (TVN_FIRST-16)
+#define TVN_ITEMCHANGINGW (TVN_FIRST-17)
+#endif
+
+static void winTreeSetFocusNode(Ihandle* ih, HTREEITEM hItem);
+typedef int (*winTreeNodeFunc)(Ihandle* ih, HTREEITEM hItem, void* userdata);
+
+static int winTreeForEach(Ihandle* ih, HTREEITEM hItem, winTreeNodeFunc func, void* userdata)
+{
+ HTREEITEM hItemChild;
+
+ if (!hItem)
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+
+ while(hItem != NULL)
+ {
+ if (!func(ih, hItem, userdata))
+ return 0;
+
+ hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+ if (hItemChild)
+ {
+ /* Recursively traverse child items */
+ if (!winTreeForEach(ih, hItemChild, func, userdata))
+ return 0;
+ }
+
+ /* Go to next sibling item */
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem);
+ }
+
+ return 1;
+}
+
+/*****************************************************************************/
+/* FINDING ITEMS */
+/*****************************************************************************/
+static HTREEITEM winTreeFindNodeID(Ihandle* ih, HTREEITEM hItem, HTREEITEM hNode)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+
+ while(hItem != NULL)
+ {
+ /* ID control to traverse items */
+ ih->data->id_control++;
+
+ /* StateID founded! */
+ if(hItem == hNode)
+ return hItem;
+
+ /* Get hItem attributes */
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE|TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ /* Check whether we have child items */
+ if (itemData->kind == ITREE_BRANCH)
+ {
+ /* Recursively traverse child items */
+ HTREEITEM hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+ hItemChild = winTreeFindNodeID(ih, hItemChild, hNode);
+
+ /* StateID founded! */
+ if(hItemChild)
+ return hItemChild;
+ }
+ /* Go to next sibling item */
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem);
+ }
+
+ return NULL;
+}
+
+static int winTreeGetNodeId(Ihandle* ih, HTREEITEM hItem)
+{
+ HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+ ih->data->id_control = -1;
+ if (winTreeFindNodeID(ih, hItemRoot, hItem))
+ return ih->data->id_control;
+ else
+ return -1;
+}
+
+static HTREEITEM winTreeFindUserDataID(Ihandle* ih, HTREEITEM hItem, void* userdata)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+
+ while(hItem != NULL)
+ {
+ /* ID control to traverse items */
+ ih->data->id_control++;
+
+ /* Get hItem attributes */
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE|TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ /* userdata founded! */
+ if(itemData->userdata == userdata)
+ return hItem;
+
+ /* Check whether we have child items */
+ if (itemData->kind == ITREE_BRANCH)
+ {
+ /* Recursively traverse child items */
+ HTREEITEM hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+ hItemChild = winTreeFindUserDataID(ih, hItemChild, userdata);
+
+ /* userdata founded! */
+ if (hItemChild)
+ return hItemChild;
+ }
+
+ /* Go to next sibling item */
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem);
+ }
+
+ return NULL;
+}
+
+static int winTreeGetUserDataId(Ihandle* ih, void* userdata)
+{
+ HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+ ih->data->id_control = -1;
+ if (winTreeFindUserDataID(ih, hItemRoot, userdata))
+ return ih->data->id_control;
+ else
+ return -1;
+}
+
+static HTREEITEM winTreeFindNodeFromID(Ihandle* ih, HTREEITEM hItem)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+
+ while(hItem != NULL)
+ {
+ /* ID control to traverse items */
+ ih->data->id_control--;
+
+ /* StateID founded! */
+ if(ih->data->id_control < 0)
+ return hItem;
+
+ /* Get hItem attributes */
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE|TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ /* Check whether we have child items */
+ if (itemData->kind == ITREE_BRANCH)
+ {
+ /* Recursively traverse child items */
+ HTREEITEM hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+ hItemChild = winTreeFindNodeFromID(ih, hItemChild);
+
+ /* StateID founded! */
+ if(ih->data->id_control < 0)
+ return hItemChild;
+ }
+
+ /* Go to next sibling item */
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem);
+ }
+
+ return hItem;
+}
+
+static HTREEITEM winTreeFindNodeFromString(Ihandle* ih, const char* name_id)
+{
+ if (name_id[0])
+ {
+ HTREEITEM hRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+ iupStrToInt(name_id, &ih->data->id_control);
+ return winTreeFindNodeFromID(ih, hRoot);
+ }
+ else
+ return (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CARET, 0);
+}
+
+/* Recursively, find a new brother for the item
+ that will have its depth changed. Returns the new brother. */
+static HTREEITEM winTreeFindNewBrother(Ihandle* ih, HTREEITEM hBrotherItem)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+
+ while(hBrotherItem != NULL)
+ {
+ if(ih->data->id_control < 0)
+ return hBrotherItem;
+
+ item.hItem = hBrotherItem;
+ item.mask = TVIF_HANDLE|TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ if (itemData->kind == ITREE_BRANCH)
+ {
+ HTREEITEM hItemChild;
+
+ ih->data->id_control--;
+ hItemChild = winTreeFindNewBrother(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hBrotherItem));
+
+ if(ih->data->id_control < 0)
+ return hItemChild;
+ }
+
+ hBrotherItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hBrotherItem);
+ }
+
+ return hBrotherItem;
+}
+
+static HTREEITEM winTreeFindNodePointed(Ihandle* ih)
+{
+ TVHITTESTINFO info;
+ DWORD pos = GetMessagePos();
+ info.pt.x = LOWORD(pos);
+ info.pt.y = HIWORD(pos);
+
+ ScreenToClient(ih->handle, &info.pt);
+
+ return (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)(LPTVHITTESTINFO)&info);
+}
+
+int iupwinGetColor(const char* value, COLORREF *color)
+{
+ unsigned char r, g, b;
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ *color = RGB(r,g,b);
+ return 1;
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+/* ADDING ITEMS */
+/*****************************************************************************/
+void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* title, int add)
+{
+ TVITEM item, tviPrevItem;
+ TVINSERTSTRUCT tvins;
+ HTREEITEM hPrevItem = winTreeFindNodeFromString(ih, name_id);
+ int kindPrev;
+ winTreeItemData* itemData;
+
+ if (!hPrevItem)
+ return;
+
+ itemData = calloc(1, sizeof(winTreeItemData));
+ itemData->image = -1;
+ itemData->image_expanded = -1;
+ itemData->kind = (unsigned char)kind;
+
+ item.mask = TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
+ item.pszText = (char*)title;
+ item.lParam = (LPARAM)itemData;
+
+ iupwinGetColor(iupAttribGetStr(ih, "FGCOLOR"), &itemData->color);
+
+ if (kind == ITREE_BRANCH)
+ {
+ item.iSelectedImage = item.iImage = (int)ih->data->def_image_collapsed;
+
+ if (ih->data->add_expanded)
+ {
+ item.mask |= TVIF_STATE;
+ item.state = item.stateMask = TVIS_EXPANDED;
+ item.iSelectedImage = item.iImage = (int)ih->data->def_image_expanded;
+ }
+ }
+ else
+ item.iSelectedImage = item.iImage = (int)ih->data->def_image_leaf;
+
+ /* Save the heading level in the node's application-defined data area */
+ tvins.item = item;
+
+ /* get the KIND attribute of node selected */
+ tviPrevItem.hItem = hPrevItem;
+ tviPrevItem.mask = TVIF_PARAM|TVIF_CHILDREN;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&tviPrevItem);
+ kindPrev = ((winTreeItemData*)tviPrevItem.lParam)->kind;
+
+ /* Define the parent and the position to the new node inside
+ the list, using the KIND attribute of node selected */
+ if (kindPrev == ITREE_BRANCH && add)
+ {
+ tvins.hParent = hPrevItem;
+ tvins.hInsertAfter = TVI_FIRST; /* insert the new node after item selected, as first child */
+ }
+ else
+ {
+ tvins.hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hPrevItem);
+ tvins.hInsertAfter = hPrevItem; /* insert the new node after item selected */
+ }
+
+ /* Add the node to the tree-view control */
+ SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
+
+ if (kindPrev == ITREE_BRANCH && tviPrevItem.cChildren==0)
+ {
+ /* this is the first child, redraw to update the '+'/'-' buttons */
+ iupdrvDisplayRedraw(ih);
+ }
+}
+
+static void winTreeAddRootNode(Ihandle* ih)
+{
+ TVITEM item;
+ TVINSERTSTRUCT tvins;
+ HTREEITEM hNewItem;
+ winTreeItemData* itemData;
+
+ itemData = calloc(1, sizeof(winTreeItemData));
+ itemData->image = -1;
+ itemData->image_expanded = -1;
+ itemData->kind = ITREE_BRANCH;
+
+ item.mask = TVIF_PARAM | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ item.state = item.stateMask = TVIS_EXPANDED;
+ item.iSelectedImage = item.iImage = (int)ih->data->def_image_expanded;
+ item.lParam = (LPARAM)itemData;
+
+ iupwinGetColor(iupAttribGetStr(ih, "FGCOLOR"), &itemData->color);
+
+ /* Save the heading level in the node's application-defined data area */
+ tvins.item = item;
+ tvins.hInsertAfter = TVI_FIRST;
+ tvins.hParent = TVI_ROOT;
+
+ /* Add the node to the tree-view control */
+ hNewItem = (HTREEITEM)SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
+
+ /* MarkStart node */
+ iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)hNewItem);
+
+ /* Set the default VALUE */
+ winTreeSetFocusNode(ih, hNewItem);
+}
+
+static int winTreeIsItemExpanded(Ihandle* ih, HTREEITEM hItem)
+{
+ TVITEM item;
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_STATE;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ return (item.state & TVIS_EXPANDED) != 0;
+}
+
+static void winTreeExpandItem(Ihandle* ih, HTREEITEM hItem, int expand)
+{
+ if (expand == -1)
+ expand = !winTreeIsItemExpanded(ih, hItem); /* toggle */
+
+ if (expand)
+ SendMessage(ih->handle, TVM_EXPAND, TVE_EXPAND, (LPARAM)hItem);
+ else
+ SendMessage(ih->handle, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hItem);
+}
+
+/*****************************************************************************/
+/* EXPANDING AND STORING ITEMS */
+/*****************************************************************************/
+static void winTreeExpandTree(Ihandle* ih, HTREEITEM hItem, int expand)
+{
+ HTREEITEM hItemChild;
+ while(hItem != NULL)
+ {
+ hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+
+ /* Check whether we have child items */
+ if (hItemChild)
+ {
+ winTreeExpandItem(ih, hItem, expand);
+
+ /* Recursively traverse child items */
+ winTreeExpandTree(ih, hItemChild, expand);
+ }
+
+ /* Go to next sibling item */
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem);
+ }
+}
+
+/*****************************************************************************/
+/* SELECTING ITEMS */
+/*****************************************************************************/
+
+static int winTreeIsItemSelected(Ihandle* ih, HTREEITEM hItem)
+{
+ return ((SendMessage(ih->handle, TVM_GETITEMSTATE, (WPARAM)hItem, TVIS_SELECTED)) & TVIS_SELECTED)!=0;
+}
+
+static void winTreeSelectItem(Ihandle* ih, HTREEITEM hItem, int select)
+{
+ TV_ITEM item;
+ item.mask = TVIF_STATE | TVIF_HANDLE;
+ item.stateMask = TVIS_SELECTED;
+ item.hItem = hItem;
+
+ if (select == -1)
+ select = !winTreeIsItemSelected(ih, hItem);
+
+ item.state = select ? TVIS_SELECTED : 0;
+
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)&item);
+}
+
+static HTREEITEM winTreeGetFocusNode(Ihandle* ih)
+{
+ return (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CARET, 0);
+}
+
+/* ------------Comment from wxWidgets--------------------
+ Helper function which tricks the standard control into changing the focused
+ item without changing anything else. */
+static void winTreeSetFocusNode(Ihandle* ih, HTREEITEM hItem)
+{
+ HTREEITEM hItemFocus = winTreeGetFocusNode(ih);
+ if (hItem != hItemFocus)
+ {
+ /* remember the selection state of the item */
+ int wasSelected = winTreeIsItemSelected(ih, hItem);
+ int wasFocusSelected = 0;
+
+ if (iupwinIsVista())
+ iupAttribSetStr(ih, "_IUPTREE_ALLOW_CHANGE", (char*)hItem); /* Vista Only */
+ else
+ wasFocusSelected = hItemFocus && winTreeIsItemSelected(ih, hItemFocus);
+
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1");
+
+ if (wasFocusSelected)
+ {
+ /* prevent the tree from unselecting the old focus which it would do by default */
+ SendMessage(ih->handle, TVM_SELECTITEM, TVGN_CARET, (LPARAM)NULL); /* remove the focus */
+ winTreeSelectItem(ih, hItemFocus, 1); /* select again */
+ }
+
+ SendMessage(ih->handle, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItem); /* set focus, selection, and unselect the previous focus */
+
+ if (!wasSelected)
+ winTreeSelectItem(ih, hItem, 0); /* need to clear the selection if was not selected */
+
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL);
+ iupAttribSetStr(ih, "_IUPTREE_ALLOW_CHANGE", NULL);
+ }
+}
+
+typedef struct _winTreeRange{
+ HTREEITEM hItem1, hItem2;
+ char inside, clear;
+}winTreeRange;
+
+static int winTreeSelectRangeFunc(Ihandle* ih, HTREEITEM hItem, winTreeRange* range)
+{
+ int end_range = 0;
+
+ if (range->inside == 0) /* detect the range start */
+ {
+ if (range->hItem1 == hItem) range->inside=1;
+ else if (range->hItem2 == hItem) range->inside=1;
+ }
+ else if (range->inside == 1) /* detect the range end */
+ {
+ if (range->hItem1 == hItem) end_range=1;
+ else if (range->hItem2 == hItem) end_range=1;
+ }
+
+ if (range->inside == 1) /* if inside, select */
+ winTreeSelectItem(ih, hItem, 1);
+ else if (range->clear) /* if outside and clear, unselect */
+ winTreeSelectItem(ih, hItem, 0);
+
+ if (end_range || (range->inside && range->hItem1==range->hItem2))
+ range->inside=-1; /* update after selecting the node */
+
+ return 1;
+}
+
+static void winTreeSelectRange(Ihandle* ih, HTREEITEM hItemFrom, HTREEITEM hItemTo, int clear)
+{
+ winTreeRange range;
+ range.hItem1 = hItemFrom;
+ range.hItem2 = hItemTo;
+ range.inside = 0;
+ range.clear = (char)clear;
+ winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeSelectRangeFunc, &range);
+}
+
+static void winTreeSelectAll(Ihandle* ih)
+{
+ HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+ winTreeSelectRange(ih, hItemRoot, NULL, 0);
+}
+
+static void winTreeClearSelection(Ihandle* ih, HTREEITEM hItemExcept)
+{
+ winTreeSelectRange(ih, hItemExcept, hItemExcept, 1);
+}
+
+static int winTreeInvertSelectFunc(Ihandle* ih, HTREEITEM hItem, void* userdata)
+{
+ winTreeSelectItem(ih, hItem, -1);
+ (void)userdata;
+ return 1;
+}
+
+typedef struct _winTreeSelArray{
+ Iarray* markedArray;
+ char is_handle;
+ int id_control;
+}winTreeSelArray;
+
+static int winTreeSelectedArrayFunc(Ihandle* ih, HTREEITEM hItem, winTreeSelArray* selarray)
+{
+ selarray->id_control++;
+
+ if (winTreeIsItemSelected(ih, hItem))
+ {
+ if (selarray->is_handle)
+ {
+ HTREEITEM* hItemArrayData = (HTREEITEM*)iupArrayInc(selarray->markedArray);
+ int i = iupArrayCount(selarray->markedArray);
+ hItemArrayData[i-1] = hItem;
+ }
+ else
+ {
+ int* intArrayData = (int*)iupArrayInc(selarray->markedArray);
+ int i = iupArrayCount(selarray->markedArray);
+ intArrayData[i-1] = selarray->id_control;
+ }
+ }
+
+ return 1;
+}
+
+static Iarray* winTreeGetSelectedArray(Ihandle* ih)
+{
+ Iarray* markedArray = iupArrayCreate(1, sizeof(HTREEITEM));
+ winTreeSelArray selarray;
+ selarray.markedArray = markedArray;
+ selarray.id_control = -1;
+ selarray.is_handle = 1;
+
+ winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeSelectedArrayFunc, &selarray);
+
+ return markedArray;
+}
+
+static Iarray* winTreeGetSelectedArrayId(Ihandle* ih)
+{
+ Iarray* markedArray = iupArrayCreate(1, sizeof(int));
+ winTreeSelArray selarray;
+ selarray.markedArray = markedArray;
+ selarray.id_control = -1;
+ selarray.is_handle = 0;
+
+ winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeSelectedArrayFunc, &selarray);
+
+ return markedArray;
+}
+
+
+/*****************************************************************************/
+/* COPYING ITEMS (Branches and its children) */
+/*****************************************************************************/
+/* Insert the copied item in a new location. Returns the new item. */
+static HTREEITEM winTreeCopyItem(Ihandle* ih, HTREEITEM hItem, HTREEITEM hParent, HTREEITEM hPosition, int full_copy)
+{
+ TVITEM item;
+ TVINSERTSTRUCT tvins;
+ char* title = iupStrGetMemory(255);
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ item.pszText = title;
+ item.cchTextMax = 255;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+
+ if (full_copy) /* during a full copy the userdata reference is not copied */
+ {
+ /* create a new one */
+ winTreeItemData* itemDataNew = malloc(sizeof(winTreeItemData));
+ memcpy(itemDataNew, (void*)item.lParam, sizeof(winTreeItemData));
+ itemDataNew->userdata = NULL;
+ item.lParam = (LPARAM)itemDataNew;
+ }
+
+ /* Copy everything including user data reference */
+ tvins.item = item;
+ tvins.hInsertAfter = hPosition;
+ tvins.hParent = hParent;
+
+ /* Add the node to the tree-view control */
+ return (HTREEITEM)SendMessage(ih->handle, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
+}
+
+static void winTreeCopyChildren(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hItemDst, int full_copy)
+{
+ HTREEITEM hChildSrc = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItemSrc);
+ HTREEITEM hNewItem = TVI_FIRST;
+ while (hChildSrc != NULL)
+ {
+ hNewItem = winTreeCopyItem(ih, hChildSrc, hItemDst, hNewItem, full_copy); /* Use the same order they where enumerated */
+
+ /* Recursively transfer all the items */
+ winTreeCopyChildren(ih, hChildSrc, hNewItem, full_copy);
+
+ /* Go to next sibling item */
+ hChildSrc = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hChildSrc);
+ }
+}
+
+/* Copies all items in a branch to a new location. Returns the new branch node. */
+static HTREEITEM winTreeCopyNode(Ihandle* ih, HTREEITEM hItemSrc, HTREEITEM hItemDst, int full_copy)
+{
+ HTREEITEM hNewItem, hParent;
+ TVITEM item;
+ winTreeItemData* itemDataDst;
+
+ /* Get DST node attributes */
+ item.hItem = hItemDst;
+ item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemDataDst = (winTreeItemData*)item.lParam;
+
+ if (itemDataDst->kind == ITREE_BRANCH && (item.state & TVIS_EXPANDED))
+ {
+ /* copy as first child of expanded branch */
+ hParent = hItemDst;
+ hItemDst = TVI_FIRST;
+ }
+ else
+ {
+ /* copy as next brother of item or collapsed branch */
+ hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItemDst);
+ }
+
+ hNewItem = winTreeCopyItem(ih, hItemSrc, hParent, hItemDst, full_copy);
+
+ winTreeCopyChildren(ih, hItemSrc, hNewItem, full_copy);
+
+ return hNewItem;
+}
+
+/*****************************************************************************/
+/* MANIPULATING IMAGES */
+/*****************************************************************************/
+static void winTreeUpdateImages(Ihandle* ih, HTREEITEM hItem, int mode)
+{
+ HTREEITEM hItemChild;
+ TVITEM item;
+ winTreeItemData* itemData;
+
+ /* called when one of the default images is changed */
+
+ while(hItem != NULL)
+ {
+ /* Get node attributes */
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ if (itemData->kind == ITREE_BRANCH)
+ {
+ if (item.state & TVIS_EXPANDED)
+ {
+ if (mode == ITREE_UPDATEIMAGE_EXPANDED)
+ {
+ item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ item.iSelectedImage = item.iImage = (itemData->image_expanded!=-1)? itemData->image_expanded: (int)ih->data->def_image_expanded;
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ }
+ }
+ else
+ {
+ if (mode == ITREE_UPDATEIMAGE_COLLAPSED)
+ {
+ item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ item.iSelectedImage = item.iImage = (itemData->image!=-1)? itemData->image: (int)ih->data->def_image_collapsed;
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ }
+ }
+
+ /* Recursively traverse child items */
+ hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+ winTreeUpdateImages(ih, hItemChild, mode);
+ }
+ else
+ {
+ if (mode == ITREE_UPDATEIMAGE_LEAF)
+ {
+ item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ item.iSelectedImage = item.iImage = (itemData->image!=-1)? itemData->image: (int)ih->data->def_image_leaf;
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ }
+ }
+
+ /* Go to next sibling node */
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem);
+ }
+}
+
+static int winTreeGetImageIndex(Ihandle* ih, const char* name)
+{
+ HIMAGELIST image_list;
+ int count, i;
+ Iarray* bmpArray;
+ HBITMAP *bmpArrayData;
+ HBITMAP bmp = iupImageGetImage(name, ih, 0);
+ if (!bmp)
+ return -1;
+
+ /* the array is used to avoi adding the same bitmap twice */
+ bmpArray = (Iarray*)iupAttribGet(ih, "_IUPWIN_BMPARRAY");
+ if (!bmpArray)
+ {
+ /* create the array if does not exist */
+ bmpArray = iupArrayCreate(50, sizeof(HBITMAP));
+ iupAttribSetStr(ih, "_IUPWIN_BMPARRAY", (char*)bmpArray);
+ }
+
+ bmpArrayData = iupArrayGetData(bmpArray);
+
+ image_list = (HIMAGELIST)SendMessage(ih->handle, TVM_GETIMAGELIST, TVSIL_NORMAL, 0);
+ if (!image_list)
+ {
+ int width, height;
+
+ /* must use this info, since image can be a driver image loaded from resources */
+ iupdrvImageGetInfo(bmp, &width, &height, NULL);
+
+ /* create the image list if does not exist */
+ image_list = ImageList_Create(width, height, ILC_COLOR32, 0, 50);
+ SendMessage(ih->handle, TVM_SETIMAGELIST, 0, (LPARAM)image_list);
+ }
+
+ /* check if that bitmap is already added to the list,
+ but we can not compare with the actual bitmap at the list since it is a copy */
+ count = ImageList_GetImageCount(image_list);
+ for (i = 0; i < count; i++)
+ {
+ if (bmpArrayData[i] == bmp)
+ return i;
+ }
+
+ bmpArrayData = iupArrayInc(bmpArray);
+ bmpArrayData[i] = bmp;
+ return ImageList_Add(image_list, bmp, NULL); /* the bmp is duplicated at the list */
+}
+
+
+/*****************************************************************************/
+/* CALLBACKS */
+/*****************************************************************************/
+
+static int winTreeCallBranchLeafCb(Ihandle* ih, HTREEITEM hItem)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+
+ /* Get Children: branch or leaf */
+ item.mask = TVIF_HANDLE|TVIF_PARAM|TVIF_STATE;
+ item.hItem = hItem;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ if (itemData->kind == ITREE_BRANCH)
+ {
+ if (item.state & TVIS_EXPANDED)
+ {
+ IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB");
+ if (cbBranchClose)
+ return cbBranchClose(ih, winTreeGetNodeId(ih, hItem));
+ }
+ else
+ {
+ IFni cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB");
+ if (cbBranchOpen)
+ return cbBranchOpen(ih, winTreeGetNodeId(ih, hItem));
+ }
+ }
+ else
+ {
+ IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB");
+ if (cbExecuteLeaf)
+ return cbExecuteLeaf(ih, winTreeGetNodeId(ih, hItem));
+ }
+
+ return IUP_DEFAULT;
+}
+
+static void winTreeCallMultiSelectionCb(Ihandle* ih)
+{
+ IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTISELECTION_CB");
+ if(cbMulti)
+ {
+ Iarray* markedArray = winTreeGetSelectedArrayId(ih);
+ int* id_hitem = (int*)iupArrayGetData(markedArray);
+
+ cbMulti(ih, id_hitem, iupArrayCount(markedArray));
+
+ iupArrayDestroy(markedArray);
+ }
+ else
+ {
+ IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB");
+ if (cbSelec)
+ {
+ Iarray* markedArray = winTreeGetSelectedArrayId(ih);
+ int* id_hitem = (int*)iupArrayGetData(markedArray);
+ int i, count = iupArrayCount(markedArray);
+
+ for (i=0; i<count; i++)
+ cbSelec(ih, id_hitem[i], 1);
+
+ iupArrayDestroy(markedArray);
+ }
+ }
+}
+
+static void winTreeCallSelectionCb(Ihandle* ih, int status, HTREEITEM hItem)
+{
+ IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB");
+ if (cbSelec)
+ {
+ if (ih->data->mark_mode == ITREE_MARK_MULTIPLE && IupGetCallback(ih,"MULTISELECTION_CB"))
+ {
+ if ((GetKeyState(VK_SHIFT) & 0x8000))
+ return;
+ }
+
+ if (iupAttribGet(ih, "_IUPTREE_IGNORE_SELECTION_CB"))
+ return;
+
+ cbSelec(ih, winTreeGetNodeId(ih, hItem), status);
+ }
+}
+
+static int winTreeCallDragDropCb(Ihandle* ih, HTREEITEM hItemDrag, HTREEITEM hItemDrop, int *is_ctrl)
+{
+ IFniiii cbDragDrop = (IFniiii)IupGetCallback(ih, "DRAGDROP_CB");
+ int is_shift = 0;
+ if ((GetKeyState(VK_SHIFT) & 0x8000))
+ is_shift = 1;
+ if ((GetKeyState(VK_CONTROL) & 0x8000))
+ *is_ctrl = 1;
+ else
+ *is_ctrl = 0;
+
+ if (cbDragDrop)
+ {
+ int drag_id = winTreeGetNodeId(ih, hItemDrag);
+ int drop_id = winTreeGetNodeId(ih, hItemDrop);
+ return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl);
+ }
+
+ return IUP_CONTINUE; /* allow to move by default if callback not defined */
+}
+
+
+/*****************************************************************************/
+/* GET AND SET ATTRIBUTES */
+/*****************************************************************************/
+
+
+static int winTreeSetImageBranchExpandedAttrib(Ihandle* ih, const char* value)
+{
+ ih->data->def_image_expanded = (void*)winTreeGetImageIndex(ih, value);
+
+ /* Update all images, starting at root node */
+ winTreeUpdateImages(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0), ITREE_UPDATEIMAGE_EXPANDED);
+
+ return 1;
+}
+
+static int winTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value)
+{
+ ih->data->def_image_collapsed = (void*)winTreeGetImageIndex(ih, value);
+
+ /* Update all images, starting at root node */
+ winTreeUpdateImages(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0), ITREE_UPDATEIMAGE_COLLAPSED);
+
+ return 1;
+}
+
+static int winTreeSetImageLeafAttrib(Ihandle* ih, const char* value)
+{
+ ih->data->def_image_leaf = (void*)winTreeGetImageIndex(ih, value);
+
+ /* Update all images, starting at root node */
+ winTreeUpdateImages(ih, (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0), ITREE_UPDATEIMAGE_LEAF);
+
+ return 1;
+}
+
+static int winTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return 0;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+ itemData->image_expanded = (short)winTreeGetImageIndex(ih, value);
+
+ if (itemData->kind == ITREE_BRANCH && item.state & TVIS_EXPANDED)
+ {
+ if (itemData->image_expanded == -1)
+ item.iSelectedImage = item.iImage = (int)ih->data->def_image_expanded;
+ else
+ item.iSelectedImage = item.iImage = itemData->image_expanded;
+ item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(const LPTVITEM)&item);
+ }
+
+ return 1;
+}
+
+static int winTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return 0;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+ itemData->image = (short)winTreeGetImageIndex(ih, value);
+
+ if (itemData->kind == ITREE_BRANCH)
+ {
+ if (!(item.state & TVIS_EXPANDED))
+ {
+ if (itemData->image == -1)
+ item.iSelectedImage = item.iImage = (int)ih->data->def_image_collapsed;
+ else
+ item.iSelectedImage = item.iImage = itemData->image;
+
+ item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(const LPTVITEM)&item);
+ }
+ }
+ else
+ {
+ if (itemData->image == -1)
+ item.iSelectedImage = item.iImage = (int)ih->data->def_image_leaf;
+ else
+ item.iSelectedImage = item.iImage = itemData->image;
+
+ item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(const LPTVITEM)&item);
+ }
+
+ return 1;
+}
+
+static int winTreeSetTopItemAttrib(Ihandle* ih, const char* value)
+{
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, value);
+ if (hItem)
+ SendMessage(ih->handle, TVM_ENSUREVISIBLE, 0, (LPARAM)hItem);
+ return 0;
+}
+
+static int winTreeSetSpacingAttrib(Ihandle* ih, const char* value)
+{
+ if (!iupStrToInt(value, &ih->data->spacing))
+ ih->data->spacing = 1;
+
+ if(ih->data->spacing < 1)
+ ih->data->spacing = 1;
+
+ if (ih->handle)
+ {
+ int old_spacing = iupAttribGetInt(ih, "_IUPWIN_OLDSPACING");
+ int height = SendMessage(ih->handle, TVM_GETITEMHEIGHT, 0, 0);
+ height -= 2*old_spacing;
+ height += 2*ih->data->spacing;
+ SendMessage(ih->handle, TVM_SETITEMHEIGHT, height, 0);
+ iupAttribSetInt(ih, "_IUPWIN_OLDSPACING", ih->data->spacing);
+ return 0;
+ }
+ else
+ return 1; /* store until not mapped, when mapped will be set again */
+}
+
+static int winTreeSetExpandAllAttrib(Ihandle* ih, const char* value)
+{
+ HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+ HTREEITEM hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItemRoot); /* skip the root node that is always expanded */
+ int expand = iupStrBoolean(value);
+ winTreeExpandTree(ih, hItem, expand);
+ return 0;
+}
+
+static int winTreeSetBgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ COLORREF cr = RGB(r,g,b);
+ SendMessage(ih->handle, TVM_SETBKCOLOR, 0, (LPARAM)cr);
+
+ /* update internal image cache */
+ iupTreeUpdateImages(ih);
+ }
+ return 0;
+}
+
+static char* winTreeGetBgColorAttrib(Ihandle* ih)
+{
+ COLORREF cr = (COLORREF)SendMessage(ih->handle, TVM_GETBKCOLOR, 0, 0);
+ if (cr == (COLORREF)-1)
+ return IupGetGlobal("TXTBGCOLOR");
+ else
+ {
+ char* str = iupStrGetMemory(20);
+ sprintf(str, "%d %d %d", (int)GetRValue(cr), (int)GetGValue(cr), (int)GetBValue(cr));
+ return str;
+ }
+}
+
+static void winTreeSetRenameCaretPos(HWND hEdit, const char* value)
+{
+ int pos = 1;
+
+ if (iupStrToInt(value, &pos))
+ {
+ if (pos < 1) pos = 1;
+ pos--; /* IUP starts at 1 */
+
+ SendMessage(hEdit, EM_SETSEL, (WPARAM)pos, (LPARAM)pos);
+ }
+}
+
+static void winTreeSetRenameSelectionPos(HWND hEdit, const char* value)
+{
+ int start = 1, end = 1;
+
+ if (iupStrToIntInt(value, &start, &end, ':') != 2)
+ return;
+
+ if(start < 1 || end < 1)
+ return;
+
+ start--; /* IUP starts at 1 */
+ end--;
+
+ SendMessage(hEdit, EM_SETSEL, (WPARAM)start, (LPARAM)end);
+}
+
+static char* winTreeGetTitle(Ihandle* ih, HTREEITEM hItem)
+{
+ TVITEM item;
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_TEXT;
+ item.pszText = iupStrGetMemory(255);
+ item.cchTextMax = 255;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ return item.pszText;
+}
+
+static char* winTreeGetTitleAttrib(Ihandle* ih, const char* name_id)
+{
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return NULL;
+ return winTreeGetTitle(ih, hItem);
+}
+
+static int winTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ TVITEM item;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return 0;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_TEXT;
+ item.pszText = (char*)value;
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(const LPTVITEM)&item);
+ return 0;
+}
+
+static char* winTreeGetFindUserDataAttrib(Ihandle* ih, const char* name_id)
+{
+ int id;
+ char* str = (char*)(name_id+1); /* skip ':' */
+ void* userdata = NULL;
+ if (sscanf(str, "%p", &userdata)!=1)
+ return NULL;
+ id = winTreeGetUserDataId(ih, userdata);
+ if (id == -1)
+ return NULL;
+ str = iupStrGetMemory(16);
+ sprintf(str, "%d", id);
+ return str;
+}
+
+static char* winTreeGetUserDataAttrib(Ihandle* ih, const char* name_id)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return NULL;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ return itemData->userdata;
+}
+
+static int winTreeSetUserDataAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return 0;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ itemData->userdata = (void*)value;
+
+ return 0;
+}
+
+static char* winTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return NULL;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ return iupwinFindHFont(itemData->hFont);
+}
+
+static int winTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return 0;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ if (value)
+ itemData->hFont = iupwinGetHFont(value);
+ else
+ itemData->hFont = NULL;
+
+ iupdrvDisplayUpdate(ih);
+
+ return 0;
+}
+
+static char* winTreeGetIndentationAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(255);
+ int indent = (int)SendMessage(ih->handle, TVM_GETINDENT, 0, 0);
+ sprintf(str, "%d", indent);
+ return str;
+}
+
+static int winTreeSetIndentationAttrib(Ihandle* ih, const char* value)
+{
+ int indent;
+ if (iupStrToInt(value, &indent))
+ SendMessage(ih->handle, TVM_SETINDENT, (WPARAM)indent, 0);
+ return 0;
+}
+
+static char* winTreeGetStateAttrib(Ihandle* ih, const char* name_id)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return NULL;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE|TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ if (itemData->kind == ITREE_BRANCH)
+ {
+ if (winTreeIsItemExpanded(ih, hItem))
+ return "EXPANDED";
+ else
+ return "COLLAPSED";
+ }
+
+ return NULL;
+}
+
+static int winTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return 0;
+
+ winTreeExpandItem(ih, hItem, iupStrEqualNoCase(value, "EXPANDED"));
+ return 0;
+}
+
+static char* winTreeGetDepthAttrib(Ihandle* ih, const char* name_id)
+{
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+ int depth = 0;
+ char* str;
+
+ if (!hItem)
+ return NULL;
+
+ while((hItemRoot != hItem) && (hItem != NULL))
+ {
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem);
+ depth++;
+ }
+
+ str = iupStrGetMemory(10);
+ sprintf(str, "%d", depth);
+ return str;
+}
+
+static int winTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ HTREEITEM hItemDst, hParent, hItemSrc;
+
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ hItemSrc = winTreeFindNodeFromString(ih, name_id);
+ if (!hItemSrc)
+ return 0;
+ hItemDst = winTreeFindNodeFromString(ih, value);
+ if (!hItemDst)
+ return 0;
+
+ /* If Drag item is an ancestor of Drop item then return */
+ hParent = hItemDst;
+ while(hParent)
+ {
+ hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hParent);
+ if (hParent == hItemSrc)
+ return 0;
+ }
+
+ /* Copying the node and its children to the new position */
+ winTreeCopyNode(ih, hItemSrc, hItemDst, 0); /* not a full copy, preserve user data */
+
+ /* do not delete the user data, we copy the references in CopyNode */
+ SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemSrc);
+
+ return 0;
+}
+
+static int winTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ HTREEITEM hItemDst, hParent, hItemSrc;
+
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ hItemSrc = winTreeFindNodeFromString(ih, name_id);
+ if (!hItemSrc)
+ return 0;
+ hItemDst = winTreeFindNodeFromString(ih, value);
+ if (!hItemDst)
+ return 0;
+
+ /* If Drag item is an ancestor of Drop item then return */
+ hParent = hItemDst;
+ while(hParent)
+ {
+ hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hParent);
+ if (hParent == hItemSrc)
+ return 0;
+ }
+
+ /* Copying the node and its children to the new position */
+ winTreeCopyNode(ih, hItemSrc, hItemDst, 1);
+
+ return 0;
+}
+
+static char* winTreeGetColorAttrib(Ihandle* ih, const char* name_id)
+{
+ unsigned char r, g, b;
+ char* str;
+ TVITEM item;
+ winTreeItemData* itemData;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return NULL;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ r = GetRValue(itemData->color);
+ g = GetGValue(itemData->color);
+ b = GetBValue(itemData->color);
+
+ str = iupStrGetMemory(12);
+ sprintf(str, "%d %d %d", r, g, b);
+ return str;
+}
+
+static int winTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ unsigned char r, g, b;
+ TVITEM item;
+ winTreeItemData* itemData;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return 0;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ itemData->color = RGB(r,g,b);
+ iupdrvDisplayUpdate(ih);
+ }
+
+ return 0;
+}
+
+static int winTreeSetFgColorAttrib(Ihandle* ih, const char* value)
+{
+ unsigned char r, g, b;
+
+ if (iupStrToRGB(value, &r, &g, &b))
+ {
+ COLORREF color = RGB(r,g,b);
+ SendMessage(ih->handle, TVM_SETTEXTCOLOR, 0, (LPARAM)color);
+ }
+ else
+ SendMessage(ih->handle, TVM_SETTEXTCOLOR, 0, (LPARAM)CLR_DEFAULT);
+
+ return 0;
+}
+
+static char* winTreeGetChildCountAttrib(Ihandle* ih, const char* name_id)
+{
+ int count;
+ char* str;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return NULL;
+
+ count = 0;
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+ while(hItem != NULL)
+ {
+ count++;
+
+ /* Go to next sibling item */
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem);
+ }
+
+ str = iupStrGetMemory(10);
+ sprintf(str, "%d", count);
+ return str;
+}
+
+static char* winTreeGetCountAttrib(Ihandle* ih)
+{
+ char* str = iupStrGetMemory(10);
+ sprintf(str, "%d", (int)SendMessage(ih->handle, TVM_GETCOUNT, 0, 0));
+ return str;
+}
+
+static char* winTreeGetKindAttrib(Ihandle* ih, const char* name_id)
+{
+ TVITEM item;
+ winTreeItemData* itemData;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return NULL;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE|TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ if(itemData->kind == ITREE_BRANCH)
+ return "BRANCH";
+ else
+ return "LEAF";
+}
+
+static char* winTreeGetParentAttrib(Ihandle* ih, const char* name_id)
+{
+ char* str;
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return NULL;
+
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem);
+ if (!hItem)
+ return NULL;
+
+ str = iupStrGetMemory(10);
+ sprintf(str, "%d", winTreeGetNodeId(ih, hItem));
+ return str;
+}
+
+static void winTreeDelNodeData(Ihandle* ih, HTREEITEM hItem)
+{
+ TVITEM item;
+ HTREEITEM hChildItem;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE|TVIF_PARAM;
+ if (SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item))
+ {
+ winTreeItemData* itemData = (winTreeItemData*)item.lParam;
+ if (itemData)
+ {
+ IFnis cb = (IFnis)IupGetCallback(ih, "NODEREMOVED_CB");
+ if (cb) cb(ih, winTreeGetNodeId(ih, hItem), (char*)itemData->userdata);
+ free(itemData);
+ item.lParam = (LPARAM)NULL;
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ }
+ }
+
+ hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+ while (hChildItem)
+ {
+ winTreeDelNodeData(ih, hChildItem);
+ hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hChildItem);
+ }
+}
+
+static int winTreeSetDelNodeAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ if (!ih->handle) /* do not store the action before map */
+ return 0;
+ if(iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */
+ {
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+
+ /* the root node can't be deleted */
+ if(!hItem || hItem == hItemRoot)
+ return 0;
+
+ /* deleting the specified node (and it's children) */
+ winTreeDelNodeData(ih, hItem);
+ SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItem);
+
+ return 0;
+ }
+ else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */
+ {
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ HTREEITEM hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+
+ if(!hItem)
+ return 0;
+
+ /* deleting the selected node's children */
+ while (hChildItem)
+ {
+ winTreeDelNodeData(ih, hChildItem);
+ SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hChildItem);
+ hChildItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);
+ }
+
+ return 0;
+ }
+ else if(iupStrEqualNoCase(value, "MARKED"))
+ {
+ int i, count;
+ Iarray* markedArray;
+ HTREEITEM* hItemArrayData;
+ HTREEITEM hItemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+
+ /* Delete the array of marked nodes */
+ markedArray = winTreeGetSelectedArray(ih);
+ hItemArrayData = (HTREEITEM*)iupArrayGetData(markedArray);
+ count = iupArrayCount(markedArray);
+
+ for(i = 0; i < count; i++)
+ {
+ if (hItemArrayData[i] != hItemRoot) /* the root node can't be deleted */
+ {
+ winTreeDelNodeData(ih, hItemArrayData[i]);
+ SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemArrayData[i]);
+ }
+ }
+
+ iupArrayDestroy(markedArray);
+
+ return 0;
+ }
+
+ return 0;
+}
+
+static int winTreeSetRenameAttrib(Ihandle* ih, const char* value)
+{
+ HTREEITEM hItemFocus = winTreeGetFocusNode(ih);
+ if (ih->data->show_rename)
+ {
+ IFni cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB");
+ if (cbShowRename)
+ cbShowRename(ih, winTreeGetNodeId(ih, hItemFocus));
+
+ SetFocus(ih->handle); /* the tree must have focus to activate the edit */
+ SendMessage(ih->handle, TVM_EDITLABEL, 0, (LPARAM)hItemFocus);
+ }
+ else
+ {
+ IFnis cbRenameNode = (IFnis)IupGetCallback(ih, "RENAMENODE_CB");
+ if (cbRenameNode)
+ cbRenameNode(ih, winTreeGetNodeId(ih, hItemFocus), winTreeGetTitle(ih, hItemFocus));
+ }
+
+ (void)value;
+ return 0;
+}
+
+static char* winTreeGetMarkedAttrib(Ihandle* ih, const char* name_id)
+{
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return NULL;
+
+ if (winTreeIsItemSelected(ih, hItem))
+ return "YES";
+ else
+ return "NO";
+}
+
+static int winTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value)
+{
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return 0;
+
+ winTreeSelectItem(ih, hItem, iupStrBoolean(value));
+ return 0;
+}
+
+static int winTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id)
+{
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, name_id);
+ if (!hItem)
+ return 0;
+
+ iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)hItem);
+
+ return 1;
+}
+
+static char* winTreeGetValueAttrib(Ihandle* ih)
+{
+ char* str;
+ HTREEITEM hItemFocus = winTreeGetFocusNode(ih);
+ if (!hItemFocus)
+ return "0"; /* default VALUE is root */
+
+ str = iupStrGetMemory(16);
+ sprintf(str, "%d", winTreeGetNodeId(ih, hItemFocus));
+ return str;
+}
+
+static int winTreeSetMarkAttrib(Ihandle* ih, const char* value)
+{
+ if (ih->data->mark_mode==ITREE_MARK_SINGLE)
+ return 0;
+
+ if(iupStrEqualNoCase(value, "BLOCK"))
+ {
+ HTREEITEM hItemFocus = winTreeGetFocusNode(ih);
+ winTreeSelectRange(ih, (HTREEITEM)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"), hItemFocus, 0);
+ }
+ else if(iupStrEqualNoCase(value, "CLEARALL"))
+ winTreeClearSelection(ih, NULL);
+ else if(iupStrEqualNoCase(value, "MARKALL"))
+ winTreeSelectAll(ih);
+ else if(iupStrEqualNoCase(value, "INVERTALL")) /* INVERTALL *MUST* appear before INVERT, or else INVERTALL will never be called. */
+ winTreeForEach(ih, NULL, (winTreeNodeFunc)winTreeInvertSelectFunc, NULL);
+ else if(iupStrEqualPartial(value, "INVERT")) /* iupStrEqualPartial allows the use of "INVERTid" form */
+ {
+ HTREEITEM hItem = winTreeFindNodeFromString(ih, &value[strlen("INVERT")]);
+ if (!hItem)
+ return 0;
+
+ winTreeSelectItem(ih, hItem, -1); /* toggle */
+ }
+ else
+ {
+ HTREEITEM hItem1, hItem2;
+
+ char str1[50], str2[50];
+ if (iupStrToStrStr(value, str1, str2, '-')!=2)
+ return 0;
+
+ hItem1 = winTreeFindNodeFromString(ih, str1);
+ if (!hItem1)
+ return 0;
+ hItem2 = winTreeFindNodeFromString(ih, str2);
+ if (!hItem2)
+ return 0;
+
+ winTreeSelectRange(ih, hItem1, hItem2, 0);
+ }
+
+ return 1;
+}
+
+static int winTreeSetValueAttrib(Ihandle* ih, const char* value)
+{
+ HTREEITEM hItem = NULL;
+ HTREEITEM hItemFocus;
+
+ if (winTreeSetMarkAttrib(ih, value))
+ return 0;
+
+ hItemFocus = winTreeGetFocusNode(ih);
+
+ if(iupStrEqualNoCase(value, "ROOT"))
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+ else if(iupStrEqualNoCase(value, "LAST"))
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_LASTVISIBLE, 0);
+ else if(iupStrEqualNoCase(value, "PGUP"))
+ {
+ int i;
+ HTREEITEM hItemPrev = hItemFocus;
+ HTREEITEM hItemNext = hItemFocus;
+ for(i = 0; i < 10; i++)
+ {
+ hItemNext = hItemPrev;
+ hItemPrev = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItemPrev);
+ if(hItemPrev == NULL)
+ {
+ hItemPrev = hItemNext;
+ break;
+ }
+ }
+
+ hItem = hItemPrev;
+ }
+ else if(iupStrEqualNoCase(value, "PGDN"))
+ {
+ int i;
+ HTREEITEM hItemPrev = hItemFocus;
+ HTREEITEM hItemNext = hItemFocus;
+
+ for(i = 0; i < 10; i++)
+ {
+ hItemPrev = hItemNext;
+ hItemNext = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItemNext);
+ if(hItemNext == NULL)
+ {
+ hItemNext = hItemPrev;
+ break;
+ }
+ }
+
+ hItem = hItemNext;
+ }
+ else if(iupStrEqualNoCase(value, "NEXT"))
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItemFocus);
+ else if(iupStrEqualNoCase(value, "PREVIOUS"))
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItemFocus);
+ else
+ hItem = winTreeFindNodeFromString(ih, value);
+
+ if (hItem)
+ {
+ if (ih->data->mark_mode==ITREE_MARK_SINGLE)
+ {
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1");
+ winTreeSelectItem(ih, hItem, 1);
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL);
+ }
+ winTreeSetFocusNode(ih, hItem);
+ }
+
+ return 0;
+}
+
+void iupdrvTreeUpdateMarkMode(Ihandle *ih)
+{
+ /* does nothing, must handle single and multiple selection manually in Windows */
+ (void)ih;
+}
+
+/*********************************************************************************************************/
+
+
+static int winTreeEditProc(Ihandle* ih, HWND cbedit, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ switch (msg)
+ {
+ case WM_GETDLGCODE:
+ {
+ MSG* pMsg = (MSG*)lp;
+
+ if (pMsg && (pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN))
+ {
+ if (pMsg->wParam == VK_ESCAPE || pMsg->wParam == VK_RETURN)
+ {
+ /* these keys are not processed if the return code is not this */
+ *result = DLGC_WANTALLKEYS;
+ return 1;
+ }
+ }
+ }
+ }
+
+ (void)wp;
+ (void)cbedit;
+ (void)ih;
+ return 0;
+}
+
+static LRESULT CALLBACK winTreeEditWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ int ret = 0;
+ LRESULT result = 0;
+ WNDPROC oldProc;
+ Ihandle *ih;
+
+ ih = iupwinHandleGet(hwnd);
+ if (!ih)
+ return DefWindowProc(hwnd, msg, wp, lp); /* should never happen */
+
+ /* retrieve the control previous procedure for subclassing */
+ oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_EDITOLDPROC_CB");
+
+ ret = winTreeEditProc(ih, hwnd, msg, wp, lp, &result);
+
+ if (ret)
+ return result;
+ else
+ return CallWindowProc(oldProc, hwnd, msg, wp, lp);
+}
+
+static void winTreeDrag(Ihandle* ih, int x, int y)
+{
+ HTREEITEM hItemDrop;
+
+ HIMAGELIST dragImageList = (HIMAGELIST)iupAttribGet(ih, "_IUPTREE_DRAGIMAGELIST");
+ if (dragImageList)
+ {
+ POINT pnt;
+ pnt.x = x;
+ pnt.y = y;
+ GetCursorPos(&pnt);
+ ClientToScreen(GetDesktopWindow(), &pnt) ;
+ ImageList_DragMove(pnt.x, pnt.y);
+ }
+
+ if ((hItemDrop = winTreeFindNodePointed(ih)) != NULL)
+ {
+ if(dragImageList)
+ ImageList_DragShowNolock(FALSE);
+
+ SendMessage(ih->handle, TVM_SELECTITEM, TVGN_DROPHILITE, (LPARAM)hItemDrop);
+
+ /* store the drop item to be executed */
+ iupAttribSetStr(ih, "_IUPTREE_DROPITEM", (char*)hItemDrop);
+
+ if(dragImageList)
+ ImageList_DragShowNolock(TRUE);
+ }
+}
+
+static void winTreeDrop(Ihandle* ih)
+{
+ HTREEITEM hItemDrag = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_DRAGITEM");
+ HTREEITEM hItemDrop = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_DROPITEM");
+ HIMAGELIST dragImageList = (HIMAGELIST)iupAttribGet(ih, "_IUPTREE_DRAGIMAGELIST");
+ HTREEITEM hParent;
+ int is_ctrl;
+
+ if (dragImageList)
+ {
+ ImageList_DragLeave(ih->handle);
+ ImageList_EndDrag();
+ ImageList_Destroy(dragImageList);
+ iupAttribSetStr(ih, "_IUPTREE_DRAGIMAGELIST", NULL);
+ }
+
+ ReleaseCapture();
+ ShowCursor(TRUE);
+
+ /* Remove drop target highlighting */
+ SendMessage(ih->handle, TVM_SELECTITEM, TVGN_DROPHILITE, (LPARAM)NULL);
+
+ iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", NULL);
+ iupAttribSetStr(ih, "_IUPTREE_DROPITEM", NULL);
+
+ if (!hItemDrop || hItemDrag == hItemDrop)
+ return;
+
+ /* If Drag item is an ancestor of Drop item then return */
+ hParent = hItemDrop;
+ while(hParent)
+ {
+ hParent = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hParent);
+ if (hParent == hItemDrag)
+ return;
+ }
+
+ if (winTreeCallDragDropCb(ih, hItemDrag, hItemDrop, &is_ctrl) == IUP_CONTINUE)
+ {
+ /* Copy the dragged item to the new position. */
+ HTREEITEM hItemNew = winTreeCopyNode(ih, hItemDrag, hItemDrop, is_ctrl);
+
+ if (!is_ctrl)
+ {
+ /* do not delete the user data, we copy the references in CopyNode */
+ SendMessage(ih->handle, TVM_DELETEITEM, 0, (LPARAM)hItemDrag);
+ }
+
+ SendMessage(ih->handle, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItemNew); /* set focus and selection */
+ }
+}
+
+static void winTreeExtendSelect(Ihandle* ih, int x, int y)
+{
+ HTREEITEM hItemFirstSel;
+ TVHITTESTINFO info;
+ HTREEITEM hItem;
+ info.pt.x = x;
+ info.pt.y = y;
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)&info);
+
+ if (!(info.flags & TVHT_ONITEM) || !hItem)
+ return;
+
+ hItemFirstSel = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_FIRSTSELITEM");
+ if (hItemFirstSel)
+ {
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1");
+ winTreeSelectRange(ih, hItemFirstSel, hItem, 1);
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL);
+
+ iupAttribSetStr(ih, "_IUPTREE_LASTSELITEM", (char*)hItem);
+ winTreeSetFocusNode(ih, hItem);
+ }
+}
+
+static int winTreeMouseMultiSelect(Ihandle* ih, int x, int y)
+{
+ TVHITTESTINFO info;
+ HTREEITEM hItem;
+ info.pt.x = x;
+ info.pt.y = y;
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)&info);
+
+ if (!(info.flags & TVHT_ONITEM) || !hItem)
+ return 0;
+
+ if (GetKeyState(VK_CONTROL) & 0x8000) /* Control key is down */
+ {
+ /* Toggle selection state */
+ winTreeSelectItem(ih, hItem, -1);
+ iupAttribSetStr(ih, "_IUPTREE_FIRSTSELITEM", (char*)hItem);
+
+ winTreeCallSelectionCb(ih, winTreeIsItemSelected(ih, hItem), hItem);
+ winTreeSetFocusNode(ih, hItem);
+
+ return 1;
+ }
+ else if (GetKeyState(VK_SHIFT) & 0x8000) /* Shift key is down */
+ {
+ HTREEITEM hItemFirstSel = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_FIRSTSELITEM");
+ if (hItemFirstSel)
+ {
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1");
+ winTreeSelectRange(ih, hItemFirstSel, hItem, 1);
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL);
+
+ winTreeCallMultiSelectionCb(ih);
+ winTreeSetFocusNode(ih, hItem);
+ return 1;
+ }
+ }
+
+ /* simple click */
+ winTreeClearSelection(ih, hItem);
+ iupAttribSetStr(ih, "_IUPTREE_FIRSTSELITEM", (char*)hItem);
+ iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", "1");
+
+ return 0;
+}
+
+static int winTreeProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ switch (msg)
+ {
+ case WM_CTLCOLOREDIT:
+ {
+ HWND hEdit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX");
+ if (hEdit)
+ {
+ winTreeItemData* itemData = (winTreeItemData*)iupAttribGet(ih, "_IUPWIN_EDIT_DATA");
+ HDC hDC = (HDC)wp;
+ COLORREF cr;
+
+ SetTextColor(hDC, itemData->color);
+
+ cr = (COLORREF)SendMessage(ih->handle, TVM_GETBKCOLOR, 0, 0);
+ SetBkColor(hDC, cr);
+ SetDCBrushColor(hDC, cr);
+ *result = (LRESULT)GetStockObject(DC_BRUSH);
+ return 1;
+ }
+
+ break;
+ }
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ {
+ /* ------------Comment from wxWidgets--------------------
+ the tree control greys out the selected item when it loses focus and
+ paints it as selected again when it regains it, but it won't do it
+ for the other items itself - help it */
+ if (ih->data->mark_mode == ITREE_MARK_MULTIPLE)
+ {
+ HTREEITEM hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_FIRSTVISIBLE, 0);
+ RECT rect;
+
+ while(hItemChild != NULL)
+ {
+ *(HTREEITEM*)&rect = hItemChild;
+ if (SendMessage(ih->handle, TVM_GETITEMRECT, TRUE, (LPARAM)&rect))
+ InvalidateRect(ih->handle, &rect, FALSE);
+
+ /* Go to next visible item */
+ hItemChild = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItemChild);
+ }
+ }
+ break;
+ }
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ {
+ if (iupwinBaseProc(ih, msg, wp, lp, result)==1)
+ return 1;
+
+ if (wp == VK_RETURN)
+ {
+ HTREEITEM hItemFocus = winTreeGetFocusNode(ih);
+ if (winTreeCallBranchLeafCb(ih, hItemFocus) != IUP_IGNORE)
+ winTreeExpandItem(ih, hItemFocus, -1);
+
+ *result = 0;
+ return 1;
+ }
+ else if (wp == VK_F2)
+ {
+ winTreeSetRenameAttrib(ih, NULL);
+ *result = 0;
+ return 1;
+ }
+ else if (wp == VK_SPACE)
+ {
+ if (GetKeyState(VK_CONTROL) & 0x8000)
+ {
+ HTREEITEM hItemFocus = winTreeGetFocusNode(ih);
+ /* Toggle selection state */
+ winTreeSelectItem(ih, hItemFocus, -1);
+ }
+ }
+ else if (wp == VK_UP || wp == VK_DOWN)
+ {
+ HTREEITEM hItemFocus = winTreeGetFocusNode(ih);
+ if (wp == VK_UP)
+ hItemFocus = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItemFocus);
+ else
+ hItemFocus = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItemFocus);
+ if (!hItemFocus)
+ return 0;
+
+ if (GetKeyState(VK_CONTROL) & 0x8000)
+ {
+ /* Only move focus */
+ winTreeSetFocusNode(ih, hItemFocus);
+
+ *result = 0;
+ return 1;
+ }
+ else if (GetKeyState(VK_SHIFT) & 0x8000)
+ {
+ HTREEITEM hItemFirstSel = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_FIRSTSELITEM");
+ if (hItemFirstSel)
+ {
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", "1");
+ winTreeSelectRange(ih, hItemFirstSel, hItemFocus, 1);
+ iupAttribSetStr(ih, "_IUPTREE_IGNORE_SELECTION_CB", NULL);
+
+ winTreeCallMultiSelectionCb(ih);
+ winTreeSetFocusNode(ih, hItemFocus);
+
+ *result = 0;
+ return 1;
+ }
+ }
+
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE)
+ {
+ iupAttribSetStr(ih, "_IUPTREE_FIRSTSELITEM", (char*)hItemFocus);
+ winTreeClearSelection(ih, NULL);
+ /* normal processing will select the focus item */
+ }
+ }
+
+ return 0;
+ }
+ case WM_LBUTTONDOWN:
+ if (iupwinButtonDown(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE)
+ {
+ /* must set focus on left button down or the tree won't show its focus */
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ SetFocus(ih->handle);
+
+ if (winTreeMouseMultiSelect(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp)))
+ {
+ *result = 0; /* abort the normal processing if we process multiple selection */
+ return 1;
+ }
+ }
+ break;
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ if (iupwinButtonDown(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+ break;
+ case WM_MOUSEMOVE:
+ if (ih->data->show_dragdrop && (HTREEITEM)iupAttribGet(ih, "_IUPTREE_DRAGITEM") != NULL)
+ winTreeDrag(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp));
+ else if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT"))
+ winTreeExtendSelect(ih, (int)(short)LOWORD(lp), (int)(short)HIWORD(lp));
+
+ iupwinMouseMove(ih, msg, wp, lp);
+ break;
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ if (iupwinButtonUp(ih, msg, wp, lp)==-1)
+ {
+ *result = 0;
+ return 1;
+ }
+
+ if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT"))
+ {
+ iupAttribSetStr(ih, "_IUPTREE_EXTENDSELECT", NULL);
+ if (iupAttribGet(ih, "_IUPTREE_LASTSELITEM"))
+ {
+ winTreeCallMultiSelectionCb(ih);
+ iupAttribSetStr(ih, "_IUPTREE_LASTSELITEM", NULL);
+ }
+ }
+
+ if (ih->data->show_dragdrop && (HTREEITEM)iupAttribGet(ih, "_IUPTREE_DRAGITEM") != NULL)
+ winTreeDrop(ih);
+
+ break;
+ case WM_CHAR:
+ {
+ if (wp==VK_TAB) /* the keys have the same definitions as the chars */
+ {
+ *result = 0;
+ return 1; /* abort default processing to avoid beep */
+ }
+ break;
+ }
+ }
+
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+static COLORREF winTreeInvertColor(COLORREF color)
+{
+ return RGB(~GetRValue(color), ~GetGValue(color), ~GetBValue(color));
+}
+
+static int winTreeWmNotify(Ihandle* ih, NMHDR* msg_info, int *result)
+{
+ if (msg_info->code == TVN_ITEMCHANGINGA || msg_info->code == TVN_ITEMCHANGINGW) /* Vista Only */
+ {
+ if (ih->data->mark_mode==ITREE_MARK_MULTIPLE)
+ {
+ NMTVITEMCHANGE* info = (NMTVITEMCHANGE*)msg_info;
+ HTREEITEM hItem = (HTREEITEM)iupAttribGet(ih, "_IUPTREE_ALLOW_CHANGE");
+ if (hItem && hItem != info->hItem) /* Workaround for Vista SetFocus */
+ {
+ *result = TRUE; /* prevent the change */
+ return 1;
+ }
+ }
+ }
+ else if (msg_info->code == TVN_SELCHANGED)
+ {
+ NMTREEVIEW* info = (NMTREEVIEW*)msg_info;
+ winTreeCallSelectionCb(ih, 0, info->itemOld.hItem); /* node unselected */
+ winTreeCallSelectionCb(ih, 1, info->itemNew.hItem); /* node selected */
+ }
+ else if(msg_info->code == TVN_BEGINLABELEDIT)
+ {
+ char* value;
+ HWND hEdit;
+ NMTVDISPINFO* info = (NMTVDISPINFO*)msg_info;
+
+ if (iupAttribGet(ih, "_IUPTREE_EXTENDSELECT"))
+ {
+ *result = TRUE; /* prevent the change */
+ return 1;
+ }
+
+ hEdit = (HWND)SendMessage(ih->handle, TVM_GETEDITCONTROL, 0, 0);
+
+ /* save the edit box. */
+ iupwinHandleAdd(ih, hEdit);
+ iupAttribSetStr(ih, "_IUPWIN_EDITBOX", (char*)hEdit);
+
+ /* subclass the edit box. */
+ IupSetCallback(ih, "_IUPWIN_EDITOLDPROC_CB", (Icallback)GetWindowLongPtr(hEdit, GWLP_WNDPROC));
+ SetWindowLongPtr(hEdit, GWLP_WNDPROC, (LONG_PTR)winTreeEditWinProc);
+
+ value = iupAttribGetStr(ih, "RENAMECARET");
+ if (value)
+ winTreeSetRenameCaretPos(hEdit, value);
+
+ value = iupAttribGetStr(ih, "RENAMESELECTION");
+ if (value)
+ winTreeSetRenameSelectionPos(hEdit, value);
+
+ {
+ winTreeItemData* itemData;
+ TVITEM item;
+ item.hItem = info->item.hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+ iupAttribSetStr(ih, "_IUPWIN_EDIT_DATA", (char*)itemData);
+
+ if (itemData->hFont)
+ SendMessage(hEdit, WM_SETFONT, (WPARAM)itemData->hFont, MAKELPARAM(TRUE,0));
+ }
+ }
+ else if(msg_info->code == TVN_ENDLABELEDIT)
+ {
+ NMTVDISPINFO* info = (NMTVDISPINFO*)msg_info;
+
+ iupAttribSetStr(ih, "_IUPWIN_EDITBOX", NULL);
+
+ if (info->item.pszText)
+ {
+ IFnis cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB");
+ if (cbRename)
+ {
+ if (cbRename(ih, winTreeGetNodeId(ih, info->item.hItem), info->item.pszText) == IUP_IGNORE)
+ {
+ *result = FALSE;
+ return 1;
+ }
+ }
+
+ *result = TRUE;
+ return 1;
+ }
+ }
+ else if(msg_info->code == TVN_BEGINDRAG)
+ {
+ if (ih->data->show_dragdrop)
+ {
+ NMTREEVIEW* pNMTreeView = (NMTREEVIEW*)msg_info;
+ HTREEITEM hItemDrag = pNMTreeView->itemNew.hItem;
+ HIMAGELIST dragImageList;
+
+ /* store the drag-and-drop item */
+ iupAttribSetStr(ih, "_IUPTREE_DRAGITEM", (char*)hItemDrag);
+
+ /* get the image list for dragging */
+ dragImageList = (HIMAGELIST)SendMessage(ih->handle, TVM_CREATEDRAGIMAGE, 0, (LPARAM)hItemDrag);
+ if (dragImageList)
+ {
+ POINT pt = pNMTreeView->ptDrag;
+ ImageList_BeginDrag(dragImageList, 0, 0, 0);
+
+ ClientToScreen(ih->handle, &pt);
+ ImageList_DragEnter(NULL, pt.x, pt.y);
+
+ iupAttribSetStr(ih, "_IUPTREE_DRAGIMAGELIST", (char*)dragImageList);
+ }
+
+ ShowCursor(FALSE);
+ SetCapture(ih->handle); /* drag only inside the tree */
+ }
+ }
+ else if(msg_info->code == NM_DBLCLK)
+ {
+ HTREEITEM hItemFocus = winTreeGetFocusNode(ih);
+ TVITEM item;
+ winTreeItemData* itemData;
+
+ /* Get Children: branch or leaf */
+ item.mask = TVIF_HANDLE|TVIF_PARAM;
+ item.hItem = hItemFocus;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ if (itemData->kind == ITREE_LEAF)
+ {
+ IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB");
+ if(cbExecuteLeaf)
+ cbExecuteLeaf(ih, winTreeGetNodeId(ih, hItemFocus));
+ }
+ }
+ else if(msg_info->code == TVN_ITEMEXPANDING)
+ {
+ /* mouse click by user: click on the "+" sign or double click on the selected node */
+ NMTREEVIEW* tree_info = (NMTREEVIEW*)msg_info;
+ HTREEITEM hItem = tree_info->itemNew.hItem;
+
+ if (winTreeCallBranchLeafCb(ih, hItem) != IUP_IGNORE)
+ {
+ TVITEM item;
+ winTreeItemData* itemData = (winTreeItemData*)tree_info->itemNew.lParam;
+
+ if (tree_info->action == TVE_EXPAND)
+ item.iSelectedImage = item.iImage = (itemData->image_expanded!=-1)? itemData->image_expanded: (int)ih->data->def_image_expanded;
+ else
+ item.iSelectedImage = item.iImage = (itemData->image!=-1)? itemData->image: (int)ih->data->def_image_collapsed;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ SendMessage(ih->handle, TVM_SETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ }
+ else
+ {
+ *result = TRUE; /* prevent the change */
+ return 1;
+ }
+ }
+ else if(msg_info->code == NM_RCLICK)
+ {
+ HTREEITEM hItem = winTreeFindNodePointed(ih);
+ IFni cbRightClick = (IFni)IupGetCallback(ih, "RIGHTCLICK_CB");
+ if (cbRightClick)
+ cbRightClick(ih, winTreeGetNodeId(ih, hItem));
+ }
+ else if (msg_info->code == NM_CUSTOMDRAW)
+ {
+ NMTVCUSTOMDRAW *customdraw = (NMTVCUSTOMDRAW*)msg_info;
+
+ if (customdraw->nmcd.dwDrawStage == CDDS_PREPAINT)
+ {
+ *result = CDRF_NOTIFYPOSTPAINT|CDRF_NOTIFYITEMDRAW;
+ return 1;
+ }
+
+ if (customdraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
+ {
+ TVITEM item;
+ winTreeItemData* itemData;
+ HTREEITEM hItem = (HTREEITEM)customdraw->nmcd.dwItemSpec;
+
+ item.hItem = hItem;
+ item.mask = TVIF_HANDLE | TVIF_PARAM;
+ SendMessage(ih->handle, TVM_GETITEM, 0, (LPARAM)(LPTVITEM)&item);
+ itemData = (winTreeItemData*)item.lParam;
+
+ if (winTreeIsItemSelected(ih, hItem))
+ customdraw->clrText = winTreeInvertColor(itemData->color);
+ else
+ customdraw->clrText = itemData->color;
+
+ *result = CDRF_NOTIFYSUBITEMDRAW|CDRF_NOTIFYPOSTPAINT;
+
+ if (itemData->hFont)
+ {
+ SelectObject(customdraw->nmcd.hdc, itemData->hFont);
+ *result |= CDRF_NEWFONT;
+ }
+
+ return 1;
+ }
+ }
+
+ return 0; /* allow the default processsing */
+}
+
+static int winTreeConvertXYToPos(Ihandle* ih, int x, int y)
+{
+ TVHITTESTINFO info;
+ HTREEITEM hItem;
+ info.pt.x = x;
+ info.pt.y = y;
+ hItem = (HTREEITEM)SendMessage(ih->handle, TVM_HITTEST, 0, (LPARAM)&info);
+ if (hItem)
+ return winTreeGetNodeId(ih, hItem);
+ return -1;
+}
+
+
+/*******************************************************************************************/
+
+static void winTreeUnMapMethod(Ihandle* ih)
+{
+ Iarray* bmp_array;
+ HIMAGELIST image_list;
+
+ HTREEITEM itemRoot = (HTREEITEM)SendMessage(ih->handle, TVM_GETNEXTITEM, TVGN_ROOT, 0);
+ winTreeDelNodeData(ih, itemRoot);
+
+ image_list = (HIMAGELIST)SendMessage(ih->handle, TVM_GETIMAGELIST, TVSIL_NORMAL, 0);
+ if (image_list)
+ ImageList_Destroy(image_list);
+
+ bmp_array = (Iarray*)iupAttribGet(ih, "_IUPWIN_BMPARRAY");
+ if (bmp_array)
+ iupArrayDestroy(bmp_array);
+
+ iupdrvBaseUnMapMethod(ih);
+}
+
+static int winTreeMapMethod(Ihandle* ih)
+{
+ DWORD dwStyle = WS_CHILD | WS_BORDER | TVS_SHOWSELALWAYS;
+
+ /* can be set only on the Tree View creation */
+
+ if (!ih->data->show_dragdrop)
+ dwStyle |= TVS_DISABLEDRAGDROP;
+
+ if (ih->data->show_rename)
+ dwStyle |= TVS_EDITLABELS;
+
+ if (!iupAttribGetBoolean(ih, "HIDELINES"))
+ dwStyle |= TVS_HASLINES;
+
+ if (!iupAttribGetBoolean(ih, "HIDEBUTTONS"))
+ dwStyle |= TVS_HASBUTTONS;
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ dwStyle |= WS_TABSTOP;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ if (!iupwinCreateWindowEx(ih, WC_TREEVIEW, 0, dwStyle))
+ return IUP_ERROR;
+
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winTreeProc);
+ IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winTreeWmNotify);
+
+ /* Force background update before setting the images */
+ {
+ char* value = iupAttribGet(ih, "BGCOLOR");
+ if (value)
+ {
+ winTreeSetBgColorAttrib(ih, value);
+ iupAttribSetStr(ih, "BGCOLOR", NULL);
+ }
+ else if (iupwinGetSystemMajorVersion()<6) /* force background in XP because of the editbox background */
+ winTreeSetBgColorAttrib(ih, IupGetGlobal("TXTBGCOLOR"));
+ }
+
+ /* Initialize the default images */
+ ih->data->def_image_leaf = (void*)winTreeGetImageIndex(ih, "IMGLEAF");
+ ih->data->def_image_collapsed = (void*)winTreeGetImageIndex(ih, "IMGCOLLAPSED");
+ ih->data->def_image_expanded = (void*)winTreeGetImageIndex(ih, "IMGEXPANDED");
+
+ /* Add the Root Node */
+ winTreeAddRootNode(ih);
+
+ /* configure for DRAG&DROP of files */
+ if (IupGetCallback(ih, "DROPFILES_CB"))
+ iupAttribSetStr(ih, "DRAGDROP", "YES");
+
+ IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)winTreeConvertXYToPos);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvTreeInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winTreeMapMethod;
+ ic->UnMap = winTreeUnMapMethod;
+
+ /* Visual */
+ iupClassRegisterAttribute(ic, "BGCOLOR", winTreeGetBgColorAttrib, winTreeSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, winTreeSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT);
+
+ /* IupTree Attributes - GENERAL */
+ iupClassRegisterAttribute(ic, "EXPANDALL", NULL, winTreeSetExpandAllAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "INDENTATION", winTreeGetIndentationAttrib, winTreeSetIndentationAttrib, NULL, NULL, IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "COUNT", winTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SPACING", iupTreeGetSpacingAttrib, winTreeSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED);
+ iupClassRegisterAttribute(ic, "TOPITEM", NULL, winTreeSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+
+ /* IupTree Attributes - IMAGES */
+ iupClassRegisterAttributeId(ic, "IMAGE", NULL, winTreeSetImageAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "IMAGEEXPANDED", NULL, winTreeSetImageExpandedAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute(ic, "IMAGELEAF", NULL, winTreeSetImageLeafAttrib, IUPAF_SAMEASSYSTEM, "IMGLEAF", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEBRANCHCOLLAPSED", NULL, winTreeSetImageBranchCollapsedAttrib, IUPAF_SAMEASSYSTEM, "IMGCOLLAPSED", IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "IMAGEBRANCHEXPANDED", NULL, winTreeSetImageBranchExpandedAttrib, IUPAF_SAMEASSYSTEM, "IMGEXPANDED", IUPAF_NO_INHERIT);
+
+ /* IupTree Attributes - NODES */
+ iupClassRegisterAttributeId(ic, "STATE", winTreeGetStateAttrib, winTreeSetStateAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "DEPTH", winTreeGetDepthAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "KIND", winTreeGetKindAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "PARENT", winTreeGetParentAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "NAME", winTreeGetTitleAttrib, winTreeSetTitleAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "TITLE", winTreeGetTitleAttrib, winTreeSetTitleAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "CHILDCOUNT", winTreeGetChildCountAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "USERDATA", winTreeGetUserDataAttrib, winTreeSetUserDataAttrib, IUPAF_NO_STRING|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "COLOR", winTreeGetColorAttrib, winTreeSetColorAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "TITLEFONT", winTreeGetTitleFontAttrib, winTreeSetTitleFontAttrib, IUPAF_NO_INHERIT);
+
+ /* IupTree Attributes - MARKS */
+ iupClassRegisterAttributeId(ic, "MARKED", winTreeGetMarkedAttrib, winTreeSetMarkedAttrib, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute (ic, "MARK", NULL, winTreeSetMarkAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute (ic, "STARTING", NULL, winTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute (ic, "MARKSTART", NULL, winTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ iupClassRegisterAttribute (ic, "VALUE", winTreeGetValueAttrib, winTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+
+ /* IupTree Attributes - ACTION */
+ iupClassRegisterAttributeId(ic, "DELNODE", NULL, winTreeSetDelNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "RENAME", NULL, winTreeSetRenameAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "MOVENODE", NULL, winTreeSetMoveNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "COPYNODE", NULL, winTreeSetCopyNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT);
+ iupClassRegisterAttributeId(ic, "FINDUSERDATA", winTreeGetFindUserDataAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT);
+}
diff --git a/iup/src/win/iupwin_val.c b/iup/src/win/iupwin_val.c
new file mode 100755
index 0000000..706c612
--- /dev/null
+++ b/iup/src/win/iupwin_val.c
@@ -0,0 +1,315 @@
+/** \file
+ * \brief Valuator Control
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <memory.h>
+#include <stdarg.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_val.h"
+#include "iup_drv.h"
+
+#include "iupwin_drv.h"
+#include "iupwin_handle.h"
+#include "iupwin_draw.h"
+
+
+#ifndef SHRT_MAX
+#define SHRT_MAX 32767
+#endif
+
+void iupdrvValGetMinSize(Ihandle* ih, int *w, int *h)
+{
+ int ticks_size = 0;
+ if (iupAttribGetInt(ih, "SHOWTICKS"))
+ {
+ char* tickspos = iupAttribGetStr(ih, "TICKSPOS");
+ if(iupStrEqualNoCase(tickspos, "BOTH"))
+ ticks_size = 2*8;
+ else
+ ticks_size = 8;
+ }
+
+ if (ih->data->type == IVAL_HORIZONTAL)
+ {
+ *w = 35;
+ *h = 30+ticks_size;
+ }
+ else
+ {
+ *w = 30+ticks_size;
+ *h = 35;
+ }
+}
+
+static int winValSetStepAttrib(Ihandle* ih, const char* value)
+{
+ int linesize;
+ ih->data->step = atof(value);
+ linesize = (int)(ih->data->step*SHRT_MAX);
+ SendMessage(ih->handle, TBM_SETLINESIZE, 0, linesize);
+ return 0; /* do not store value in hash table */
+}
+
+static int winValSetPageStepAttrib(Ihandle* ih, const char* value)
+{
+ int pagesize;
+ ih->data->pagestep = atof(value);
+ pagesize = (int)(ih->data->pagestep*SHRT_MAX);
+ SendMessage(ih->handle, TBM_SETPAGESIZE, 0, pagesize);
+ return 0; /* do not store value in hash table */
+}
+
+static int winValSetShowTicksAttrib(Ihandle* ih, const char* value)
+{
+ int tick_freq, show_ticks;
+
+ if (!ih->data->show_ticks) /* can only set if already not zero */
+ return 0;
+
+ show_ticks = atoi(value);
+ if (show_ticks<2) show_ticks=2;
+ ih->data->show_ticks = show_ticks;
+
+ /* Defines the interval frequency for tick marks */
+ tick_freq = SHRT_MAX/(show_ticks-1);
+ SendMessage(ih->handle, TBM_SETTICFREQ, tick_freq, 0);
+ return 0;
+}
+
+static int winValSetValueAttrib(Ihandle* ih, const char* value)
+{
+ int ival;
+
+ ih->data->val = atof(value);
+ iupValCropValue(ih);
+
+ ival = (int)(((ih->data->val-ih->data->vmin)/(ih->data->vmax - ih->data->vmin))*SHRT_MAX);
+ if (ih->data->inverted)
+ ival = SHRT_MAX-ival;
+
+ SendMessage(ih->handle, TBM_SETPOS, TRUE, ival);
+ return 0; /* do not store value in hash table */
+}
+
+
+/*********************************************************************************************/
+
+
+static int winValCtlColor(Ihandle* ih, HDC hdc, LRESULT *result)
+{
+ COLORREF cr;
+ if (iupwinGetParentBgColor(ih, &cr))
+ {
+ SetDCBrushColor(hdc, cr);
+ *result = (LRESULT)GetStockObject(DC_BRUSH);
+ return 1;
+ }
+ return 0;
+}
+
+static int winValCustomScroll(Ihandle* ih, int msg)
+{
+ double old_val = ih->data->val;
+ int ival;
+ IFn cb;
+
+ ival = (int)SendMessage(ih->handle, TBM_GETPOS, 0, 0);
+ if (ih->data->inverted)
+ ival = SHRT_MAX-ival;
+
+ ih->data->val = (((double)ival/(double)SHRT_MAX)*(ih->data->vmax - ih->data->vmin)) + ih->data->vmin;
+ iupValCropValue(ih);
+
+ cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB");
+ if (cb)
+ {
+ if (ih->data->val == old_val)
+ return 0;
+
+ cb(ih);
+ }
+ else
+ {
+ IFnd cb_old = NULL;
+ switch (msg)
+ {
+ case TB_BOTTOM:
+ case TB_TOP:
+ case TB_LINEDOWN:
+ case TB_LINEUP:
+ case TB_PAGEDOWN:
+ case TB_PAGEUP:
+ {
+ cb_old = (IFnd) IupGetCallback(ih, "BUTTON_PRESS_CB");
+ break;
+ }
+ case TB_THUMBPOSITION:
+ {
+ cb_old = (IFnd) IupGetCallback(ih, "BUTTON_RELEASE_CB");
+ break;
+ }
+ case TB_THUMBTRACK:
+ {
+ cb_old = (IFnd) IupGetCallback(ih, "MOUSEMOVE_CB");
+ break;
+ }
+ }
+ if (cb_old)
+ cb_old(ih, ih->data->val);
+ }
+
+ return 0; /* not used */
+}
+
+static void winValIncPageValue(Ihandle *ih, int dir)
+{
+ int pagesize, ival;
+ pagesize = (int)(ih->data->pagestep*SHRT_MAX);
+
+ ival = (int)SendMessage(ih->handle, TBM_GETPOS, 0, 0);
+ ival += dir*pagesize;
+ if (ival < 0) ival = 0;
+ if (ival > SHRT_MAX) ival = SHRT_MAX;
+ SendMessage(ih->handle, TBM_SETPOS, TRUE, ival);
+
+ winValCustomScroll(ih, 0);
+}
+
+static int winValProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result)
+{
+ (void)lp;
+
+ switch (msg)
+ {
+ case WM_ERASEBKGND:
+ {
+ RECT rect;
+ HDC hDC = (HDC)wp;
+ GetClientRect(ih->handle, &rect);
+ iupwinDrawParentBackground(ih, hDC, &rect);
+ /* return non zero value */
+ *result = 1;
+ return 1;
+ }
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ {
+ if (iupwinBaseProc(ih, msg, wp, lp, result)==1)
+ return 1;
+
+ if (GetKeyState(VK_CONTROL) & 0x8000) /* handle Ctrl+Arrows */
+ {
+ if (wp == VK_UP || wp == VK_LEFT)
+ {
+ winValIncPageValue(ih, -1);
+ *result = 0;
+ return 1;
+ }
+ if (wp == VK_RIGHT || wp == VK_DOWN)
+ {
+ winValIncPageValue(ih, 1);
+ *result = 0;
+ return 1;
+ }
+ }
+ return 0;
+ }
+ }
+
+ return iupwinBaseProc(ih, msg, wp, lp, result);
+}
+
+
+/*********************************************************************************************/
+
+
+static int winValMapMethod(Ihandle* ih)
+{
+ DWORD dwStyle = WS_CHILD | TBS_AUTOTICKS;
+ int show_ticks;
+
+ if (!ih->parent)
+ return IUP_ERROR;
+
+ /* Track bar Orientation */
+ if (ih->data->type == IVAL_HORIZONTAL)
+ dwStyle |= TBS_HORZ;
+ else
+ dwStyle |= TBS_VERT;
+
+ if (iupAttribGetBoolean(ih, "CANFOCUS"))
+ dwStyle |= WS_TABSTOP;
+
+ /* Track bar Ticks */
+ show_ticks = iupAttribGetInt(ih, "SHOWTICKS");
+ if (!show_ticks)
+ {
+ dwStyle |= TBS_NOTICKS; /* No show_ticks */
+ }
+ else
+ {
+ char* tickspos;
+
+ if (show_ticks<2) show_ticks=2;
+ ih->data->show_ticks = show_ticks; /* non zero value, can be changed later, but not to zero */
+
+ /* Defines the position of tick marks */
+ tickspos = iupAttribGetStr(ih, "TICKSPOS");
+ if(iupStrEqualNoCase(tickspos, "BOTH"))
+ dwStyle |= TBS_BOTH;
+ else if(iupStrEqualNoCase(tickspos, "REVERSE"))
+ dwStyle |= TBS_BOTTOM; /* same as TBS_RIGHT */
+ else /* NORMAL */
+ dwStyle |= TBS_TOP; /* same as TBS_LEFT */
+ }
+
+ if (!iupwinCreateWindowEx(ih, TRACKBAR_CLASS, 0, dwStyle))
+ return IUP_ERROR;
+
+ /* Process Keyboard */
+ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winValProc);
+
+ /* Process Val Scroll commands */
+ IupSetCallback(ih, "_IUPWIN_CUSTOMSCROLL_CB", (Icallback)winValCustomScroll);
+
+ /* Process background color */
+ IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winValCtlColor);
+
+ /* configure the native range */
+ SendMessage(ih->handle, TBM_SETRANGEMIN, FALSE, 0);
+ SendMessage(ih->handle, TBM_SETRANGEMAX, FALSE, SHRT_MAX);
+
+ if (ih->data->inverted)
+ SendMessage(ih->handle, TBM_SETPOS, FALSE, SHRT_MAX); /* default initial position is at MIN */
+
+ return IUP_NOERROR;
+}
+
+void iupdrvValInitClass(Iclass* ic)
+{
+ /* Driver Dependent Class functions */
+ ic->Map = winValMapMethod;
+
+ /* IupVal only */
+ iupClassRegisterAttribute(ic, "VALUE", iupValGetValueAttrib, winValSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "SHOWTICKS", iupValGetShowTicksAttrib, winValSetShowTicksAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_DEFAULT);
+ iupClassRegisterAttribute(ic, "PAGESTEP", iupValGetPageStepAttrib, winValSetPageStepAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */
+ iupClassRegisterAttribute(ic, "STEP", iupValGetStepAttrib, winValSetStepAttrib, "0.01", NULL, IUPAF_NO_INHERIT); /* force new default value */
+
+ iupClassRegisterAttribute(ic, "TICKSPOS", NULL, NULL, "NORMAL", NULL, IUPAF_NOT_MAPPED);
+}
diff --git a/iup/src/win/iupwindows_help.c b/iup/src/win/iupwindows_help.c
new file mode 100755
index 0000000..f3a06b6
--- /dev/null
+++ b/iup/src/win/iupwindows_help.c
@@ -0,0 +1,32 @@
+/** \file
+ * \brief Windows Driver IupHelp
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <windows.h>
+#include <shellapi.h>
+
+#include "iup.h"
+
+int IupHelp(const char* url)
+{
+ int err = (int)ShellExecute(GetDesktopWindow(), "open", url, NULL, NULL, SW_SHOWNORMAL);
+ if (err <= 32)
+ {
+ switch (err)
+ {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ return -2; /* File not found */
+ break;
+ default:
+ return -1; /* Generic error */
+ break;
+ }
+ }
+ return 1;
+}
diff --git a/iup/src/win/iupwindows_info.c b/iup/src/win/iupwindows_info.c
new file mode 100755
index 0000000..982c980
--- /dev/null
+++ b/iup/src/win/iupwindows_info.c
@@ -0,0 +1,212 @@
+/** \file
+ * \brief Windows System Information
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* This module should depend only on IUP core headers
+ and Windows system headers. */
+
+#include <windows.h>
+
+#include "iup_str.h"
+#include "iup_drvinfo.h"
+
+
+int iupdrvMakeDirectory(const char* name)
+{
+ if (CreateDirectory(name, NULL))
+ return 1;
+ else
+ return 0;
+}
+
+int iupdrvIsFile(const char* name)
+{
+ DWORD attrib = GetFileAttributes(name);
+ if (attrib == INVALID_FILE_ATTRIBUTES)
+ return 0;
+ if (attrib & FILE_ATTRIBUTE_DIRECTORY)
+ return 0;
+ return 1;
+}
+
+int iupdrvIsDirectory(const char* name)
+{
+ DWORD attrib = GetFileAttributes(name);
+ if (attrib == INVALID_FILE_ATTRIBUTES)
+ return 0;
+ if (attrib & FILE_ATTRIBUTE_DIRECTORY)
+ return 1;
+ return 0;
+}
+
+char* iupdrvGetCurrentDirectory(void)
+{
+ char* cur_dir;
+ int len = GetCurrentDirectory(0, NULL);
+ if (len == 0) return NULL;
+
+ cur_dir = malloc(len+2);
+ GetCurrentDirectory(len+1, cur_dir);
+ cur_dir[len] = '\\';
+ cur_dir[len+1] = 0;
+ return cur_dir;
+}
+
+int iupdrvSetCurrentDirectory(const char* dir)
+{
+ return SetCurrentDirectory(dir);
+}
+
+int iupdrvGetWindowDecor(void* wnd, int *border, int *caption)
+{
+ WINDOWINFO wi;
+ wi.cbSize = sizeof(WINDOWINFO);
+ GetWindowInfo((HWND)wnd, &wi);
+
+ *border = wi.cxWindowBorders;
+
+ if (wi.rcClient.bottom == wi.rcClient.top)
+ *caption = wi.rcClient.bottom - wi.cyWindowBorders;
+ else
+ {
+ /* caption = window height - top border - client height */
+ *caption = (wi.rcWindow.bottom-wi.rcWindow.top) - 2*wi.cyWindowBorders - (wi.rcClient.bottom-wi.rcClient.top);
+ }
+
+ return 1;
+}
+
+void iupdrvGetScreenSize(int *width, int *height)
+{
+ RECT area;
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &area, 0);
+ *width = (int)(area.right - area.left);
+ *height = (int)(area.bottom - area.top);
+}
+
+void iupdrvGetFullSize(int *width, int *height)
+{
+ RECT rect;
+ GetWindowRect(GetDesktopWindow(), &rect);
+ *width = rect.right - rect.left;
+ *height = rect.bottom - rect.top;
+}
+
+int iupdrvGetScreenDepth(void)
+{
+ int bpp;
+ HDC hDCDisplay = GetDC(NULL);
+ bpp = GetDeviceCaps(hDCDisplay, BITSPIXEL);
+ ReleaseDC(NULL, hDCDisplay);
+ return bpp;
+}
+
+void iupdrvGetCursorPos(int *x, int *y)
+{
+ POINT CursorPoint;
+ GetCursorPos(&CursorPoint);
+ *x = (int)CursorPoint.x;
+ *y = (int)CursorPoint.y;
+}
+
+void iupdrvGetKeyState(char* key)
+{
+ if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
+ key[0] = 'S';
+ else
+ key[0] = ' ';
+ if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
+ key[1] = 'C';
+ else
+ key[1] = ' ';
+ if (GetAsyncKeyState(VK_MENU) & 0x8000)
+ key[2] = 'A';
+ else
+ key[2] = ' ';
+ if ((GetAsyncKeyState(VK_LWIN) & 0x8000) || (GetAsyncKeyState(VK_RWIN) & 0x8000))
+ key[3] = 'Y';
+ else
+ key[3] = ' ';
+
+ key[4] = 0;
+}
+
+char *iupdrvGetSystemName(void)
+{
+ OSVERSIONINFO osvi;
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&osvi);
+
+ if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
+ {
+ if (osvi.dwMajorVersion <= 4)
+ return "WinNT";
+
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
+ return "Win2K";
+
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion > 0)
+ return "WinXP";
+
+ if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0)
+ return "Vista";
+
+ if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion > 0)
+ return "Win7";
+ }
+
+ return "Windows";
+}
+
+char *iupdrvGetSystemVersion(void)
+{
+ char *str = iupStrGetMemory(256);
+ OSVERSIONINFOEX osvi;
+ SYSTEM_INFO si;
+
+ ZeroMemory(&si, sizeof(SYSTEM_INFO));
+ GetSystemInfo(&si);
+
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ GetVersionEx((OSVERSIONINFO*)&osvi);
+
+ sprintf(str, "%d.%d.%d", (int)osvi.dwMajorVersion, (int)osvi.dwMinorVersion, (int)osvi.dwBuildNumber);
+
+ /* Display service pack (if any). */
+ if (osvi.szCSDVersion && osvi.szCSDVersion[0]!=0)
+ {
+ strcat(str, " ");
+ strcat(str, osvi.szCSDVersion);
+ }
+
+ if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
+ strcat(str, " (IA64)");
+ else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
+ strcat(str, " (x64)");
+ else
+ strcat(str, " (x86)");
+
+ return str;
+}
+
+char *iupdrvGetComputerName(void)
+{
+ DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
+ char* str = iupStrGetMemory(size);
+ GetComputerName((LPTSTR)str, &size);
+ return str;
+}
+
+char *iupdrvGetUserName(void)
+{
+ DWORD size = 256;
+ char* str = iupStrGetMemory(size);
+ GetUserName((LPTSTR)str, &size);
+ return (char*)str;
+}
diff --git a/iup/src/win/iupwindows_main.c b/iup/src/win/iupwindows_main.c
new file mode 100755
index 0000000..ea7e2ae
--- /dev/null
+++ b/iup/src/win/iupwindows_main.c
@@ -0,0 +1,66 @@
+/** \file
+ * \brief Windows Driver WinMain
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+
+#include <stdlib.h> /* declaration of __argc and __argv */
+
+#include "iup.h"
+
+
+#ifdef __WATCOMC__ /* force Watcom to link this module, called from IupOpen */
+void iupwinMainDummy(void)
+{
+ return;
+}
+#else
+extern int main(int, char **);
+#endif
+
+/* save this handle in DllMain only, use to load resources from the DLL. */
+HINSTANCE iupwin_dll_hinstance = 0;
+
+#ifdef IUP_DLL
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ (void)fdwReason;
+ (void)lpvReserved;
+
+ iupwin_dll_hinstance = hinstDLL;
+
+ return TRUE;
+}
+#else
+/* this module is always linked in the makefile,
+ But it must not define WinMain if building the DLL */
+int PASCAL WinMain (HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int ncmdshow)
+{
+ (void)hinst; /* NOT used */
+ (void)hprev;
+ (void)cmdline;
+ (void)ncmdshow;
+
+ /* WinMain is NOT called for Console applications */
+
+#ifdef __WATCOMC__
+ {
+ extern int _argc;
+ extern char** _argv;
+ return IupMain(_argc, _argv);
+ }
+#else
+ {
+ /* this seems to work for all the compilers we tested, except Watcom compilers */
+ /* These are declared in <stdlib.h>, except for Cygwin. */
+#ifdef __GNUC__
+ extern int __argc;
+ extern char** __argv;
+#endif
+ return main(__argc, __argv);
+ }
+#endif
+}
+#endif