From d577d991b97ae2b5ee1af23641bcffc3f83af5b2 Mon Sep 17 00:00:00 2001 From: Pixel Date: Wed, 4 Nov 2009 11:56:41 -0800 Subject: Initial import. Contains the im, cd and iup librairies, and a "working" Makefile for them under linux. --- iup/src/win/iupwin_brush.c | 62 + iup/src/win/iupwin_brush.h | 26 + iup/src/win/iupwin_button.c | 715 +++++++++++ iup/src/win/iupwin_canvas.c | 724 +++++++++++ iup/src/win/iupwin_clipboard.c | 190 +++ iup/src/win/iupwin_colordlg.c | 133 ++ iup/src/win/iupwin_common.c | 865 +++++++++++++ iup/src/win/iupwin_dialog.c | 1439 +++++++++++++++++++++ iup/src/win/iupwin_draw.c | 328 +++++ iup/src/win/iupwin_draw.h | 47 + iup/src/win/iupwin_drv.h | 113 ++ iup/src/win/iupwin_filedlg.c | 580 +++++++++ iup/src/win/iupwin_focus.c | 62 + iup/src/win/iupwin_font.c | 342 +++++ iup/src/win/iupwin_fontdlg.c | 160 +++ iup/src/win/iupwin_frame.c | 203 +++ iup/src/win/iupwin_globalattrib.c | 243 ++++ iup/src/win/iupwin_handle.c | 56 + iup/src/win/iupwin_handle.h | 28 + iup/src/win/iupwin_image.c | 668 ++++++++++ iup/src/win/iupwin_info.c | 277 ++++ iup/src/win/iupwin_info.h | 29 + iup/src/win/iupwin_key.c | 348 +++++ iup/src/win/iupwin_label.c | 339 +++++ iup/src/win/iupwin_list.c | 1460 +++++++++++++++++++++ iup/src/win/iupwin_loop.c | 135 ++ iup/src/win/iupwin_menu.c | 667 ++++++++++ iup/src/win/iupwin_messagedlg.c | 105 ++ iup/src/win/iupwin_open.c | 124 ++ iup/src/win/iupwin_progressbar.c | 164 +++ iup/src/win/iupwin_tabs.c | 680 ++++++++++ iup/src/win/iupwin_text.c | 1993 +++++++++++++++++++++++++++++ iup/src/win/iupwin_timer.c | 88 ++ iup/src/win/iupwin_tips.c | 191 +++ iup/src/win/iupwin_toggle.c | 693 ++++++++++ iup/src/win/iupwin_tree.c | 2542 +++++++++++++++++++++++++++++++++++++ iup/src/win/iupwin_val.c | 315 +++++ iup/src/win/iupwindows_help.c | 32 + iup/src/win/iupwindows_info.c | 212 ++++ iup/src/win/iupwindows_main.c | 66 + 40 files changed, 17444 insertions(+) create mode 100755 iup/src/win/iupwin_brush.c create mode 100755 iup/src/win/iupwin_brush.h create mode 100755 iup/src/win/iupwin_button.c create mode 100755 iup/src/win/iupwin_canvas.c create mode 100755 iup/src/win/iupwin_clipboard.c create mode 100755 iup/src/win/iupwin_colordlg.c create mode 100755 iup/src/win/iupwin_common.c create mode 100755 iup/src/win/iupwin_dialog.c create mode 100755 iup/src/win/iupwin_draw.c create mode 100755 iup/src/win/iupwin_draw.h create mode 100755 iup/src/win/iupwin_drv.h create mode 100755 iup/src/win/iupwin_filedlg.c create mode 100755 iup/src/win/iupwin_focus.c create mode 100755 iup/src/win/iupwin_font.c create mode 100755 iup/src/win/iupwin_fontdlg.c create mode 100755 iup/src/win/iupwin_frame.c create mode 100755 iup/src/win/iupwin_globalattrib.c create mode 100755 iup/src/win/iupwin_handle.c create mode 100755 iup/src/win/iupwin_handle.h create mode 100755 iup/src/win/iupwin_image.c create mode 100755 iup/src/win/iupwin_info.c create mode 100755 iup/src/win/iupwin_info.h create mode 100755 iup/src/win/iupwin_key.c create mode 100755 iup/src/win/iupwin_label.c create mode 100755 iup/src/win/iupwin_list.c create mode 100755 iup/src/win/iupwin_loop.c create mode 100755 iup/src/win/iupwin_menu.c create mode 100755 iup/src/win/iupwin_messagedlg.c create mode 100755 iup/src/win/iupwin_open.c create mode 100755 iup/src/win/iupwin_progressbar.c create mode 100755 iup/src/win/iupwin_tabs.c create mode 100755 iup/src/win/iupwin_text.c create mode 100755 iup/src/win/iupwin_timer.c create mode 100755 iup/src/win/iupwin_tips.c create mode 100755 iup/src/win/iupwin_toggle.c create mode 100755 iup/src/win/iupwin_tree.c create mode 100755 iup/src/win/iupwin_val.c create mode 100755 iup/src/win/iupwindows_help.c create mode 100755 iup/src/win/iupwindows_info.c create mode 100755 iup/src/win/iupwindows_main.c (limited to 'iup/src/win') 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 +#include + +#include + +#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 +#include + +#include +#include +#include +#include +#include + +#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 + +#include +#include +#include +#include +#include + +#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 + +#include +#include + +#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 +#include + +#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 +#include +#include + +#include +#include + +#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 + +#include +#include +#include +#include +#include + +#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 +#include +#include + +#include +#include +#include +#include + +#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 +#include +#include + +#include + +#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 +#include + +#include + +#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 +#include + +#include + +#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 +#include + +#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 +#include + +#include +#include +#include +#include +#include + +#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 +#include +#include + +#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 +#include +#include + +#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 + +#include +#include +#include + +#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;ibiWidth; + 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;ibiSize = 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; ycurrentwidth, + 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 +#include + +#include +#include + +#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 + +#include + +#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 + +#include +#include +#include +#include +#include + +#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 +#include + +#include +#include +#include +#include +#include + +#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; ihandle, 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; ihandle, 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; idata->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; ihandle, 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 +#include +#include + +#include + +#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 + +#include +#include +#include + +#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 + +#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 +#include +#include + +#include +#include + +#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 +#include + +#include +#include +#include +#include +#include + +#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 +#include + +#include +#include +#include +#include +#include +#include + +#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; ihandle, TCM_GETITEMCOUNT, 0, 0); + tie.mask = TCIF_PARAM; + + for (pos=0; poshandle, 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; poshandle, 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 +#include +#include + +#include +#include +#include +#include +#include + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_mask.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_array.h" +#include "iup_text.h" +#include "iup_key.h" +#include "iup_dialog.h" + +#include "iupwin_drv.h" +#include "iupwin_handle.h" + +/* Cygwin and MingW Win32api does not define these */ + +#ifndef PFN_ARABIC +#define PFN_ARABIC 2 +#define PFN_LCLETTER 3 +#define PFN_UCLETTER 4 +#define PFN_LCROMAN 5 +#define PFN_UCROMAN 6 +#endif + +#ifndef PFNS_PAREN +#define PFNS_PAREN 0x000 +#define PFNS_PARENS 0x100 +#define PFNS_PERIOD 0x200 +#define PFNS_PLAIN 0x300 +#define PFNS_NONUMBER 0x400 +#endif + +#ifndef CFM_BACKCOLOR +#define CFM_BACKCOLOR 0x04000000 +#define CFM_UNDERLINETYPE 0x00800000 +#define CFM_WEIGHT 0x00400000 +#define CFM_DISABLED 0x2000 +#define CFE_DISABLED CFM_DISABLED +#endif + +#ifndef CFU_UNDERLINEDOTTED +#define CFU_UNDERLINEDOTTED 4 +#define CFU_UNDERLINEDOUBLE 3 +#define CFU_UNDERLINE 1 +#define CFU_UNDERLINENONE 0 +#endif + +#ifndef SES_UPPERCASE +#define SES_UPPERCASE 512 +#define SES_LOWERCASE 1024 +#endif +/* End Cygwin/MingW */ + +#ifndef EM_SETCUEBANNER /* defined only if _WIN32_WINNT >= 0x501 */ +#define ECM_FIRST 0x1500 /* Edit control messages */ +#define EM_SETCUEBANNER (ECM_FIRST + 1) +#endif + +#define WM_CARET WM_APP+1 /* Custom IUP message */ + + +void iupdrvTextAddSpin(int *w, int h) +{ + *w += h; +} + +void iupdrvTextAddBorders(int *w, int *h) +{ + int border_size = 2*3; + (*w) += border_size; + (*h) += border_size; +} + +static void winTextParseParagraphFormat(Ihandle* formattag, PARAFORMAT2 *paraformat, int convert2twips) +{ + int val; + char* format; + + ZeroMemory(paraformat, sizeof(PARAFORMAT2)); + paraformat->cbSize = sizeof(PARAFORMAT2); + + format = iupAttribGet(formattag, "NUMBERING"); + if (format) + { + paraformat->dwMask |= PFM_NUMBERING; + + if (iupStrEqualNoCase(format, "BULLET")) + paraformat->wNumbering = PFN_BULLET; + else if (iupStrEqualNoCase(format, "ARABIC")) + paraformat->wNumbering = PFN_ARABIC; + else if (iupStrEqualNoCase(format, "LCLETTER")) + paraformat->wNumbering = PFN_LCLETTER; + else if (iupStrEqualNoCase(format, "UCLETTER")) + paraformat->wNumbering = PFN_UCLETTER; + else if (iupStrEqualNoCase(format, "LCROMAN")) + paraformat->wNumbering = PFN_LCROMAN; + else if (iupStrEqualNoCase(format, "UCROMAN")) + paraformat->wNumbering = PFN_UCROMAN; + else + paraformat->wNumbering = 0; /* "NONE" */ + + format = iupAttribGet(formattag, "NUMBERINGSTYLE"); + if (format) + { + paraformat->dwMask |= PFM_NUMBERINGSTYLE; + + if (iupStrEqualNoCase(format, "RIGHTPARENTESES")) + paraformat->wNumberingStyle = PFNS_PAREN; + else if (iupStrEqualNoCase(format, "PARENTESES")) + paraformat->wNumberingStyle = PFNS_PARENS; + else if (iupStrEqualNoCase(format, "PERIOD")) + paraformat->wNumberingStyle = PFNS_PERIOD; + else if (iupStrEqualNoCase(format, "NONUMBER")) + paraformat->wNumberingStyle = PFNS_NONUMBER; + else + paraformat->wNumberingStyle = PFNS_PLAIN; /* "NONE" */ + } + + format = iupAttribGet(formattag, "NUMBERINGTAB"); + if (format && iupStrToInt(format, &val)) + { + paraformat->dwMask |= PFM_NUMBERINGTAB; + paraformat->wNumberingTab = (WORD)(val*convert2twips); + } + } + + format = iupAttribGet(formattag, "INDENT"); + if (format && iupStrToInt(format, &val)) + { + paraformat->dwMask |= PFM_STARTINDENT|PFM_RIGHTINDENT|PFM_OFFSET; + paraformat->dxStartIndent = val*convert2twips; + + format = iupAttribGet(formattag, "INDENTRIGHT"); + if (format && iupStrToInt(format, &val)) + paraformat->dxRightIndent = val*convert2twips; + else + paraformat->dxRightIndent = paraformat->dxStartIndent; + + format = iupAttribGet(formattag, "INDENTOFFSET"); + if (format && iupStrToInt(format, &val)) + paraformat->dxOffset = val*convert2twips; + else + paraformat->dxOffset = 0; + } + + format = iupAttribGet(formattag, "ALIGNMENT"); + if (format) + { + paraformat->dwMask |= PFM_ALIGNMENT; + + if (iupStrEqualNoCase(format, "JUSTIFY")) + paraformat->wAlignment = PFA_JUSTIFY; + else if (iupStrEqualNoCase(format, "RIGHT")) + paraformat->wAlignment = PFA_RIGHT; + else if (iupStrEqualNoCase(format, "CENTER")) + paraformat->wAlignment = PFA_CENTER; + else + paraformat->wAlignment = PFA_LEFT; /* "LEFT" */ + } + + format = iupAttribGet(formattag, "TABSARRAY"); + if (format) + { + int pos, align, i = 0; + LONG tab; + char* str; + + paraformat->dwMask |= PFM_TABSTOPS; + + while (format) + { + str = iupStrCopyUntil((char**)&format, ' '); + if (!str) break; + pos = atoi(str)*convert2twips; + free(str); + + str = iupStrCopyUntil((char**)&format, ' '); + if (!str) break; + + if (iupStrEqualNoCase(str, "DECIMAL")) + align = 3; + else if (iupStrEqualNoCase(str, "RIGHT")) + align = 2; + else if (iupStrEqualNoCase(str, "CENTER")) + align = 1; + else /* "LEFT" */ + align = 0; + free(str); + + tab = (pos&0xFFF)|(align<<24); + paraformat->rgxTabs[i] = tab; + i++; + if (i == 32) break; + } + paraformat->cTabCount = (SHORT)i; + } + + format = iupAttribGet(formattag, "SPACEBEFORE"); + if (format && iupStrToInt(format, &val)) + { + paraformat->dwMask |= PFM_SPACEBEFORE; + paraformat->dySpaceBefore = val*convert2twips; + } + + format = iupAttribGet(formattag, "SPACEAFTER"); + if (format && iupStrToInt(format, &val)) + { + paraformat->dwMask |= PFM_SPACEAFTER; + paraformat->dySpaceAfter = val*convert2twips; + } + + format = iupAttribGet(formattag, "LINESPACING"); + if (format) + { + paraformat->dwMask |= PFM_LINESPACING; + + if (iupStrEqualNoCase(format, "SINGLE")) + paraformat->bLineSpacingRule = 0; + else if (iupStrEqualNoCase(format, "ONEHALF")) + paraformat->bLineSpacingRule = 1; + else if (iupStrEqualNoCase(format, "DOUBLE")) + paraformat->bLineSpacingRule = 2; + else if (iupStrToInt(format, &val)) + { + paraformat->bLineSpacingRule = 3; + paraformat->dyLineSpacing = val*convert2twips; + } + } +} + +static void winTextParseCharacterFormat(Ihandle* formattag, CHARFORMAT2 *charformat, int pixel2twips) +{ + int val; + char* format; + + ZeroMemory(charformat, sizeof(CHARFORMAT2)); + charformat->cbSize = sizeof(CHARFORMAT2); + + format = iupAttribGet(formattag, "DISABLED"); + if (format) + { + charformat->dwMask |= CFM_DISABLED; + if (iupStrBoolean(format)) + charformat->dwEffects |= CFE_DISABLED; + } + + format = iupAttribGet(formattag, "RISE"); + if (format) + { + if (iupStrEqualNoCase(format, "SUPERSCRIPT")) + { + charformat->dwMask |= CFM_SUPERSCRIPT; + charformat->dwEffects |= CFE_SUPERSCRIPT; + } + else if (iupStrEqualNoCase(format, "SUBSCRIPT")) + { + charformat->dwMask |= CFM_SUBSCRIPT; + charformat->dwEffects |= CFE_SUBSCRIPT; + } + else if (iupStrToInt(format, &val)) + { + charformat->dwMask |= CFM_OFFSET; + charformat->yOffset = val; + } + } + + format = iupAttribGet(formattag, "ITALIC"); + if (format) + { + charformat->dwMask |= CFM_ITALIC; + if (iupStrBoolean(format)) + charformat->dwEffects |= CFE_ITALIC; + } + + format = iupAttribGet(formattag, "STRIKEOUT"); + if (format) + { + charformat->dwMask |= CFM_STRIKEOUT; + if (iupStrBoolean(format)) + charformat->dwEffects |= CFE_STRIKEOUT; + } + + format = iupAttribGet(formattag, "PROTECTED"); + if (format) + { + charformat->dwMask |= CFM_PROTECTED; + if (iupStrBoolean(format)) + charformat->dwEffects |= CFE_PROTECTED; + } + + format = iupAttribGet(formattag, "FONTSIZE"); + if (format && iupStrToInt(format, &val)) + { + /* (1/1440 of an inch, or 1/20 of a printer's point) */ + charformat->dwMask |= CFM_SIZE; + if (val < 0) /* in pixels */ + charformat->yHeight = (-val)*pixel2twips; + else + charformat->yHeight = val*20; + } + + format = iupAttribGet(formattag, "FONTSCALE"); + if (format && charformat->yHeight != 0) + { + float fval = 0; + if (iupStrEqualNoCase(format, "XX-SMALL")) + fval = 0.5787037037037f; + else if (iupStrEqualNoCase(format, "X-SMALL")) + fval = 0.6444444444444f; + else if (iupStrEqualNoCase(format, "SMALL")) + fval = 0.8333333333333f; + else if (iupStrEqualNoCase(format, "MEDIUM")) + fval = 1.0f; + else if (iupStrEqualNoCase(format, "LARGE")) + fval = 1.2f; + else if (iupStrEqualNoCase(format, "X-LARGE")) + fval = 1.4399999999999f; + else if (iupStrEqualNoCase(format, "XX-LARGE")) + fval = 1.728f; + else + iupStrToFloat(format, &fval); + + if (fval > 0) + { + fval = ((float)charformat->yHeight)*fval; + charformat->yHeight = iupROUND(fval); + } + } + + format = iupAttribGet(formattag, "FONTFACE"); + if (format) + { + charformat->dwMask |= CFM_FACE; + strcpy(charformat->szFaceName, format); + } + + format = iupAttribGet(formattag, "FGCOLOR"); + if (format) + { + unsigned char r, g, b; + if (iupStrToRGB(format, &r, &g, &b)) + { + charformat->dwMask |= CFM_COLOR; + charformat->crTextColor = RGB(r, g, b); + } + } + + format = iupAttribGet(formattag, "BGCOLOR"); + if (format) + { + unsigned char r, g, b; + if (iupStrToRGB(format, &r, &g, &b)) + { + charformat->dwMask |= CFM_BACKCOLOR; + charformat->crBackColor = RGB(r, g, b); + } + } + + format = iupAttribGet(formattag, "UNDERLINE"); + if (format) + { + charformat->dwMask |= CFM_UNDERLINETYPE; + + if (iupStrEqualNoCase(format, "SINGLE")) + charformat->bUnderlineType = CFU_UNDERLINE; + else if (iupStrEqualNoCase(format, "DOUBLE")) + charformat->bUnderlineType = CFU_UNDERLINEDOUBLE; + else if (iupStrEqualNoCase(format, "DOTTED")) + charformat->bUnderlineType = CFU_UNDERLINEDOTTED; + else /* "NONE" */ + charformat->bUnderlineType = CFU_UNDERLINENONE; + + if (charformat->bUnderlineType != CFU_UNDERLINENONE) + { + charformat->dwMask |= CFM_UNDERLINE; + charformat->dwEffects |= CFE_UNDERLINE; + } + } + + format = iupAttribGet(formattag, "WEIGHT"); + if (format) + { + charformat->dwMask |= CFM_WEIGHT; + + if (iupStrEqualNoCase(format, "EXTRALIGHT")) + charformat->wWeight = FW_EXTRALIGHT; + else if (iupStrEqualNoCase(format, "LIGHT")) + charformat->wWeight = FW_LIGHT; + else if (iupStrEqualNoCase(format, "SEMIBOLD")) + charformat->wWeight = FW_SEMIBOLD; + else if (iupStrEqualNoCase(format, "BOLD")) + charformat->wWeight = FW_BOLD; + else if (iupStrEqualNoCase(format, "EXTRABOLD")) + charformat->wWeight = FW_EXTRABOLD; + else if (iupStrEqualNoCase(format, "HEAVY")) + charformat->wWeight = FW_HEAVY; + else /* "NORMAL" */ + charformat->wWeight = FW_NORMAL; + + if (charformat->wWeight != FW_NORMAL) + { + charformat->dwMask |= CFM_BOLD; + charformat->dwEffects |= CFE_BOLD; + } + } +} + +static int winTextSetLinColToPosition(Ihandle *ih, int lin, int col) +{ + int linmax, colmax, lineindex; + + lin--; /* IUP starts at 1 */ + col--; + + linmax = SendMessage(ih->handle, EM_GETLINECOUNT, 0, 0L); + if (lin > linmax) + lin = linmax; + + lineindex = SendMessage(ih->handle, EM_LINEINDEX, (WPARAM)lin, 0L); + + colmax = SendMessage(ih->handle, EM_LINELENGTH, (WPARAM)lineindex, 0L); + if (col > colmax) + col = colmax; /* after the last character */ + + return lineindex + col; +} + +static void winTextGetLinColFromPosition(Ihandle* ih, int pos, int* lin, int* col) +{ + /* here "pos" must contains the extra chars if the case */ + int lineindex; + + if (ih->data->has_formatting) + *lin = SendMessage(ih->handle, EM_EXLINEFROMCHAR, (WPARAM)0, (LPARAM)pos); + else + *lin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L); + + lineindex = SendMessage(ih->handle, EM_LINEINDEX, (WPARAM)(*lin), (LPARAM)0L); + *col = pos - lineindex; /* lineindex is at the first character of the line */ + + (*lin)++; /* IUP starts at 1 */ + (*col)++; +} + +static int winTextRemoveExtraChars(Ihandle* ih, int pos) +{ + /* called only if not single line and not formatting */ + int lin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L); + pos -= lin; /* remove \r characters from count */ + return pos; +} + +static int winTextAddExtraChars(Ihandle* ih, int pos) +{ + /* called only if not single line and not formatting */ + int lin, clin; + + clin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L); + + /* pos is smaller than the actual pos (missing the \r count), + so we must calculate the line until the returned value is the same as the expected. */ + do + { + lin = clin; + clin = SendMessage(ih->handle, EM_LINEFROMCHAR, (WPARAM)(pos+lin+1), (LPARAM)0L); /* add one because we can be at the last character */ + } while (clin != lin); /* and it will not change to the next line by 1 */ + + pos += lin; /* add \r characters from count */ + return pos; +} + +static int winTextGetCaretPos(Ihandle* ih) +{ + int pos = 0; + POINT point; + + if (GetFocus() != ih->handle || !GetCaretPos(&point)) + { + /* if does not have the focus, or could not get caret position, + then use the selection start position */ + SendMessage(ih->handle, EM_GETSEL, (WPARAM)&pos, 0); + } + else + { + if (ih->data->has_formatting) + pos = SendMessage(ih->handle, EM_CHARFROMPOS, 0, (LPARAM)&point); + else + { + LRESULT ret; + + /* Workaround for weird behavior because of the return value in GetCaretPos */ + if (ih->data->is_multiline && point.y < 5) + point.y += 5; + + ret = SendMessage(ih->handle, EM_CHARFROMPOS, 0, MAKELPARAM(point.x, point.y)); + pos = LOWORD(ret); + } + } + + return pos; +} + +static int winTextGetCaret(Ihandle* ih, int *lin, int *col) +{ + int pos = winTextGetCaretPos(ih); + + if (ih->data->is_multiline) + { + winTextGetLinColFromPosition(ih, pos, lin, col); + + if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + pos = winTextRemoveExtraChars(ih, pos); + } + else + { + *col = pos; + (*col)++; /* IUP starts at 1 */ + *lin = 1; + } + + return pos; +} + +static void winTextGetSelection(Ihandle* ih, int *start, int *end) +{ + *start = 0; + *end = 0; + + SendMessage(ih->handle, EM_GETSEL, (WPARAM)start, (LPARAM)end); + + if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + { + (*start) = winTextRemoveExtraChars(ih, *start); + (*end) = winTextRemoveExtraChars(ih, *end); + } +} + +void iupdrvTextConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos) +{ + *pos = winTextSetLinColToPosition(ih, lin, col); + + if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + *pos = winTextRemoveExtraChars(ih, *pos); +} + +void iupdrvTextConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col) +{ + if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + pos = winTextAddExtraChars(ih, pos); + + winTextGetLinColFromPosition(ih, pos, lin, col); +} + +static int winTextConvertXYToPos(Ihandle* ih, int x, int y) +{ + int pos; + + if (ih->data->has_formatting) + { + POINT point; + point.x = x; + point.y = y; + pos = (int)SendMessage(ih->handle, EM_CHARFROMPOS, 0, (LPARAM)&point); + } + else + { + LRESULT ret = SendMessage(ih->handle, EM_CHARFROMPOS, 0, MAKELPARAM(x, y)); + pos = LOWORD(ret); + } + + if (ih->data->is_multiline) + { + if (!ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + pos = winTextRemoveExtraChars(ih, pos); + } + + return pos; +} + + +/***********************************************************************************************/ + + +static int winTextSetValueAttrib(Ihandle* ih, const char* value) +{ + char* str; + if (!value) value = ""; + str = (char*)value; + if (ih->data->is_multiline) + { + if (ih->data->has_formatting) + str = iupStrToMac(str); + else + str = iupStrToDos(str); + } + iupAttribSetStr(ih, "IUPWIN_IGNORECHANGE", "1"); + SetWindowText(ih->handle, str); + iupAttribSetStr(ih, "IUPWIN_IGNORECHANGE", NULL); + if (str != value) free(str); + return 0; +} + +static char* winTextGetValueAttrib(Ihandle* ih) +{ + int nc = GetWindowTextLength(ih->handle); + if (nc) + { + char* str = iupStrGetMemory(nc+1); + GetWindowText(ih->handle, str, nc+1); /* notice that this function always returns in DOS format */ + if (ih->data->is_multiline) + iupStrToUnix(str); + return str; + } + else + return ""; +} + +static int winTextSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &(ih->data->horiz_padding), &(ih->data->vert_padding), 'x'); + ih->data->vert_padding = 0; + if (ih->handle) + SendMessage(ih->handle, EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN, MAKELPARAM(ih->data->horiz_padding, ih->data->horiz_padding)); + return 0; +} + +static int winTextSetSelectedTextAttrib(Ihandle* ih, const char* value) +{ + if (value) + { + int start = 0, end = 0; + char* str; + + SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); + if (start == end) + return 0; + + str = (char*)value; + if (ih->data->is_multiline) + { + if (ih->data->has_formatting) + str = iupStrToMac(str); + else + str = iupStrToDos(str); + } + SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)str); + if (str != value) free(str); + } + return 0; +} + +static char* winTextGetSelectedTextAttrib(Ihandle* ih) +{ + int nc = GetWindowTextLength(ih->handle); + if (nc) + { + int start = 0, end = 0; + char* str; + + SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); + if (start == end) + return NULL; + + if (ih->data->has_formatting) + { + str = iupStrGetMemory(end-start+1); + SendMessage(ih->handle, EM_GETSELTEXT, 0, (LPARAM)str); + } + else + { + str = iupStrGetMemory(nc+1); + GetWindowText(ih->handle, str, nc+1); /* notice that this function always returns in DOS format */ + /* returns only the selected text */ + str[end] = 0; + str += start; + } + + if (ih->data->is_multiline) + iupStrToUnix(str); + return str; + } + else + return NULL; +} + +static int winTextSetNCAttrib(Ihandle* ih, const char* value) +{ + if (!iupStrToInt(value, &ih->data->nc)) + ih->data->nc = 0; + + if (ih->handle) + { + if (ih->data->has_formatting) + SendMessage(ih->handle, EM_EXLIMITTEXT, 0, ih->data->nc); /* so it can be larger than 64k */ + else + SendMessage(ih->handle, EM_LIMITTEXT, ih->data->nc, 0L); + } + return 0; +} + +static int winTextSetSelectionAttrib(Ihandle* ih, const char* value) +{ + int start=1, end=1; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + SendMessage(ih->handle, EM_SETSEL, (WPARAM)-1, (LPARAM)0); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + SendMessage(ih->handle, EM_SETSEL, (WPARAM)0, (LPARAM)-1); + return 0; + } + + if (ih->data->is_multiline) + { + int lin_start=1, col_start=1, lin_end=1, col_end=1; + + if (sscanf(value, "%d,%d:%d,%d", &lin_start, &col_start, &lin_end, &col_end)!=4) return 0; + if (lin_start<1 || col_start<1 || lin_end<1 || col_end<1) return 0; + + start = winTextSetLinColToPosition(ih, lin_start, col_start); + end = winTextSetLinColToPosition(ih, lin_end, col_end); + } + else + { + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<1 || end<1) + return 0; + + start--; /* IUP starts at 1 */ + end--; + } + + SendMessage(ih->handle, EM_SETSEL, (WPARAM)start, (LPARAM)end); + + return 0; +} + +static char* winTextGetSelectionAttrib(Ihandle* ih) +{ + int start = 0, end = 0; + char* str; + + SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); + if (start == end) + return NULL; + + str = iupStrGetMemory(100); + + if (ih->data->is_multiline) + { + int start_col, start_lin, end_col, end_lin; + winTextGetLinColFromPosition(ih, start, &start_lin, &start_col); + winTextGetLinColFromPosition(ih, end, &end_lin, &end_col); + sprintf(str,"%d,%d:%d,%d", start_lin, start_col, end_lin, end_col); + } + else + { + start++; /* IUP starts at 1 */ + end++; + sprintf(str, "%d:%d", start, end); + } + + return str; +} + +static int winTextSetSelectionPosAttrib(Ihandle* ih, const char* value) +{ + int start=0, end=0; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + SendMessage(ih->handle, EM_SETSEL, (WPARAM)-1, (LPARAM)0); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + SendMessage(ih->handle, EM_SETSEL, (WPARAM)0, (LPARAM)-1); + return 0; + } + + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<0 || end<0) + return 0; + + if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + { + start = winTextAddExtraChars(ih, start); + end = winTextAddExtraChars(ih, end); + } + + SendMessage(ih->handle, EM_SETSEL, (WPARAM)start, (LPARAM)end); + + return 0; +} + +static char* winTextGetSelectionPosAttrib(Ihandle* ih) +{ + int start = 0, end = 0; + char* str; + + SendMessage(ih->handle, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); + if (start == end) + return NULL; + + if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + { + start = winTextRemoveExtraChars(ih, start); + end = winTextRemoveExtraChars(ih, end); + } + + str = iupStrGetMemory(100); + + sprintf(str, "%d:%d", start, end); + + return str; +} + +static int winTextSetInsertAttrib(Ihandle* ih, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + if (value) + { + char* str = (char*)value; + if (ih->data->is_multiline) + { + if (ih->data->has_formatting) + str = iupStrToMac(str); + else + str = iupStrToDos(str); + } + + SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)str); + + if (str != value) free(str); + } + return 0; +} + +static int winTextSetAppendAttrib(Ihandle* ih, const char* value) +{ + int len; + char* str; + if (!ih->handle) /* do not store the action before map */ + return 0; + if (!value) value = ""; + str = (char*)value; + if (ih->data->is_multiline) + { + if (ih->data->has_formatting) + str = iupStrToMac(str); + else + str = iupStrToDos(str); + } + + len = GetWindowTextLength(ih->handle)+1; + SendMessage(ih->handle, EM_SETSEL, (WPARAM)len, (LPARAM)len); + if (ih->data->is_multiline && ih->data->append_newline) + { + if (ih->data->has_formatting) + SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)"\r"); + else + SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)"\r\n"); + } + SendMessage(ih->handle, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)str); + + if (str != value) free(str); + return 0; +} + +static int winTextSetReadOnlyAttrib(Ihandle* ih, const char* value) +{ + SendMessage(ih->handle, EM_SETREADONLY, (WPARAM)iupStrBoolean(value), 0); + return 0; +} + +static char* winTextGetReadOnlyAttrib(Ihandle* ih) +{ + DWORD style = GetWindowLong(ih->handle, GWL_STYLE); + if (style & ES_READONLY) + return "YES"; + else + return "NO"; +} + +static int winTextSetTabSizeAttrib(Ihandle* ih, const char* value) +{ + int tabsize; + if (!ih->data->is_multiline) + return 0; + + iupStrToInt(value, &tabsize); + tabsize *= 4; + SendMessage(ih->handle, EM_SETTABSTOPS, (WPARAM)1L, (LPARAM)&tabsize); + iupdrvDisplayRedraw(ih); + return 1; +} + +static int winTextSetCaretAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + + if (!value) + return 0; + + if (ih->data->is_multiline) + { + int lin = 1, col = 1; + iupStrToIntInt(value, &lin, &col, ','); /* be permissive in SetCaret, do not abort if invalid */ + if (lin < 1) lin = 1; + if (col < 1) col = 1; + + pos = winTextSetLinColToPosition(ih, lin, col); + } + else + { + sscanf(value,"%i",&pos); + if (pos < 1) pos = 1; + pos--; /* IUP starts at 1 */ + } + + SendMessage(ih->handle, EM_SETSEL, (WPARAM)pos, (LPARAM)pos); + SendMessage(ih->handle, EM_SCROLLCARET, 0L, 0L); + + return 0; +} + +static char* winTextGetCaretAttrib(Ihandle* ih) +{ + int col, lin; + char* str; + + str = iupStrGetMemory(100); + + winTextGetCaret(ih, &lin, &col); + + if (ih->data->is_multiline) + sprintf(str, "%d,%d", lin, col); + else + sprintf(str, "%d", col); + + return str; +} + +static int winTextSetCaretPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); /* be permissive in SetCaret, do not abort if invalid */ + if (pos < 0) pos = 0; + + if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + pos = winTextAddExtraChars(ih, pos); + + SendMessage(ih->handle, EM_SETSEL, (WPARAM)pos, (LPARAM)pos); + SendMessage(ih->handle, EM_SCROLLCARET, 0L, 0L); + + return 0; +} + +static char* winTextGetCaretPosAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(100); + int pos = winTextGetCaretPos(ih); + if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + pos = winTextRemoveExtraChars(ih, pos); + sprintf(str, "%d", pos); + return str; +} + +static int winTextSetScrollToAttrib(Ihandle* ih, const char* value) +{ + int lin = 1, col = 1; + + if (!value) + return 0; + + if (ih->data->is_multiline) + { + iupStrToIntInt(value, &lin, &col, ','); + if (lin < 1) lin = 1; + if (col < 1) col = 1; + } + else + { + sscanf(value,"%i",&col); + if (col < 1) col = 1; + } + + lin--; /* return to Windows referece */ + col--; + + if (ih->data->has_formatting) + SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)0, (LPARAM)lin); + else + SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)col, (LPARAM)lin); + + return 0; +} + +static int winTextSetScrollToPosAttrib(Ihandle* ih, const char* value) +{ + int lin, col, pos = 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + if (ih->data->is_multiline && !ih->data->has_formatting) /* when formatting or single line text uses only one char per line end */ + pos = winTextAddExtraChars(ih, pos); + + winTextGetLinColFromPosition(ih, pos, &lin, &col); + lin--; /* return to Windows referece */ + col--; + + if (ih->data->has_formatting) + SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)0, (LPARAM)lin); + else + SendMessage(ih->handle, EM_LINESCROLL, (WPARAM)col, (LPARAM)lin); + + return 0; +} + +static int winTextSetFilterAttrib(Ihandle *ih, const char *value) +{ + int style = 0; + + if (iupStrEqualNoCase(value, "LOWERCASE")) + { + if (ih->data->has_formatting) + { + SendMessage(ih->handle, EM_SETEDITSTYLE, SES_LOWERCASE, SES_LOWERCASE); + return 1; + } + style = ES_LOWERCASE; + } + else if (iupStrEqualNoCase(value, "NUMBER")) + style = ES_NUMBER; + else if (iupStrEqualNoCase(value, "UPPERCASE")) + { + if (ih->data->has_formatting) + { + SendMessage(ih->handle, EM_SETEDITSTYLE, SES_UPPERCASE, SES_UPPERCASE); + return 1; + } + style = ES_UPPERCASE; + } + + if (style) + iupwinMergeStyle(ih, ES_LOWERCASE|ES_NUMBER|ES_UPPERCASE, style); + + return 1; +} + +static int winTextSetClipboardAttrib(Ihandle *ih, const char *value) +{ + UINT msg = 0; + + if (iupStrEqualNoCase(value, "COPY")) + msg = WM_COPY; + else if (iupStrEqualNoCase(value, "CUT")) + msg = WM_CUT; + else if (iupStrEqualNoCase(value, "PASTE")) + msg = WM_PASTE; + else if (iupStrEqualNoCase(value, "CLEAR")) + msg = WM_CLEAR; + else if (iupStrEqualNoCase(value, "UNDO")) + msg = WM_UNDO; + else if (ih->data->has_formatting && iupStrEqualNoCase(value, "REDO")) + msg = EM_REDO; + + if (msg) + SendMessage(ih->handle, msg, 0, 0); + + return 0; +} + +static int winTextSetBgColorAttrib(Ihandle *ih, const char *value) +{ + if (ih->data->has_formatting) + { + unsigned char r, g, b; + if (iupStrToRGB(value, &r, &g, &b)) + { + COLORREF color; + color = RGB(r,g,b); + SendMessage(ih->handle, EM_SETBKGNDCOLOR, 0, (LPARAM)color); + } + } + return 1; +} + +static int winTextSetCueBannerAttrib(Ihandle *ih, const char *value) +{ + if (!ih->data->is_multiline && iupwin_comctl32ver6) + { + WCHAR* wstr = iupwinStrChar2Wide(value); + SendMessage(ih->handle, EM_SETCUEBANNER, (WPARAM)FALSE, (LPARAM)wstr); + free(wstr); + return 1; + } + return 0; +} + +static int winTextSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + int new_style; + + if (iupStrEqualNoCase(value, "ARIGHT")) + new_style = ES_RIGHT; + else if (iupStrEqualNoCase(value, "ACENTER")) + new_style = ES_CENTER; + else /* "ALEFT" */ + new_style = ES_LEFT; + + iupwinMergeStyle(ih, ES_LEFT|ES_CENTER|ES_RIGHT, new_style); + + return 1; +} + +static int winTextSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + /* ignore the first call that is done in IupMap, + it is already done before calling iupTextUpdateFormatTags. */ + if (ih->data->has_formatting && iupAttribGet(ih, "_IUPWIN_IGNORE_FONT")) + { + iupAttribSetStr(ih, "_IUPWIN_IGNORE_FONT", NULL); + return 0; + } + return iupdrvSetStandardFontAttrib(ih, value); +} + +void iupdrvTextAddFormatTag(Ihandle* ih, Ihandle* formattag) +{ + int convert2twips, pixel2twips; + char *selection, *units; + PARAFORMAT2 paraformat; + CHARFORMAT2 charformat; + + /* one twip is 1/1440 inch */ + /* twip = (pixel*1440)/(pixel/inch) */ + pixel2twips = 1440/iupwinGetScreenRes(); + + /* default is PIXELS */ + convert2twips = pixel2twips; + units = iupAttribGet(formattag, "UNITS"); + if (units) + { + int val; + if (iupStrEqualNoCase(units, "TWIPS")) + convert2twips = 1; + else if (iupStrToInt(units, &val)) + convert2twips = val; + } + + selection = iupAttribGet(formattag, "SELECTION"); + if (selection) + { + /* In Windows, the format message use the current selection */ + winTextSetSelectionAttrib(ih, selection); + iupAttribSetStr(ih, "SELECTION", NULL); + } + else + { + char* selectionpos = iupAttribGet(formattag, "SELECTIONPOS"); + if (selectionpos) + { + /* In Windows, the format message use the current selection */ + winTextSetSelectionPosAttrib(ih, selectionpos); + iupAttribSetStr(ih, "SELECTIONPOS", NULL); + } + } + + if (iupAttribGet(formattag, "FONTSCALE") && !iupAttribGet(formattag, "FONTSIZE")) + iupAttribSetStr(formattag, "FONTSIZE", iupGetFontSizeAttrib(ih)); + + winTextParseParagraphFormat(formattag, ¶format, convert2twips); + if (paraformat.dwMask != 0) + SendMessage(ih->handle, EM_SETPARAFORMAT, 0, (LPARAM)¶format); + + winTextParseCharacterFormat(formattag, &charformat, pixel2twips); + if (charformat.dwMask != 0) + SendMessage(ih->handle, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charformat); + + /* reset the selection, if changed here */ + if (selection) + winTextSetSelectionAttrib(ih, NULL); +} + +static int winTextSetRemoveFormattingAttrib(Ihandle* ih, const char* value) +{ + PARAFORMAT2 paraformat; + CHARFORMAT2 charformat; + COLORREF colorref; + int val; + + if (!ih->data->has_formatting) + return 0; + + ZeroMemory(¶format, sizeof(PARAFORMAT2)); + paraformat.cbSize = sizeof(PARAFORMAT2); + paraformat.dwMask = PFM_NUMBERING|PFM_STARTINDENT|PFM_RIGHTINDENT|PFM_OFFSET| + PFM_ALIGNMENT|PFM_SPACEBEFORE|PFM_SPACEAFTER|PFM_LINESPACING; + paraformat.wAlignment = PFA_LEFT; + + ZeroMemory(&charformat, sizeof(CHARFORMAT2)); + charformat.cbSize = sizeof(CHARFORMAT2); + charformat.dwMask = CFM_DISABLED|CFM_OFFSET|CFM_ITALIC|CFM_STRIKEOUT|CFM_PROTECTED| + CFM_UNDERLINETYPE|CFM_UNDERLINE|CFM_WEIGHT|CFM_FACE; + charformat.wWeight = FW_NORMAL; + strcpy(charformat.szFaceName, iupGetFontFaceAttrib(ih)); + + if (iupwinGetColorRef(ih, "FGCOLOR", &colorref)) + { + charformat.dwMask |= CFM_COLOR; + charformat.crTextColor = colorref; + } + + if (iupwinGetColorRef(ih, "BGCOLOR", &colorref)) + { + charformat.dwMask |= CFM_BACKCOLOR; + charformat.crBackColor = colorref; + } + + if (iupStrToInt(iupGetFontSizeAttrib(ih), &val)) + { + /* (1/1440 of an inch, or 1/20 of a printer's point) */ + charformat.dwMask |= CFM_SIZE; + if (val < 0) /* in pixels */ + { + int pixel2twips = 1440/iupwinGetScreenRes(); + charformat.yHeight = (-val)*pixel2twips; + } + else + charformat.yHeight = val*20; + } + + SendMessage(ih->handle, EM_SETPARAFORMAT, 0, (LPARAM)¶format); + SendMessage(ih->handle, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charformat); + + (void)value; + return 0; +} + +static int winTextSetOverwriteAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->has_formatting) + return 0; + + if (iupAttribGetBoolean(ih, "OVERWRITE")) + { + if (!iupStrBoolean(value)) + SendMessage(ih->handle, WM_KEYDOWN, VK_INSERT, 0); /* toggle from ON to OFF */ + } + else + { + if (iupStrBoolean(value)) + SendMessage(ih->handle, WM_KEYDOWN, VK_INSERT, 0); /* toggle from OFF to ON */ + } + return 1; +} + + +static int winTextSetVisibleAttrib(Ihandle* ih, const char* value) +{ + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + if (hSpin) + ShowWindow(hSpin, iupStrBoolean(value)? SW_SHOWNORMAL: SW_HIDE); + + return iupBaseSetVisibleAttrib(ih, value); +} + +static void winTextCropSpinValue(HWND hSpin, int min, int max) +{ + /* refresh if internally cropped, but text still shows an invalid value */ + int pos = SendMessage(hSpin, UDM_GETPOS32, 0, 0); + if (pos <= min) + SendMessage(hSpin, UDM_SETPOS32, 0, min); + if (pos >= max) + SendMessage(hSpin, UDM_SETPOS32, 0, max); +} + +static int winTextSetSpinMinAttrib(Ihandle* ih, const char* value) +{ + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + if (hSpin) + { + int min; + if (iupStrToInt(value, &min)) + { + int max = iupAttribGetInt(ih, "SPINMAX"); + SendMessage(hSpin, UDM_SETRANGE32, min, max); + + winTextCropSpinValue(hSpin, min, max); + } + } + return 1; +} + +static int winTextSetSpinMaxAttrib(Ihandle* ih, const char* value) +{ + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + if (hSpin) + { + int max; + if (iupStrToInt(value, &max)) + { + int min = iupAttribGetInt(ih, "SPINMIN"); + SendMessage(hSpin, UDM_SETRANGE32, min, max); + + winTextCropSpinValue(hSpin, min, max); + } + } + return 1; +} + +static int winTextSetSpinIncAttrib(Ihandle* ih, const char* value) +{ + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + if (hSpin) + { + int inc; + if (iupStrToInt(value, &inc)) + { + UDACCEL paAccels[3]; + paAccels[0].nInc = inc; + paAccels[0].nSec = 0; + paAccels[1].nInc = inc*5; + paAccels[1].nSec = 2; + paAccels[2].nInc = inc*20; + paAccels[2].nSec = 5; + SendMessage(hSpin, UDM_SETACCEL, 3, (LPARAM)paAccels); + } + } + return 1; +} + +static int winTextSetSpinValueAttrib(Ihandle* ih, const char* value) +{ + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + if (hSpin) + { + int pos; + if (iupStrToInt(value, &pos)) + SendMessage(hSpin, UDM_SETPOS32, 0, pos); + } + return 1; +} + +static char* winTextGetSpinValueAttrib(Ihandle* ih) +{ + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + if (hSpin) + { + int pos = SendMessage(hSpin, UDM_GETPOS32, 0, 0); + char *str = iupStrGetMemory(50); + sprintf(str, "%d", pos); + return str; + } + return NULL; +} + + +/****************************************************************************************/ + + +static int winTextCtlColor(Ihandle* ih, HDC hdc, LRESULT *result) +{ + COLORREF cr; + + if (iupwinGetColorRef(ih, "FGCOLOR", &cr)) + SetTextColor(hdc, cr); + + if (iupwinGetColorRef(ih, "BGCOLOR", &cr)) + { + SetBkColor(hdc, cr); + SetDCBrushColor(hdc, cr); + *result = (LRESULT)GetStockObject(DC_BRUSH); + return 1; + } + return 0; +} + +static void winTextCallCaretCb(Ihandle* ih) +{ + int col, lin, pos; + + IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB"); + if (!cb) return; + + pos = winTextGetCaret(ih, &lin, &col); + + if (pos != ih->data->last_caret_pos) + { + ih->data->last_caret_pos = pos; + + cb(ih, lin, col, pos); + } +} + +static int winTextCallActionCb(Ihandle* ih, const char* insert_value, int key, int dir) +{ + int start, end, ret = 1; + char *value, *new_value; + + IFnis cb = (IFnis)IupGetCallback(ih, "ACTION"); + if (!cb && !ih->data->mask) + return 1; + + winTextGetSelection(ih, &start, &end); + + value = winTextGetValueAttrib(ih); + + if (value[0]==0) + new_value = iupStrDup(insert_value); + else if (insert_value) + new_value = iupStrInsert(value, insert_value, start, end); + else + { + new_value = value; + iupStrRemove(value, start, end, dir); + } + + if (!new_value) + return 0; /* abort */ + + if (ih->data->nc && (int)strlen(new_value) > ih->data->nc) + { + if (new_value != value) free(new_value); + return 0; /* abort */ + } + + if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0) + { + if (new_value != value) free(new_value); + return 0; /* abort */ + } + + if (cb) + { + int cb_ret = cb(ih, key, (char*)new_value); + if (cb_ret==IUP_IGNORE) + ret = 0; /* abort processing */ + else if (cb_ret==IUP_CLOSE) + { + IupExitLoop(); + ret = 0; /* abort processing */ + } + else if (cb_ret!=0 && key!=0 && + cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE) + { + WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB"); + CallWindowProc(oldProc, ih->handle, WM_CHAR, cb_ret, 0); /* replace key */ + ret = 0; /* abort processing */ + } + } + + if (new_value != value) free(new_value); + return ret; +} + +static int winTextSpinWmNotify(Ihandle* ih, NMHDR* msg_info, int *result) +{ + if (msg_info->code == UDN_DELTAPOS) + { + NMUPDOWN *updown = (NMUPDOWN*)msg_info; + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + int pos = updown->iPos+updown->iDelta; + int min, max; + SendMessage(hSpin, UDM_GETRANGE32, (WPARAM)&min, (LPARAM)&max); + if (pos>=min && pos<=max) + { + IFni cb = (IFni) IupGetCallback(ih, "SPIN_CB"); + if (cb) + { + int ret = cb(ih, pos); + if (ret == IUP_IGNORE) + { + *result = 1; + return 1; + } + } + } + } + + (void)result; + return 0; /* result not used */ +} + +static int winTextProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) +{ + int ret = 0; + + if (msg==WM_KEYDOWN) /* process K_ANY before text callbacks */ + { + ret = iupwinBaseProc(ih, msg, wp, lp, result); + if (ret) + { + *result = 0; + return 1; + } + } + + switch (msg) + { + case WM_CHAR: + { + if ((char)wp == '\b') + { + if (!winTextCallActionCb(ih, NULL, 0, -1)) + ret = 1; + } + else if ((char)wp == '\n' || (char)wp == '\r') + { + if (!ih->data->has_formatting && !(GetKeyState(VK_CONTROL) & 0x8000)) /* when formatting is processed in WM_KEYDOWN */ + { + char insert_value[2]; + insert_value[0] = '\n'; + insert_value[1] = 0; + + if (!winTextCallActionCb(ih, insert_value, wp, 1)) + ret = 1; + } + } + else if (!(GetKeyState(VK_CONTROL) & 0x8000 || + GetKeyState(VK_MENU) & 0x8000 || + GetKeyState(VK_LWIN) & 0x8000 || + GetKeyState(VK_RWIN) & 0x8000)) + { + char insert_value[2]; + insert_value[0] = (char)wp; + insert_value[1] = 0; + + if (!winTextCallActionCb(ih, insert_value, wp, 1)) + ret = 1; + } + + PostMessage(ih->handle, WM_CARET, 0, 0L); + + if (!ih->data->is_multiline && + (wp==VK_RETURN || wp==VK_ESCAPE || wp==VK_TAB)) /* the keys have the same definitions as the chars */ + ret = 1; /* abort default processing to avoid beep */ + + if (ih->data->is_multiline && + (wp=='\n' && (GetKeyState(VK_CONTROL) & 0x8000))) + ret = 1; /* abort default processing to avoid inserting a new line */ + + break; + } + case WM_KEYDOWN: + { + if (wp == VK_DELETE) /* Del does not generates a WM_CHAR */ + { + if (!winTextCallActionCb(ih, NULL, 0, 1)) + ret = 1; + } + else if (wp == VK_INSERT && ih->data->has_formatting) + { + if (iupAttribGetBoolean(ih, "OVERWRITE")) + iupAttribSetStr(ih, "OVERWRITE", "OFF"); /* toggle from ON to OFF */ + else + iupAttribSetStr(ih, "OVERWRITE", "ON"); /* toggle from OFF to ON */ + } + else if (wp == 'A' && GetKeyState(VK_CONTROL) & 0x8000) /* Ctrl+A = Select All */ + { + SendMessage(ih->handle, EM_SETSEL, (WPARAM)0, (LPARAM)-1); + } + else if (wp == VK_RETURN && ih->data->has_formatting && !(GetKeyState(VK_CONTROL) & 0x8000)) + { + char insert_value[2]; + insert_value[0] = '\n'; + insert_value[1] = 0; + + if (!winTextCallActionCb(ih, insert_value, '\n', 1)) + ret = 1; + } + + PostMessage(ih->handle, WM_CARET, 0, 0L); + + if (ret) /* if abort processing, then the result is 0 */ + { + *result = 0; + return 1; + } + else + return 0; /* already processed at the begining of this function */ + } + case WM_KEYUP: + { + PostMessage(ih->handle, WM_CARET, 0, 0L); + break; + } + case WM_CLEAR: + { + if (!winTextCallActionCb(ih, NULL, 0, 1)) + ret = 1; + + PostMessage(ih->handle, WM_CARET, 0, 0L); + break; + } + case WM_CUT: + { + if (!winTextCallActionCb(ih, NULL, 0, 1)) + ret = 1; + + PostMessage(ih->handle, WM_CARET, 0, 0L); + break; + } + case WM_PASTE: + { + if (IupGetCallback(ih,"ACTION") || ih->data->mask) /* test before to avoid alocate clipboard text memory */ + { + char* insert_value = iupwinGetClipboardText(ih); + if (insert_value) + { + if (!winTextCallActionCb(ih, insert_value, 0, 1)) + ret = 1; + free(insert_value); + } + } + + PostMessage(ih->handle, WM_CARET, 0, 0L); + break; + } + case WM_UNDO: + { + IFnis cb = (IFnis)IupGetCallback(ih, "ACTION"); + if (cb) + { + char* value; + WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_OLDPROC_CB"); + CallWindowProc(oldProc, ih->handle, WM_UNDO, 0, 0); + + value = winTextGetValueAttrib(ih); + cb(ih, 0, (char*)value); + + ret = 1; + } + + PostMessage(ih->handle, WM_CARET, 0, 0L); + break; + } + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + { + if (iupwinButtonDown(ih, msg, wp, lp)==-1) + { + *result = 0; + return 1; + } + PostMessage(ih->handle, WM_CARET, 0, 0L); + break; + } + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONUP: + { + if (iupwinButtonUp(ih, msg, wp, lp)==-1) + { + *result = 0; + return 1; + } + PostMessage(ih->handle, WM_CARET, 0, 0L); + break; + } + case WM_CARET: + { + winTextCallCaretCb(ih); + break; + } + case WM_MOUSEMOVE: + { + iupwinMouseMove(ih, msg, wp, lp); + break; + } + case WM_VSCROLL: + case WM_HSCROLL: + { + if (ih->data->has_formatting) + { + /* fix weird behavior when dialog has COMPOSITE=YES, + scrollbars are not updated when dragging */ + if (LOWORD(wp) == SB_THUMBTRACK) + SendMessage(ih->handle, EM_SHOWSCROLLBAR, msg==WM_VSCROLL? SB_VERT: SB_HORZ, TRUE); + } + break; + } + } + + if (ret) /* if abort processing, then the result is 0 */ + { + *result = 0; + return 1; + } + else + return iupwinBaseProc(ih, msg, wp, lp, result); +} + +static void winTextCreateSpin(Ihandle* ih) +{ + HWND hSpin; + DWORD dwStyle = WS_CHILD|UDS_ARROWKEYS|UDS_HOTTRACK|UDS_NOTHOUSANDS; + int serial = iupDialogGetChildId(ih); + + if (iupStrEqualNoCase(iupAttribGetStr(ih, "SPINALIGN"), "LEFT")) + dwStyle |= UDS_ALIGNLEFT; + else + dwStyle |= UDS_ALIGNRIGHT; + + if (iupAttribGetBoolean(ih, "SPINWRAP")) + dwStyle |= UDS_WRAP; + + if (iupAttribGetBoolean(ih, "SPINAUTO")) + dwStyle |= UDS_SETBUDDYINT; + + hSpin = CreateWindowEx(0, /* extended window style */ + UPDOWN_CLASS, /* window class */ + NULL, /* title */ + dwStyle, /* window style */ + 0, /* x-position */ + 0, /* y-position */ + 10, /* default width to avoid 0 */ + 10, /* default height to avoid 0 */ + GetParent(ih->handle), /* window parent */ + (HMENU)serial, /* child identifier */ + iupwin_hinstance, /* instance of app. */ + NULL); + + if (!hSpin) + return; + + iupwinHandleAdd(ih, hSpin); + + /* Process WM_NOTIFY */ + IupSetCallback(ih, "_IUPWIN_NOTIFY_CB", (Icallback)winTextSpinWmNotify); + + SendMessage(hSpin, UDM_SETBUDDY, (WPARAM)ih->handle, 0); + iupAttribSetStr(ih, "_IUPWIN_SPIN", (char*)hSpin); + + /* default values */ + SendMessage(hSpin, UDM_SETRANGE32, 0, 100); + SendMessage(hSpin, UDM_SETPOS32, 0, 0); +} + +static int winTextWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp) +{ + int cmd = HIWORD(wp); + switch (cmd) + { + case EN_CHANGE: + { + if (iupAttribGetStr(ih, "IUPWIN_IGNORECHANGE")) + return 0; + + iupBaseCallValueChangedCb(ih); + break; + } + } + + (void)lp; + return 0; /* not used */ +} + +static void winTextLayoutUpdateMethod(Ihandle* ih) +{ + HWND hSpin = (HWND)iupAttribGet(ih, "_IUPWIN_SPIN"); + if (hSpin) + { + if (iupStrEqualNoCase(iupAttribGetStr(ih, "SPINALIGN"), "LEFT")) + { + SetWindowPos(ih->handle, NULL, ih->x+ih->currentheight-1, ih->y, ih->currentwidth-ih->currentheight, ih->currentheight, + SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER); + + SetWindowPos(hSpin, NULL, ih->x, ih->y, ih->currentheight, ih->currentheight, + SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER); + } + else + { + SetWindowPos(ih->handle, NULL, ih->x, ih->y, ih->currentwidth-ih->currentheight, ih->currentheight, + SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER); + + SetWindowPos(hSpin, NULL, ih->x+ih->currentwidth-ih->currentheight-1, ih->y, ih->currentheight, ih->currentheight, + SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER); + } + } + else + iupdrvBaseLayoutUpdateMethod(ih); +} + +static int winTextMapMethod(Ihandle* ih) +{ + DWORD dwStyle = WS_CHILD, + dwExStyle = 0; + char* winclass = "EDIT", *value; + + if (!ih->parent) + return IUP_ERROR; + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + dwStyle |= WS_TABSTOP; + + if (ih->data->has_formatting) + { + /* enable richedit 3.0 */ + static HMODULE richedit = NULL; + if (!richedit) + richedit = LoadLibrary("Riched20.dll"); + if (!richedit) + return IUP_ERROR; + + winclass = RICHEDIT_CLASS; + } + + if (ih->data->is_multiline) + { + dwStyle |= ES_AUTOVSCROLL|ES_MULTILINE|ES_WANTRETURN; + + if (iupAttribGetBoolean(ih, "WORDWRAP")) + { + ih->data->sb &= ~IUP_SB_HORIZ; /* must remove the horizontal scroolbar */ + /* and do not specify ES_AUTOHSCROLL, the control automatically wraps words */ + } + else + dwStyle |= ES_AUTOHSCROLL; + + if (ih->data->sb & IUP_SB_HORIZ) + dwStyle |= WS_HSCROLL; + if (ih->data->sb & IUP_SB_VERT) + dwStyle |= WS_VSCROLL; + + if (ih->data->has_formatting && ih->data->sb != IUP_SB_NONE) + { + if (!iupAttribGetBoolean(ih, "AUTOHIDE")) + dwStyle |= ES_DISABLENOSCROLL; + } + } + else + { + dwStyle |= ES_AUTOHSCROLL|ES_NOHIDESEL; + + if (iupAttribGetBoolean(ih, "PASSWORD")) + dwStyle |= ES_PASSWORD; + } + + value = iupAttribGet(ih, "ALIGNMENT"); + if (value) + { + if (iupStrEqualNoCase(value, "ARIGHT")) + dwStyle |= ES_RIGHT; + else if (iupStrEqualNoCase(value, "ACENTER")) + dwStyle |= ES_CENTER; + else /* default "ALEFT" */ + dwStyle |= ES_LEFT; + } + + if (iupAttribGetBoolean(ih, "BORDER")) + dwExStyle |= WS_EX_CLIENTEDGE; + + if (!iupwinCreateWindowEx(ih, winclass, dwExStyle, dwStyle)) + return IUP_ERROR; + + /* Process ACTION_CB and CARET_CB */ + IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winTextProc); + + /* Process background color */ + IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winTextCtlColor); + + /* Process WM_COMMAND */ + IupSetCallback(ih, "_IUPWIN_COMMAND_CB", (Icallback)winTextWmCommand); + + /* set defaults */ + SendMessage(ih->handle, EM_LIMITTEXT, 0, 0L); + { + int tabsize = 8*4; + SendMessage(ih->handle, EM_SETTABSTOPS, (WPARAM)1L, (LPARAM)&tabsize); + } + + if (!ih->data->is_multiline && iupAttribGetBoolean(ih, "SPIN")) + winTextCreateSpin(ih); + + /* configure for DRAG&DROP */ + if (IupGetCallback(ih, "DROPFILES_CB")) + iupAttribSetStr(ih, "DRAGDROP", "YES"); + + if (ih->data->has_formatting) + { + SendMessage(ih->handle, EM_SETTEXTMODE, (WPARAM)(TM_RICHTEXT|TM_MULTILEVELUNDO|TM_SINGLECODEPAGE), 0); + SendMessage(ih->handle, EM_SETEVENTMASK, 0, ENM_CHANGE); + } + + if (ih->data->formattags) + { + /* must update FONT before updating the format during map */ + iupUpdateStandardFontAttrib(ih); + iupAttribSetStr(ih, "_IUPWIN_IGNORE_FONT", "1"); + + iupTextUpdateFormatTags(ih); + } + + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)winTextConvertXYToPos); + + return IUP_NOERROR; +} + +void iupdrvTextInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = winTextMapMethod; + ic->LayoutUpdate = winTextLayoutUpdateMethod; + + /* Driver Dependent Attribute functions */ + + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, winTextSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winTextSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "VISIBLE", iupBaseGetVisibleAttrib, winTextSetVisibleAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_NOT_MAPPED); /* usually black */ + + /* IupText only */ + iupClassRegisterAttribute(ic, "PADDING", iupTextGetPaddingAttrib, winTextSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "VALUE", winTextGetValueAttrib, winTextSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTEDTEXT", winTextGetSelectedTextAttrib, winTextSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTION", winTextGetSelectionAttrib, winTextSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTIONPOS", winTextGetSelectionPosAttrib, winTextSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARET", winTextGetCaretAttrib, winTextSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARETPOS", winTextGetCaretPosAttrib, winTextSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INSERT", NULL, winTextSetInsertAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "APPEND", NULL, winTextSetAppendAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "READONLY", winTextGetReadOnlyAttrib, winTextSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "NC", iupTextGetNCAttrib, winTextSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, winTextSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTO", NULL, winTextSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, winTextSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINMIN", NULL, winTextSetSpinMinAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINMAX", NULL, winTextSetSpinMaxAttrib, IUPAF_SAMEASSYSTEM, "100", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPININC", NULL, winTextSetSpinIncAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINVALUE", winTextGetSpinValueAttrib, winTextSetSpinValueAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT); + + /* IupText Windows and GTK only */ + iupClassRegisterAttribute(ic, "ADDFORMATTAG", NULL, iupTextSetAddFormatTagAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ADDFORMATTAG_HANDLE", NULL, iupTextSetAddFormatTagHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, winTextSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ALEFT", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FORMATTING", iupTextGetFormattingAttrib, iupTextSetFormattingAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "OVERWRITE", NULL, winTextSetOverwriteAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "REMOVEFORMATTING", NULL, winTextSetRemoveFormattingAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TABSIZE", NULL, winTextSetTabSizeAttrib, IUPAF_SAMEASSYSTEM, "8", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "PASSWORD", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); + + /* IupText Windows only */ + iupClassRegisterAttribute(ic, "CUEBANNER", NULL, winTextSetCueBannerAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FILTER", NULL, winTextSetFilterAttrib, NULL, NULL, IUPAF_NO_INHERIT); +} diff --git a/iup/src/win/iupwin_timer.c b/iup/src/win/iupwin_timer.c new file mode 100755 index 0000000..f2bb9c5 --- /dev/null +++ b/iup/src/win/iupwin_timer.c @@ -0,0 +1,88 @@ +/** \file + * \brief Timer for the Windows Driver. + * + * See Copyright Notice in "iup.h" + */ + +#include + +#include +#include + +#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 + +#include +#include + +#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 +#include + +#include +#include +#include +#include +#include + +#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 +#include + +#include +#include +#include +#include +#include + +#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; idata->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 +#include + +#include +#include +#include +#include +#include +#include + +#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 +#include + +#include +#include + +#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 +#include + +/* This module should depend only on IUP core headers + and Windows system headers. */ + +#include + +#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 + +#include /* 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 , except for Cygwin. */ +#ifdef __GNUC__ + extern int __argc; + extern char** __argv; +#endif + return main(__argc, __argv); + } +#endif +} +#endif -- cgit v1.2.3