Mercurial > install
changeset 10:dd61d68f3b75
Update to the latest DW and a few minor fixes.
author | Brian Smith <brian@dbsoft.org> |
---|---|
date | Wed, 25 Jul 2012 00:05:29 -0500 |
parents | bd8f2c281cae |
children | 9b5da2f35bee |
files | dw.h os2/dw.c rexx.c sfxace/makefile.vac win/dw.c |
diffstat | 5 files changed, 5607 insertions(+), 2379 deletions(-) [+] |
line wrap: on
line diff
--- a/dw.h Sun Nov 20 11:11:53 2011 -0600 +++ b/dw.h Wed Jul 25 00:05:29 2012 -0500 @@ -1,11 +1,11 @@ -/* $Id: dw.h 1311 2011-11-03 23:34:10Z bsmith $ */ +/* $Id: dw.h 1790 2012-07-24 22:52:57Z bsmith $ */ #ifndef _H_DW #define _H_DW /* Dynamic Windows version numbers */ #define DW_MAJOR_VERSION 2 -#define DW_MINOR_VERSION 1 +#define DW_MINOR_VERSION 4 #define DW_SUB_VERSION 0 #if !defined(__PHOTON__) @@ -57,6 +57,14 @@ #define DW_MIS_CHECKED (1 << 2) #define DW_MIS_UNCHECKED (1 << 3) +/* Gravity */ +#define DW_GRAV_TOP 0 +#define DW_GRAV_LEFT 0 +#define DW_GRAV_CENTER 1 +#define DW_GRAV_RIGHT 2 +#define DW_GRAV_BOTTOM 2 +#define DW_GRAV_OBSTACLES (1 << 10) + /* ensure we can build the Gtk port with MingW on Windows */ #if defined(DW_USE_GTK) && defined(__MINGW32__) # ifndef GDK_WINDOWING_WIN32 @@ -67,8 +75,10 @@ #if defined(__OS2__) || (defined(__WIN32__) && !defined(GDK_WINDOWING_WIN32)) || defined(__MAC__) || (defined(WINNT) && !defined(GDK_WINDOWING_WIN32)) || defined(__EMX__) /* OS/2, Windows or MacOS */ -#if (defined(__IBMC__) || defined(_System)) && !defined(API) -#define API _System +#ifdef __OS2__ +# if (defined(__IBMC__) || defined(__WATCOMC__) || defined(_System)) && !defined(API) +# define API _System +# endif #endif /* Used internally */ @@ -79,7 +89,6 @@ #define SIZEEXPAND 1 #define SPLITBAR_WIDTH 4 -#define BUBBLE_HELP_MAX 256 typedef struct _user_data { @@ -124,13 +133,9 @@ #define DW_FCF_MINBUTTON FCF_MINBUTTON #define DW_FCF_MAXBUTTON FCF_MAXBUTTON #define DW_FCF_MINMAX FCF_MINMAX -#define DW_FCF_VERTSCROLL FCF_VERTSCROLL -#define DW_FCF_HORZSCROLL FCF_HORZSCROLL #define DW_FCF_DLGBORDER FCF_DLGBORDER #define DW_FCF_BORDER FCF_BORDER -#define DW_FCF_SHELLPOSITION FCF_SHELLPOSITION #define DW_FCF_TASKLIST FCF_TASKLIST -#define DW_FCF_NOBYTEALIGN FCF_NOBYTEALIGN #define DW_FCF_NOMOVEWITHOWNER FCF_NOMOVEWITHOWNER #define DW_FCF_SYSMODAL FCF_SYSMODAL #define DW_FCF_HIDEBUTTON FCF_HIDEBUTTON @@ -167,8 +172,6 @@ #define DW_BS_NOBORDER BS_NOBORDER -#define DW_OS2_NEW_WINDOW 1 - /* flag values for dw_messagebox() */ #define DW_MB_OK MB_OK #define DW_MB_OKCANCEL MB_OKCANCEL @@ -222,12 +225,15 @@ #define VK_LMENU VK_MENU #define VK_RMENU VK_MENU +#define BUBBLE_HELP_MAX 256 + typedef struct _window_data { PFNWP oldproc; UserData *root; HWND clickdefault; ULONG flags; void *data; + char bubbletext[BUBBLE_HELP_MAX]; } WindowData; typedef struct _hpixmap { @@ -237,6 +243,7 @@ HBITMAP hbm; HWND handle, font; unsigned long transcolor; + int depth; } *HPIXMAP; typedef void *HTREEITEM; @@ -336,13 +343,9 @@ #define DW_FCF_MINBUTTON (1 << 2) /* NSMiniaturizableWindowMask */ #define DW_FCF_MAXBUTTON 0 #define DW_FCF_MINMAX (1 << 2) /* NSMiniaturizableWindowMask */ -#define DW_FCF_VERTSCROLL 0 -#define DW_FCF_HORZSCROLL 0 #define DW_FCF_DLGBORDER 0 #define DW_FCF_BORDER 0 -#define DW_FCF_SHELLPOSITION 0 #define DW_FCF_TASKLIST 0 -#define DW_FCF_NOBYTEALIGN 0 #define DW_FCF_NOMOVEWITHOWNER 0 #define DW_FCF_SYSMODAL 0 #define DW_FCF_HIDEBUTTON 0 @@ -484,12 +487,8 @@ #include <commctrl.h> #if defined(MSVC) && !defined(API) -# ifdef __MINGW32__ -# ifdef BUILD_DLL -# define API APIENTRY __declspec(dllexport) -# else -# define API APIENTRY __declspec(dllimport) -# endif +# if defined(__MINGW32__) && defined(BUILD_DLL) +# define API _cdecl __declspec(dllexport) # else # define API _cdecl #endif @@ -519,13 +518,9 @@ #define DW_FCF_MINBUTTON WS_MINIMIZEBOX #define DW_FCF_MAXBUTTON WS_MAXIMIZEBOX #define DW_FCF_MINMAX (WS_MINIMIZEBOX|WS_MAXIMIZEBOX) -#define DW_FCF_VERTSCROLL WS_VSCROLL -#define DW_FCF_HORZSCROLL WS_HSCROLL #define DW_FCF_DLGBORDER WS_DLGFRAME #define DW_FCF_BORDER WS_BORDER -#define DW_FCF_SHELLPOSITION 0 -#define DW_FCF_TASKLIST WS_VSCROLL -#define DW_FCF_NOBYTEALIGN 0 +#define DW_FCF_TASKLIST (1 << 1) #define DW_FCF_NOMOVEWITHOWNER 0 #define DW_FCF_SYSMODAL 0 #define DW_FCF_HIDEBUTTON WS_MINIMIZEBOX @@ -533,6 +528,7 @@ #define DW_FCF_AUTOICON 0 #define DW_FCF_MAXIMIZE WS_MAXIMIZE #define DW_FCF_MINIMIZE WS_MINIMIZE +#define DW_FCF_COMPOSITED 1 #define DW_CFA_BITMAPORICON 1 #define DW_CFA_STRING (1 << 1) @@ -578,22 +574,6 @@ #define KC_SHIFT (1 << 1) #define KC_ALT (1 << 2) -#define STATICCLASSNAME "STATIC" -#define COMBOBOXCLASSNAME "COMBOBOX" -#define LISTBOXCLASSNAME "LISTBOX" -#define BUTTONCLASSNAME "BUTTON" -#define POPUPMENUCLASSNAME "POPUPMENU" -#define EDITCLASSNAME "EDIT" -#define FRAMECLASSNAME "FRAME" -#define SCROLLBARCLASSNAME "SCROLLBAR" - -#define ClassName "dynamicwindows" -#define SplitbarClassName "dwsplitbar" -#define ObjectClassName "dwobjectclass" -#define BrowserClassName "dwbrowserclass" -#define ScrollClassName "dwscrollclass" -#define DefaultFont NULL - typedef struct _color { int fore; int back; @@ -653,8 +633,6 @@ int hsize, vsize; /* Padding */ int pad; - /* Ratio of current item */ - float xratio, yratio; } Item; typedef struct _box { @@ -670,16 +648,16 @@ int count; /* Box type - horizontal or vertical */ int type; + /* Keep track of how box is packed */ + int hsize, vsize; /* Padding */ - int pad, parentpad, grouppadx, grouppady; + int pad, grouppadx, grouppady; /* Groupbox */ HWND grouphwnd; /* Default item */ HWND defaultitem; /* Used as temporary storage in the calculation stage */ - int upx, upy, minheight, minwidth; - /* Ratio in this box */ - float xratio, yratio, parentxratio, parentyratio; + int usedpadx, usedpady, minheight, minwidth; /* Used for calculating individual item ratios */ int width, height; /* Any combinations of flags describing the box */ @@ -688,20 +666,6 @@ struct _item *items; } Box; -typedef struct _bubblebutton { -#if defined(__WIN32__) || defined(WINNT) - ColorInfo cinfo; - int checkbox; - WNDPROC pOldProc; -#endif -#if defined(__OS2__) || defined(__EMX__) - PFNWP pOldProc; - UserData *root; - unsigned long id; - char bubbletext[BUBBLE_HELP_MAX]; -#endif -} BubbleButton; - #elif defined(__PHOTON__) #include <stdio.h> #include <stdlib.h> @@ -817,13 +781,9 @@ #define DW_FCF_MINBUTTON Ph_WM_RENDER_MIN #define DW_FCF_MAXBUTTON Ph_WM_RENDER_MAX #define DW_FCF_MINMAX (Ph_WM_RENDER_MIN|Ph_WM_RENDER_MAX) -#define DW_FCF_VERTSCROLL 0 -#define DW_FCF_HORZSCROLL 0 #define DW_FCF_DLGBORDER 0 #define DW_FCF_BORDER Ph_WM_RENDER_BORDER -#define DW_FCF_SHELLPOSITION 0 #define DW_FCF_TASKLIST 0 -#define DW_FCF_NOBYTEALIGN 0 #define DW_FCF_NOMOVEWITHOWNER 0 #define DW_FCF_SYSMODAL 0 #define DW_FCF_HIDEBUTTON 0 @@ -1002,13 +962,9 @@ #define DW_FCF_MINBUTTON (1 << 4) #define DW_FCF_MAXBUTTON (1 << 5) #define DW_FCF_MINMAX (1 << 6) -#define DW_FCF_VERTSCROLL (1 << 7) -#define DW_FCF_HORZSCROLL (1 << 8) #define DW_FCF_DLGBORDER (1 << 9) #define DW_FCF_BORDER (1 << 10) -#define DW_FCF_SHELLPOSITION (1 << 11) #define DW_FCF_TASKLIST (1 << 12) -#define DW_FCF_NOBYTEALIGN (1 << 13) #define DW_FCF_NOMOVEWITHOWNER (1 << 14) #define DW_FCF_SYSMODAL (1 << 15) #define DW_FCF_HIDEBUTTON (1 << 16) @@ -1361,7 +1317,12 @@ /* Obsolete, should disappear sometime */ #define BOXHORZ DW_HORZ #define BOXVERT DW_VERT +#define DW_FCF_SHELLPOSITION 0 +#define DW_FCF_NOBYTEALIGN 0 +#define DW_FCF_VERTSCROLL 0 +#define DW_FCF_HORZSCROLL 0 +/* Scrolling constants */ #define DW_SCROLL_UP 0 #define DW_SCROLL_DOWN 1 #define DW_SCROLL_TOP 2 @@ -1414,11 +1375,11 @@ #define DW_HTML_STOP 5 #define DW_HTML_PRINT 6 -/* Drawing flags... used for Arc currently */ +/* Drawing flags */ #define DW_DRAW_DEFAULT 0 #define DW_DRAW_FILL 1 #define DW_DRAW_FULL (1 << 1) - +#define DW_DRAW_NOAA (1 << 2) /* Macro for casting resource IDs to HICN */ #define DW_RESOURCE(a) (a < 65536 ? (HICN)a : (HICN)0) @@ -1436,6 +1397,11 @@ #define DW_UINT_TO_POINTER(a) ((void *)a) #define DW_POINTER_TO_UINT(a) ((unsigned int)a) #endif +#define DW_POINTER(a) ((void *)a) + +#ifndef DW_FCF_COMPOSITED +#define DW_FCF_COMPOSITED 0 +#endif #ifndef API #define API @@ -1443,6 +1409,14 @@ #define DWSIGNAL API +/* Constants for sizing scrolled widgets */ +#define _DW_SCROLLED_MIN_WIDTH 100 +#define _DW_SCROLLED_MIN_HEIGHT 75 +#define _DW_SCROLLED_MAX_WIDTH 500 +#define _DW_SCROLLED_MAX_HEIGHT 400 + +#include <wchar.h> + /* Let other APIs know what types we've defined, * Regina REXX in particular, on Unix. */ @@ -1457,10 +1431,43 @@ #define UINT_TYPEDEFED 1 #define INT_TYPEDEFED 1 +/* Support for API deprecation in supported compilers */ +#if defined(__has_feature) && !defined(__has_extension) +#define __has_extension __has_feature +#endif + +/* Visual C */ +#if defined(_MSC_VER) +# if _MSC_VER >= 1400 +# define DW_DEPRECATED(func, message) __declspec(deprecated(message)) func +# endif +/* Clang */ +#elif defined(__has_extension) +# if __has_extension(attribute_deprecated_with_message) +# define DW_DEPRECATED(func, message) func __attribute__ ((deprecated (message))) +# else +# define DW_DEPRECATED(func, message) func __attribute__ ((deprecated)) +# endif +/* GCC */ +#elif defined(__GNUC__) +# if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40500 +# define DW_DEPRECATED(func, message) func __attribute__ ((deprecated (message))) +# else +# define DW_DEPRECATED(func, message) func __attribute__ ((deprecated)) +# endif +#endif + +/* Compiler without deprecation support */ +#ifndef DW_DEPRECATED +#define DW_DEPRECATED(func, message) func +#endif + /* Public function prototypes */ void API dw_box_pack_start(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad); void API dw_box_pack_end(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad); void API dw_box_pack_at_index(HWND box, HWND item, int index, int width, int height, int hsize, int vsize, int pad); +HWND API dw_box_unpack_at_index(HWND box, int index); +int API dw_box_unpack(HWND handle); #if !defined(__OS2__) && !defined(__WIN32__) && !defined(__EMX__) && !defined(__MAC__) int API dw_int_init(DWResources *res, int newthread, int *argc, char **argv[]); #define dw_init(a, b, c) dw_int_init(&_resources, a, &b, &c) @@ -1468,6 +1475,7 @@ int API dw_init(int newthread, int argc, char *argv[]); #endif void API dw_main(void); +void API dw_main_quit(void); void API dw_main_sleep(int seconds); void API dw_main_iteration(void); void API dw_free(void *ptr); @@ -1487,7 +1495,7 @@ int API dw_scrollbox_get_pos( HWND handle, int orient ); int API dw_scrollbox_get_range( HWND handle, int orient ); HWND API dw_groupbox_new(int type, int pad, char *title); -HWND API dw_mdi_new(unsigned long id); +DW_DEPRECATED(HWND API dw_mdi_new(unsigned long id), "Due to lack of full Mac support consider avoiding this function."); HWND API dw_bitmap_new(unsigned long id); HWND API dw_bitmapbutton_new(char *text, unsigned long id); HWND API dw_bitmapbutton_new_from_file(char *text, unsigned long id, char *filename); @@ -1530,12 +1538,15 @@ void API dw_window_set_size(HWND handle, unsigned long width, unsigned long height); void API dw_window_set_pos_size(HWND handle, long x, long y, unsigned long width, unsigned long height); void API dw_window_get_pos_size(HWND handle, long *x, long *y, unsigned long *width, unsigned long *height); +void API dw_window_get_preferred_size(HWND handle, int *width, int *height); +void API dw_window_set_gravity(HWND handle, int horz, int vert); void API dw_window_set_style(HWND handle, unsigned long style, unsigned long mask); void API dw_window_set_icon(HWND handle, HICN icon); void API dw_window_set_bitmap(HWND handle, unsigned long id, char *filename); void API dw_window_set_bitmap_from_data(HWND handle, unsigned long id, char *data, int len); char * API dw_window_get_text(HWND handle); void API dw_window_set_text(HWND handle, char *text); +void API dw_window_set_tooltip(HWND handle, char *bubbletext); int API dw_window_set_border(HWND handle, int border); void API dw_window_disable(HWND handle); void API dw_window_enable(HWND handle); @@ -1598,6 +1609,7 @@ void API dw_container_delete_row(HWND handle, char *text); void API dw_container_optimize(HWND handle); void API dw_container_set_stripe(HWND handle, unsigned long oddcolor, unsigned long evencolor); +void API dw_filesystem_set_column_title(HWND handle, char *title); int API dw_filesystem_setup(HWND handle, unsigned long *flags, char **titles, int count); void API dw_filesystem_set_item(HWND handle, void *pointer, int column, int row, void *data); void API dw_filesystem_set_file(HWND handle, void *pointer, int row, char *filename, HICN icon); @@ -1624,10 +1636,8 @@ HMENUI API dw_menu_new(unsigned long id); HMENUI API dw_menubar_new(HWND location); HWND API dw_menu_append_item(HMENUI menu, char *title, unsigned long id, unsigned long flags, int end, int check, HMENUI submenu); -#ifdef INCOMPLETE -void API dw_menu_delete_item(HMENUI menu, unsigned long id); -#endif -void API dw_menu_item_set_check(HMENUI menu, unsigned long id, int check); +int API dw_menu_delete_item(HMENUI menu, unsigned long id); +DW_DEPRECATED(void API dw_menu_item_set_check(HMENUI menu, unsigned long id, int check), "Use dw_menu_item_set_state() for new code."); void API dw_menu_item_set_state( HMENUI menux, unsigned long id, unsigned long state); void API dw_menu_popup(HMENUI *menu, HWND parent, int x, int y); void API dw_menu_destroy(HMENUI *menu); @@ -1680,6 +1690,7 @@ int API dw_browse(char *url); char * API dw_file_browse(char *title, char *defpath, char *ext, int flags); char * API dw_user_dir(void); +char * API dw_app_dir(void); DWDialog * API dw_dialog_new(void *data); int API dw_dialog_dismiss(DWDialog *dialog, void *result); void * API dw_dialog_wait(DWDialog *dialog); @@ -1715,5 +1726,7 @@ HPRINT API dw_print_new(char *jobname, unsigned long flags, unsigned int pages, void *drawfunc, void *drawdata); int API dw_print_run(HPRINT print, unsigned long flags); void API dw_print_cancel(HPRINT print); +wchar_t * API dw_utf8_to_wchar(char *utf8string); +char * API dw_wchar_to_utf8(wchar_t *wstring); #endif
--- a/os2/dw.c Sun Nov 20 11:11:53 2011 -0600 +++ b/os2/dw.c Wed Jul 25 00:05:29 2012 -0500 @@ -2,10 +2,11 @@ * Dynamic Windows: * A GTK like implementation of the PM GUI * - * (C) 2000-2011 Brian Smith <brian@dbsoft.org> - * (C) 2003-2008 Mark Hessling <m.hessling@qut.edu.au> + * (C) 2000-2012 Brian Smith <brian@dbsoft.org> + * (C) 2003-2011 Mark Hessling <mark@rexx.org> * (C) 2000 Achim Hasenmueller <achimha@innotek.de> * (C) 2000 Peter Nielsen <peter@pmview.com> + * (C) 2007 Alex Taylor (some code borrowed from clipuni) * (C) 1998 Sergey I. Yevtushenko (some code borrowed from cell toolkit) * */ @@ -37,6 +38,11 @@ #ifdef __WATCOMC__ #include <alloca.h> #endif +#include <fcntl.h> +#ifdef UNICODE +#include <uconv.h> +#include <unikbd.h> +#endif #include "dw.h" #define QWP_USER 0 @@ -44,20 +50,65 @@ /* The toolkit headers don't seem to have this */ BOOL APIENTRY WinStretchPointer(HPS hps, LONG x, LONG y, LONG cx, LONG cy, HPOINTER hptr, ULONG fs); +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +#ifdef __IBMC__ +#define API_FUNC * API +#else +#define API_FUNC API * +#endif + MRESULT EXPENTRY _run_event(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2); MRESULT EXPENTRY _wndproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2); MRESULT EXPENTRY _scrollwndproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2); void _do_resize(Box *thisbox, int x, int y); void _handle_splitbar_resize(HWND hwnd, float percent, int type, int x, int y); -int _load_bitmap_file(char *file, HWND handle, HBITMAP *hbm, HDC *hdc, HPS *hps, unsigned long *width, unsigned long *height); -void _dw_box_pack_start(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad, char *functionname); -void _dw_box_pack_end(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad, char *functionname); +int _load_bitmap_file(char *file, HWND handle, HBITMAP *hbm, HDC *hdc, HPS *hps, unsigned long *width, unsigned long *height, int *depth); void _free_menu_data(HWND menu); -ULONG (* _System _PmPrintfString)(char *String) = 0; +BOOL (API_FUNC _WinQueryDesktopWorkArea)(HWND hwndDesktop, PWRECT pwrcWorkArea) = 0; +/* PMPrintf support for dw_debug() */ +ULONG (API_FUNC _PmPrintfString)(char *String) = 0; +/* GBM (Generalize Bitmap Module) support for file loading */ +#pragma pack(4) +typedef struct +{ + int w, h, bpp; + unsigned char priv[2000]; +} GBM; +typedef struct { unsigned char r, g, b; } GBMRGB; +#pragma pack() +int (API_FUNC _gbm_init)(void) = 0; +int (API_FUNC _gbm_deinit)(void) = 0; +int (API_FUNC _gbm_query_n_filetypes)(int *count) = 0; +int (API_FUNC _gbm_io_open)(const char *fn, int mode) = 0; +int (API_FUNC _gbm_io_close)(int fd) = 0; +int (API_FUNC _gbm_read_header)(const char *fn, int fd, int ft, GBM *gbm, const char *info) = 0; +int (API_FUNC _gbm_read_palette)(int fd, int ft, GBM *gbm, GBMRGB *gbmrgb) = 0; +int (API_FUNC _gbm_read_data)(int fd, int ft, GBM *gbm, unsigned char *data) = 0; +const char * (API_FUNC _gbm_err)(int rc) = 0; +/* + * GBM List of supported formats: BMP, PNG, JPEG, Targa, TIFF and XPM. + */ +#define NUM_EXTS 8 +char *image_exts[NUM_EXTS] = +{ + ".bmp", + ".png", + ".jpg", + ".jpeg", + ".tga", + ".tif", + ".tiff", + ".xpm" +}; + char ClassName[] = "dynamicwindows"; char SplitbarClassName[] = "dwsplitbar"; char ScrollClassName[] = "dwscroll"; +char CalendarClassName[] = "dwcalendar"; char *DefaultFont = "9.WarpSans"; HAB dwhab = 0; @@ -67,11 +118,19 @@ HWND hwndApp = NULLHANDLE, hwndBubble = NULLHANDLE, hwndBubbleLast = NULLHANDLE, hwndEmph = NULLHANDLE; HWND hwndTrayServer = NULLHANDLE, hwndTaskBar = NULLHANDLE; -; + PRECORDCORE pCoreEmph = NULL; ULONG aulBuffer[4]; HWND lasthcnr = 0, lastitem = 0, popup = 0, desktop; -HMOD wpconfig = 0, pmprintf = 0; +HMOD wpconfig = 0, pmprintf = 0, pmmerge = 0, gbm = 0; +static char _dw_exec_dir[MAX_PATH+1] = {0}; + +#ifdef UNICODE +/* Atom for "text/unicode" clipboard format */ +ATOM Unicode; +KHAND Keyboard; +UconvObject Uconv; /* conversion object */ +#endif unsigned long _colors[] = { CLR_BLACK, @@ -92,6 +151,8 @@ CLR_WHITE }; +#define DW_OS2_NEW_WINDOW 1 + #define IS_WARP4() (aulBuffer[0] == 20 && aulBuffer[1] >= 40) #ifndef min @@ -223,19 +284,41 @@ return TRUE; } +/* Internal function to queue a window redraw */ +void _dw_redraw(HWND window, int skip) +{ + static HWND lastwindow = 0; + HWND redraw = lastwindow; + + if(skip && !window) + return; + + lastwindow = window; + if(redraw != lastwindow && redraw) + { + dw_window_redraw(redraw); + } +} + /* Find the desktop window handle */ HWND _toplevel_window(HWND handle) { HWND box, lastbox = WinQueryWindow(handle, QW_PARENT); /* Find the toplevel window */ - while((box = WinQueryWindow(lastbox, QW_PARENT)) != desktop && box > 0) + while((box = WinQueryWindow(lastbox, QW_PARENT)) != desktop && box) { lastbox = box; } - if(box > 0) - return lastbox; - return handle; + if(box) + { + char tmpbuf[100] = {0}; + + WinQueryClassName(lastbox, 99, (PCH)tmpbuf); + if(strncmp(tmpbuf, "#1", 3) == 0) + return lastbox; + } + return NULLHANDLE; } @@ -295,7 +378,7 @@ henum = WinBeginEnumWindows(handle); while((child = WinGetNextWindow(henum)) != NULLHANDLE) { - char tmpbuf[100]; + char tmpbuf[100] = {0}; WinQueryClassName(child, 99, (PCH)tmpbuf); @@ -320,7 +403,7 @@ henum = WinBeginEnumWindows(handle); while((child = WinGetNextWindow(henum)) != NULLHANDLE) { - char tmpbuf[100]; + char tmpbuf[100] = {0}; WinQueryClassName(child, 99, (PCH)tmpbuf); @@ -399,7 +482,7 @@ if(ptr) { WindowData *wd = (WindowData *)ptr; - char tmpbuf[100]; + char tmpbuf[100] = {0}; WinQueryClassName(handle, 99, (PCH)tmpbuf); @@ -424,14 +507,25 @@ } else if(strncmp(tmpbuf, "#37", 4)==0) { + char *coltitle = (char *)dw_window_get_data(handle, "_dw_coltitle"); + PFIELDINFO first; + dw_container_clear(handle, FALSE); if(wd && dw_window_get_data(handle, "_dw_container")) { void *oldflags = wd->data; - wd->data = NULL; free(oldflags); } + /* Free memory allocated for the container column titles */ + while((first = (PFIELDINFO)WinSendMsg(handle, CM_QUERYDETAILFIELDINFO, 0, MPFROMSHORT(CMA_FIRST))) != NULL) + { + if(first->pTitleData) + free(first->pTitleData); + WinSendMsg(handle, CM_REMOVEDETAILFIELDINFO, (MPARAM)&first, MPFROM2SHORT(1, CMA_FREE)); + } + if(coltitle) + free(coltitle); } if(wd->oldproc) @@ -490,7 +584,7 @@ */ int _validate_focus(HWND handle) { - char tmpbuf[100]; + char tmpbuf[100] = {0}; if(!handle) return 0; @@ -591,7 +685,7 @@ } else { - char tmpbuf[100] = ""; + char tmpbuf[100] = {0}; WinQueryClassName(box->items[z].hwnd, 99, (PCH)tmpbuf); if(strncmp(tmpbuf, SplitbarClassName, strlen(SplitbarClassName)+1)==0) @@ -726,7 +820,7 @@ } else { - char tmpbuf[100] = ""; + char tmpbuf[100] = {0}; WinQueryClassName(box->items[z].hwnd, 99, (PCH)tmpbuf); if(strncmp(tmpbuf, SplitbarClassName, strlen(SplitbarClassName)+1)==0) @@ -971,7 +1065,7 @@ void _check_resize_notebook(HWND hwnd) { - char tmpbuf[100]; + char tmpbuf[100] = {0}; WinQueryClassName(hwnd, 99, (PCH)tmpbuf); @@ -1027,194 +1121,151 @@ return WinSetWindowPos(hwnd, behind, x, height - y - cy, cx, cy, fl); } -#define _DW_DEFAULT_SCROLLBAR_WIDTH 16 +#ifdef UNICODE +#define MAX_CP_NAME 12 /* maximum length of a codepage name */ +#define MAX_CP_SPEC 64 /* maximum length of a UconvObject codepage specifier */ + +char *_WideToUTF8(UniChar *unistr) +{ + /* Convert text to UTF-8 codepage */ + char *retval = NULL; + /* Now do the conversion */ + ULONG ulBufLen = (UniStrlen(unistr) * 4) + 1; + char *s, *pszLocalText = (char *)malloc(ulBufLen); + + if(UniStrFromUcs(Uconv, pszLocalText, + unistr, ulBufLen) == ULS_SUCCESS) + { + /* (some codepages use 0x1A for substitutions; replace with ?) */ + while((s = strchr(pszLocalText, 0x1A)) != NULL) *s = '?'; + /* Output the converted text */ + retval = pszLocalText; + } + else if(pszLocalText) + free(pszLocalText); + return retval; +} + +UniChar *_UTF8toWide(char *utf8str) +{ + /* Convert text to Unicode */ + UniChar *retval = NULL; + /* Now do the conversion */ + UniChar *buf = calloc(strlen(utf8str) + 1, sizeof(UniChar)); + + if(UniStrToUcs(Uconv, buf, + utf8str, strlen(utf8str) * sizeof(UniChar)) == ULS_SUCCESS) + { + /* Output the converted text */ + retval = buf; + } + else if(buf) + free(buf); + return retval; +} +#endif /* This function calculates how much space the widgets and boxes require * and does expansion as necessary. */ -int _resize_box(Box *thisbox, int *depth, int x, int y, int *usedx, int *usedy, - int pass, int *usedpadx, int *usedpady) -{ - int z, currentx = 0, currenty = 0; +static void _resize_box(Box *thisbox, int *depth, int x, int y, int pass) +{ + /* Current item position */ + int z, currentx = thisbox->pad, currenty = thisbox->pad; + /* Used x, y and padding maximum values... + * These will be used to find the widest or + * tallest items in a box. + */ int uymax = 0, uxmax = 0; int upymax = 0, upxmax = 0; - /* Used for the SIZEEXPAND */ - int nux = *usedx, nuy = *usedy; - int nupx = *usedpadx, nupy = *usedpady; - - (*usedx) += (thisbox->pad * 2); - (*usedy) += (thisbox->pad * 2); + + /* Reset the box sizes */ + thisbox->minwidth = thisbox->minheight = thisbox->usedpadx = thisbox->usedpady = thisbox->pad * 2; if(thisbox->grouphwnd) { - char *text = dw_window_get_text(thisbox->grouphwnd); - - thisbox->grouppady = 0; - - if(text) - { - dw_font_text_extents_get(thisbox->grouphwnd, 0, text, NULL, &thisbox->grouppady); - dw_free(text); - } - - if(thisbox->grouppady) - thisbox->grouppady += 3; - else - thisbox->grouppady = 6; - - thisbox->grouppadx = 6; - - (*usedx) += thisbox->grouppadx; - (*usedpadx) += thisbox->grouppadx; - (*usedy) += thisbox->grouppady; - (*usedpady) += thisbox->grouppady; - } - + /* Only calculate the size on the first pass... + * use the cached values on second. + */ + if(pass == 1) + { + char *text = dw_window_get_text(thisbox->grouphwnd); + + thisbox->grouppady = 9; + + if(text) + { + if(*text) + dw_font_text_extents_get(thisbox->grouphwnd, 0, text, NULL, &thisbox->grouppady); + dw_free(text); + } + /* If the string height is less than 9... + * set it to 9 anyway since that is the minimum. + */ + if(thisbox->grouppady < 9) + thisbox->grouppady = 9; + + if(thisbox->grouppady) + thisbox->grouppady += 3; + else + thisbox->grouppady = 6; + + thisbox->grouppadx = 6; + } + + thisbox->minwidth += thisbox->grouppadx; + thisbox->usedpadx += thisbox->grouppadx; + thisbox->minheight += thisbox->grouppady; + thisbox->usedpady += thisbox->grouppady; + } + + /* Count up all the space for all items in the box */ for(z=0;z<thisbox->count;z++) { + int itempad, itemwidth, itemheight; + if(thisbox->items[z].type == TYPEBOX) { - int initialx, initialy; Box *tmp = WinQueryWindowPtr(thisbox->items[z].hwnd, QWP_USER); - initialx = x - (*usedx); - initialy = y - (*usedy); - if(tmp) { - int newx, newy; - int nux = *usedx, nuy = *usedy; - int upx = *usedpadx + (tmp->pad*2), upy = *usedpady + (tmp->pad*2); - - /* On the second pass we know how big the box needs to be and how - * much space we have, so we can calculate a ratio for the new box. - */ - if(pass == 2) + /* On the first pass calculate the box contents */ + if(pass == 1) { - int deep = *depth + 1; - - _resize_box(tmp, &deep, x, y, &nux, &nuy, 1, &upx, &upy); - - tmp->upx = upx - *usedpadx; - tmp->upy = upy - *usedpady; - - newx = x - nux; - newy = y - nuy; - - tmp->width = thisbox->items[z].width = initialx - newx; - tmp->height = thisbox->items[z].height = initialy - newy; - - tmp->parentxratio = thisbox->xratio; - tmp->parentyratio = thisbox->yratio; - - tmp->parentpad = tmp->pad; - - /* Just in case */ - tmp->xratio = thisbox->xratio; - tmp->yratio = thisbox->yratio; - - if(thisbox->type == DW_VERT) - { - int tmppad = (thisbox->items[z].pad*2)+(tmp->pad*2)+tmp->grouppady; - - if((thisbox->items[z].width - tmppad)!=0) - tmp->xratio = ((float)((thisbox->items[z].width * thisbox->xratio)-tmppad))/((float)(thisbox->items[z].width-tmppad)); - } - else - { - if((thisbox->items[z].width-tmp->upx)!=0) - tmp->xratio = ((float)((thisbox->items[z].width * thisbox->xratio)-tmp->upx))/((float)(thisbox->items[z].width-tmp->upx)); - } - if(thisbox->type == DW_HORZ) - { - int tmppad = (thisbox->items[z].pad*2)+(tmp->pad*2)+tmp->grouppadx; - - if((thisbox->items[z].height-tmppad)!=0) - tmp->yratio = ((float)((thisbox->items[z].height * thisbox->yratio)-tmppad))/((float)(thisbox->items[z].height-tmppad)); - } - else - { - if((thisbox->items[z].height-tmp->upy)!=0) - tmp->yratio = ((float)((thisbox->items[z].height * thisbox->yratio)-tmp->upy))/((float)(thisbox->items[z].height-tmp->upy)); - } - - nux = *usedx; nuy = *usedy; - upx = *usedpadx + (tmp->pad*2); upy = *usedpady + (tmp->pad*2); + (*depth)++; + + /* Save the newly calculated values on the box */ + _resize_box(tmp, depth, x, y, pass); + + /* Duplicate the values in the item list for use below */ + thisbox->items[z].width = tmp->minwidth; + thisbox->items[z].height = tmp->minheight; + + /* If the box has no contents but is expandable... default the size to 1 */ + if(!thisbox->items[z].width && thisbox->items[z].hsize) + thisbox->items[z].width = 1; + if(!thisbox->items[z].height && thisbox->items[z].vsize) + thisbox->items[z].height = 1; + + (*depth)--; } - - (*depth)++; - - _resize_box(tmp, depth, x, y, &nux, &nuy, pass, &upx, &upy); - - (*depth)--; - - newx = x - nux; - newy = y - nuy; - - tmp->minwidth = thisbox->items[z].width = initialx - newx; - tmp->minheight = thisbox->items[z].height = initialy - newy; - } - } - - if(pass > 1 && *depth > 0) - { - if(thisbox->type == DW_VERT) - { - int tmppad = (thisbox->items[z].pad*2)+(thisbox->parentpad*2)+thisbox->grouppadx; - - if((thisbox->minwidth-tmppad) == 0) - thisbox->items[z].xratio = 1.0; - else - thisbox->items[z].xratio = ((float)((thisbox->width * thisbox->parentxratio)-tmppad))/((float)(thisbox->minwidth-tmppad)); - } - else - { - if(thisbox->minwidth-thisbox->upx == 0) - thisbox->items[z].xratio = 1.0; - else - thisbox->items[z].xratio = ((float)((thisbox->width * thisbox->parentxratio)-thisbox->upx))/((float)(thisbox->minwidth-thisbox->upx)); - } - - if(thisbox->type == DW_HORZ) - { - int tmppad = (thisbox->items[z].pad*2)+(thisbox->parentpad*2)+thisbox->grouppady; - - if((thisbox->minheight-tmppad) == 0) - thisbox->items[z].yratio = 1.0; - else - thisbox->items[z].yratio = ((float)((thisbox->height * thisbox->parentyratio)-tmppad))/((float)(thisbox->minheight-tmppad)); - } - else - { - if(thisbox->minheight-thisbox->upy == 0) - thisbox->items[z].yratio = 1.0; - else - thisbox->items[z].yratio = ((float)((thisbox->height * thisbox->parentyratio)-thisbox->upy))/((float)(thisbox->minheight-thisbox->upy)); - } - - if(thisbox->items[z].type == TYPEBOX) - { - Box *tmp = WinQueryWindowPtr(thisbox->items[z].hwnd, QWP_USER); - - if(tmp) - { - tmp->parentxratio = thisbox->items[z].xratio; - tmp->parentyratio = thisbox->items[z].yratio; - } - } - } - else - { - thisbox->items[z].xratio = thisbox->xratio; - thisbox->items[z].yratio = thisbox->yratio; - } - + } + } + + /* Precalculate these values, since they will + * be used used repeatedly in the next section. + */ + itempad = thisbox->items[z].pad * 2; + itemwidth = thisbox->items[z].width + itempad; + itemheight = thisbox->items[z].height + itempad; + + /* Calculate the totals and maximums */ if(thisbox->type == DW_VERT) { - int itemwidth = thisbox->items[z].width + (thisbox->items[z].pad*2); - if(itemwidth > uxmax) uxmax = itemwidth; + if(thisbox->items[z].hsize != SIZEEXPAND) { if(itemwidth > upxmax) @@ -1222,30 +1273,17 @@ } else { - if(thisbox->items[z].pad*2 > upxmax) - upxmax = thisbox->items[z].pad*2; - } + if(itempad > upxmax) + upxmax = itempad; + } + thisbox->minheight += itemheight; + if(thisbox->items[z].vsize != SIZEEXPAND) + thisbox->usedpady += itemheight; + else + thisbox->usedpady += itempad; } else { - if(thisbox->items[z].width == -1) - { - /* figure out how much space this item requires */ - /* thisbox->items[z].width = */ - } - else - { - (*usedx) += thisbox->items[z].width + (thisbox->items[z].pad*2); - if(thisbox->items[z].hsize != SIZEEXPAND) - (*usedpadx) += (thisbox->items[z].pad*2) + thisbox->items[z].width; - else - (*usedpadx) += thisbox->items[z].pad*2; - } - } - if(thisbox->type == DW_HORZ) - { - int itemheight = thisbox->items[z].height + (thisbox->items[z].pad*2); - if(itemheight > uymax) uymax = itemheight; if(thisbox->items[z].vsize != SIZEEXPAND) @@ -1255,121 +1293,73 @@ } else { - if(thisbox->items[z].pad*2 > upymax) - upymax = thisbox->items[z].pad*2; - } - } - else - { - if(thisbox->items[z].height == -1) - { - /* figure out how much space this item requires */ - /* thisbox->items[z].height = */ - } + if(itempad > upymax) + upymax = itempad; + } + thisbox->minwidth += itemwidth; + if(thisbox->items[z].hsize != SIZEEXPAND) + thisbox->usedpadx += itemwidth; else - { - (*usedy) += thisbox->items[z].height + (thisbox->items[z].pad*2); - if(thisbox->items[z].vsize != SIZEEXPAND) - (*usedpady) += (thisbox->items[z].pad*2) + thisbox->items[z].height; - else - (*usedpady) += thisbox->items[z].pad*2; - } - } - } - - (*usedx) += uxmax; - (*usedy) += uymax; - (*usedpadx) += upxmax; - (*usedpady) += upymax; - - currentx += thisbox->pad; - currenty += thisbox->pad; - + thisbox->usedpadx += itempad; + } + } + + /* Add the maximums which were calculated in the previous loop */ + thisbox->minwidth += uxmax; + thisbox->minheight += uymax; + thisbox->usedpadx += upxmax; + thisbox->usedpady += upymax; + + /* Move the groupbox start past the group border */ if(thisbox->grouphwnd) { currentx += 3; currenty += thisbox->grouppady - 3; } - - /* The second pass is for expansion and actual placement. */ + + /* The second pass is for actual placement. */ if(pass > 1) { - /* Any SIZEEXPAND items should be set to uxmax/uymax */ - for(z=0;z<thisbox->count;z++) - { - if(thisbox->items[z].hsize == SIZEEXPAND && thisbox->type == DW_VERT) - thisbox->items[z].width = uxmax-(thisbox->items[z].pad*2); - if(thisbox->items[z].vsize == SIZEEXPAND && thisbox->type == DW_HORZ) - thisbox->items[z].height = uymax-(thisbox->items[z].pad*2); - /* Run this code segment again to finalize the sized after setting uxmax/uymax values. */ - if(thisbox->items[z].type == TYPEBOX) - { - Box *tmp = WinQueryWindowPtr(thisbox->items[z].hwnd, QWP_USER); - - if(tmp) - { - if(*depth > 0) - { - float calcval; - - if(thisbox->type == DW_VERT) - { - calcval = (float)(tmp->minwidth-((thisbox->items[z].pad*2)+(thisbox->pad*2))); - if(calcval == 0.0) - tmp->xratio = thisbox->xratio; - else - tmp->xratio = ((float)((thisbox->items[z].width * thisbox->xratio)-((thisbox->items[z].pad*2)+(thisbox->pad*2))))/calcval; - tmp->width = thisbox->items[z].width; - } - if(thisbox->type == DW_HORZ) - { - calcval = (float)(tmp->minheight-((thisbox->items[z].pad*2)+(thisbox->pad*2))); - if(calcval == 0.0) - tmp->yratio = thisbox->yratio; - else - tmp->yratio = ((float)((thisbox->items[z].height * thisbox->yratio)-((thisbox->items[z].pad*2)+(thisbox->pad*2))))/calcval; - tmp->height = thisbox->items[z].height; - } - } - - (*depth)++; - - _resize_box(tmp, depth, x, y, &nux, &nuy, 3, &nupx, &nupy); - - (*depth)--; - - } - } - } - for(z=0;z<(thisbox->count);z++) { int height = thisbox->items[z].height; int width = thisbox->items[z].width; - int pad = thisbox->items[z].pad; - HWND handle = thisbox->items[z].hwnd; - int vectorx, vectory; - - /* When upxmax != pad*2 then ratios are incorrect. */ - vectorx = (int)((width*thisbox->items[z].xratio)-width); - vectory = (int)((height*thisbox->items[z].yratio)-height); - + int itempad = thisbox->items[z].pad * 2; + int thispad = thisbox->pad * 2; + + /* Calculate the new sizes */ + if(thisbox->items[z].hsize == SIZEEXPAND) + { + if(thisbox->type == DW_HORZ) + { + int expandablex = thisbox->minwidth - thisbox->usedpadx; + + if(expandablex) + width = (int)(((float)width / (float)expandablex) * (float)(x - thisbox->usedpadx)); + } + else + width = x - (itempad + thispad + thisbox->grouppadx); + } + if(thisbox->items[z].vsize == SIZEEXPAND) + { + if(thisbox->type == DW_VERT) + { + int expandabley = thisbox->minheight - thisbox->usedpady; + + if(expandabley) + height = (int)(((float)height / (float)expandabley) * (float)(y - thisbox->usedpady)); + } + else + height = y - (itempad + thispad + thisbox->grouppady); + } + + /* If the calculated size is valid... */ if(width > 0 && height > 0) { - char tmpbuf[100]; - /* This is a hack to fix rounding of the sizing */ - if(*depth == 0) - { - vectorx++; - vectory++; - } - - /* If this item isn't going to expand... reset the vectors to 0 */ - if(thisbox->items[z].vsize != SIZEEXPAND) - vectory = 0; - if(thisbox->items[z].hsize != SIZEEXPAND) - vectorx = 0; - + int pad = thisbox->items[z].pad; + HWND handle = thisbox->items[z].hwnd; + char tmpbuf[100] = {0}; + WinQueryClassName(handle, 99, (PCH)tmpbuf); if(strncmp(tmpbuf, "#2", 3)==0) @@ -1377,28 +1367,26 @@ HWND frame = (HWND)dw_window_get_data(handle, "_dw_combo_box"); /* Make the combobox big enough to drop down. :) */ WinSetWindowPos(handle, HWND_TOP, 0, -100, - width + vectorx, (height + vectory) + 100, SWP_MOVE | SWP_SIZE | SWP_ZORDER); + width, height + 100, SWP_MOVE | SWP_SIZE | SWP_ZORDER); _MySetWindowPos(frame, thisbox->hwnd, HWND_TOP, currentx + pad, currenty + pad, - width + vectorx, height + vectory, SWP_MOVE | SWP_SIZE | SWP_ZORDER); + width, height, SWP_MOVE | SWP_SIZE | SWP_ZORDER); } else if(strncmp(tmpbuf, "#6", 3)==0) { /* Entryfields on OS/2 have a thick border that isn't on Windows and GTK */ _MySetWindowPos(handle, thisbox->hwnd, HWND_TOP, (currentx + pad) + 3, (currenty + pad) + 3, - (width + vectorx) - 6, (height + vectory) - 6, SWP_MOVE | SWP_SIZE | SWP_ZORDER); + width - 6, height - 6, SWP_MOVE | SWP_SIZE | SWP_ZORDER); } else if(strncmp(tmpbuf, "#40", 5)==0) { _MySetWindowPos(handle, thisbox->hwnd, HWND_TOP, currentx + pad, currenty + pad, - width + vectorx, height + vectory, SWP_MOVE | SWP_SIZE | SWP_ZORDER); + width, height, SWP_MOVE | SWP_SIZE | SWP_ZORDER); _check_resize_notebook(handle); } else if(strncmp(tmpbuf, ScrollClassName, strlen(ScrollClassName)+1)==0) { /* Handle special case of scrollbox */ - int cx = width + vectorx; - int cy = height + vectory; - int usedx = 0, usedy = 0, usedpadx = 0, usedpady = 0, depth = 0; + int cx, cy, depth = 0; HWND box = (HWND)dw_window_get_data(handle, "_dw_resizebox"); HWND client = WinWindowFromID(handle, FID_CLIENT); HWND vscroll = WinWindowFromID(handle, FID_VERTSCROLL); @@ -1409,46 +1397,46 @@ unsigned int vpos = (unsigned int)WinSendMsg(vscroll, SBM_QUERYPOS, 0, 0); /* Position the scrollbox parts */ - _MySetWindowPos(handle, thisbox->hwnd, HWND_TOP, currentx + pad, currenty + pad, cx, cy, SWP_MOVE | SWP_SIZE | SWP_ZORDER); - WinSetWindowPos(client, HWND_TOP, 0, _DW_DEFAULT_SCROLLBAR_WIDTH, cx - _DW_DEFAULT_SCROLLBAR_WIDTH, cy - _DW_DEFAULT_SCROLLBAR_WIDTH, SWP_MOVE | SWP_SIZE | SWP_ZORDER); - WinSetWindowPos(hscroll, HWND_TOP, 0, 0, cx - _DW_DEFAULT_SCROLLBAR_WIDTH, _DW_DEFAULT_SCROLLBAR_WIDTH, SWP_MOVE | SWP_SIZE | SWP_ZORDER); - WinSetWindowPos(vscroll, HWND_TOP, cx - _DW_DEFAULT_SCROLLBAR_WIDTH, _DW_DEFAULT_SCROLLBAR_WIDTH, _DW_DEFAULT_SCROLLBAR_WIDTH, cy - _DW_DEFAULT_SCROLLBAR_WIDTH, SWP_MOVE | SWP_SIZE | SWP_ZORDER); - - origx = cx = cx - _DW_DEFAULT_SCROLLBAR_WIDTH; - origy = cy = cy - _DW_DEFAULT_SCROLLBAR_WIDTH; + _MySetWindowPos(handle, thisbox->hwnd, HWND_TOP, currentx + pad, currenty + pad, width, height, SWP_MOVE | SWP_SIZE | SWP_ZORDER); + WinSetWindowPos(client, HWND_TOP, 0, WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL), width - WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL), height - WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL), SWP_MOVE | SWP_SIZE | SWP_ZORDER); + WinSetWindowPos(hscroll, HWND_TOP, 0, 0, width - WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL), WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL), SWP_MOVE | SWP_SIZE | SWP_ZORDER); + WinSetWindowPos(vscroll, HWND_TOP, width - WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL), WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL), WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL), height - WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL), SWP_MOVE | SWP_SIZE | SWP_ZORDER); + + origx = cx = width - WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL); + origy = cy = height - WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL); /* Get the required space for the box */ - _resize_box(contentbox, &depth, cx, cy, &usedx, &usedy, 1, &usedpadx, &usedpady); - - if(cx < usedx) + _resize_box(contentbox, &depth, cx, cy, 1); + + if(cx < contentbox->minwidth) { - cx = usedx; + cx = contentbox->minwidth; } - if(cy < usedy) + if(cy < contentbox->minheight) { - cy = usedy; + cy = contentbox->minheight; } /* Setup vertical scroller */ - WinSendMsg(vscroll, SBM_SETSCROLLBAR, (MPARAM)vpos, MPFROM2SHORT(0, (unsigned short)usedy - origy)); - WinSendMsg(vscroll, SBM_SETTHUMBSIZE, MPFROM2SHORT((unsigned short)origy, usedy), 0); - if(vpos > usedy) + WinSendMsg(vscroll, SBM_SETSCROLLBAR, (MPARAM)vpos, MPFROM2SHORT(0, (unsigned short)contentbox->minheight - origy)); + WinSendMsg(vscroll, SBM_SETTHUMBSIZE, MPFROM2SHORT((unsigned short)origy, contentbox->minheight), 0); + if(vpos > contentbox->minheight) { - vpos = usedy; + vpos = contentbox->minheight; WinSendMsg(vscroll, SBM_SETPOS, (MPARAM)vpos, 0); } /* Setup horizontal scroller */ - WinSendMsg(hscroll, SBM_SETSCROLLBAR, (MPARAM)hpos, MPFROM2SHORT(0, (unsigned short)usedx - origx)); - WinSendMsg(hscroll, SBM_SETTHUMBSIZE, MPFROM2SHORT((unsigned short)origx, usedx), 0); - if(hpos > usedx) + WinSendMsg(hscroll, SBM_SETSCROLLBAR, (MPARAM)hpos, MPFROM2SHORT(0, (unsigned short)contentbox->minwidth - origx)); + WinSendMsg(hscroll, SBM_SETTHUMBSIZE, MPFROM2SHORT((unsigned short)origx, contentbox->minwidth), 0); + if(hpos > contentbox->minwidth) { - hpos = usedx; + hpos = contentbox->minwidth; WinSendMsg(hscroll, SBM_SETPOS, (MPARAM)hpos, 0); } /* Position the scrolled box */ - WinSetWindowPos(box, HWND_TOP, 0, -(cy - origy), cx, cy, SWP_MOVE | SWP_SIZE | SWP_ZORDER); + WinSetWindowPos(box, HWND_TOP, -hpos, -(cy - origy - vpos), cx, cy, SWP_MOVE | SWP_SIZE | SWP_ZORDER); dw_window_set_data(handle, "_dw_cy", (void *)(cy - origy)); @@ -1460,39 +1448,48 @@ /* Then try the bottom or right box */ float *percent = (float *)dw_window_get_data(handle, "_dw_percent"); int type = (int)dw_window_get_data(handle, "_dw_type"); - int cx = width + vectorx; - int cy = height + vectory; _MySetWindowPos(handle, thisbox->hwnd, HWND_TOP, currentx + pad, currenty + pad, - cx, cy, SWP_MOVE | SWP_SIZE | SWP_ZORDER); - - if(cx > 0 && cy > 0 && percent) - _handle_splitbar_resize(handle, *percent, type, cx, cy); + width, height, SWP_MOVE | SWP_SIZE | SWP_ZORDER); + + if(percent) + _handle_splitbar_resize(handle, *percent, type, width, height); } else { + /* Everything else */ _MySetWindowPos(handle, thisbox->hwnd, HWND_TOP, currentx + pad, currenty + pad, - width + vectorx, height + vectory, SWP_MOVE | SWP_SIZE | SWP_ZORDER); + width, height, SWP_MOVE | SWP_SIZE | SWP_ZORDER); + + /* After placing a box... place its components */ if(thisbox->items[z].type == TYPEBOX) { Box *boxinfo = WinQueryWindowPtr(handle, QWP_USER); - if(boxinfo && boxinfo->grouphwnd) - WinSetWindowPos(boxinfo->grouphwnd, HWND_TOP, 0, 0, - width + vectorx, height + vectory, SWP_MOVE | SWP_SIZE); - + if(boxinfo) + { + if(boxinfo->grouphwnd) + { + /* Move the group border into place */ + WinSetWindowPos(boxinfo->grouphwnd, HWND_TOP, 0, 0, + width, height, SWP_MOVE | SWP_SIZE); + } + /* Dive into the box */ + (*depth)++; + _resize_box(boxinfo, depth, width, height, pass); + (*depth)--; + } } - } + /* Advance the current position in the box */ if(thisbox->type == DW_HORZ) - currentx += width + vectorx + (pad * 2); + currentx += width + (pad * 2); if(thisbox->type == DW_VERT) - currenty += height + vectory + (pad * 2); - } - } - } - return 0; + currenty += height + (pad * 2); + } + } + } } void _do_resize(Box *thisbox, int x, int y) @@ -1501,19 +1498,13 @@ { if(thisbox) { - int usedx = 0, usedy = 0, usedpadx = 0, usedpady = 0, depth = 0; - - _resize_box(thisbox, &depth, x, y, &usedx, &usedy, 1, &usedpadx, &usedpady); - - if(usedx-usedpadx == 0 || usedy-usedpady == 0) - return; - - thisbox->xratio = ((float)(x-usedpadx))/((float)(usedx-usedpadx)); - thisbox->yratio = ((float)(y-usedpady))/((float)(usedy-usedpady)); - - usedx = usedy = usedpadx = usedpady = depth = 0; - - _resize_box(thisbox, &depth, x, y, &usedx, &usedy, 2, &usedpadx, &usedpady); + int depth = 0; + + /* Calculate space requirements */ + _resize_box(thisbox, &depth, x, y, 1); + + /* Finally place all the boxes and controls */ + _resize_box(thisbox, &depth, x, y, 2); } } } @@ -1608,6 +1599,258 @@ GpiLine(hpsPaint, &ptl2); } +void _drawtext(HWND hWnd, HPS hpsPaint) +{ + RECTL rclPaint; + int len = WinQueryWindowTextLength(hWnd); + ULONG style = WinQueryWindowULong(hWnd, QWL_STYLE) & (DT_TOP|DT_VCENTER|DT_BOTTOM|DT_LEFT|DT_CENTER|DT_RIGHT|DT_WORDBREAK); + char *tempbuf = alloca(len + 2); + ULONG fcolor = DT_TEXTATTRS, bcolor = DT_TEXTATTRS; + + WinQueryWindowText(hWnd, len + 1, (PSZ)tempbuf); + WinQueryWindowRect(hWnd, &rclPaint); + + if(WinQueryPresParam(hWnd, PP_BACKGROUNDCOLOR, 0, NULL, sizeof(bcolor), &bcolor, QPF_NOINHERIT) || + WinQueryPresParam(hWnd, PP_BACKGROUNDCOLORINDEX, 0, NULL, sizeof(bcolor), &bcolor, QPF_NOINHERIT)) + GpiSetBackColor(hpsPaint, bcolor); + if(WinQueryPresParam(hWnd, PP_FOREGROUNDCOLOR, 0, NULL, sizeof(fcolor), &fcolor, QPF_NOINHERIT) || + WinQueryPresParam(hWnd, PP_FOREGROUNDCOLORINDEX, 0, NULL, sizeof(fcolor), &fcolor, QPF_NOINHERIT)) + GpiSetColor(hpsPaint, fcolor); + WinDrawText(hpsPaint, -1, (PCH)tempbuf, &rclPaint, DT_TEXTATTRS, DT_TEXTATTRS, style | DT_TEXTATTRS | DT_ERASERECT); +} + +/* Function: BubbleProc + * Abstract: Subclass procedure for bubble help + */ +MRESULT EXPENTRY _BubbleProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + PFNWP proc = (PFNWP)WinQueryWindowPtr(hwnd, QWL_USER); + + if(msg == WM_PAINT) + { + POINTL ptl; + HPS hpsTemp; + RECTL rcl; + int height, width; + + WinQueryWindowRect(hwnd, &rcl); + height = rcl.yTop - rcl.yBottom - 1; + width = rcl.xRight - rcl.xLeft - 1; + + /* Draw a border around the bubble help */ + hpsTemp = WinBeginPaint(hwnd, 0, 0); + + _drawtext(hwnd, hpsTemp); + GpiSetColor(hpsTemp, CLR_BLACK); + ptl.x = ptl.y = 0; + GpiMove(hpsTemp, &ptl); + ptl.x = 0; + ptl.y = height; + GpiLine(hpsTemp, &ptl); + ptl.x = ptl.y = 0; + GpiMove(hpsTemp, &ptl); + ptl.y = 0; + ptl.x = width; + GpiLine(hpsTemp, &ptl); + ptl.x = width; + ptl.y = height; + GpiMove(hpsTemp, &ptl); + ptl.x = 0; + ptl.y = height; + GpiLine(hpsTemp, &ptl); + ptl.x = width; + ptl.y = height; + GpiMove(hpsTemp, &ptl); + ptl.y = 0; + ptl.x = width; + GpiLine(hpsTemp, &ptl); + WinEndPaint(hpsTemp); + return (MRESULT)TRUE; + } + if(proc) + return proc(hwnd, msg, mp1, mp2); + return WinDefWindowProc(hwnd, msg, mp1, mp2); +} + +/* Subclass WC_STATIC to draw a bitmap centered */ +MRESULT EXPENTRY _BitmapProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + WindowData *blah = (WindowData *)WinQueryWindowPtr(hwnd, QWL_USER); + + if(msg == WM_PAINT) + { + HPS hps = WinBeginPaint(hwnd, 0, 0); + HBITMAP hbm = (HBITMAP)dw_window_get_data(hwnd, "_dw_bitmap"); + RECTL rcl; + + WinQueryWindowRect(hwnd, &rcl) ; + WinFillRect(hps, &rcl, CLR_PALEGRAY); + + /* If we have a bitmap... draw it */ + if(hbm) + { + BITMAPINFOHEADER sl; + + sl.cbFix = sizeof(BITMAPINFOHEADER); + + /* Check the bitmap size */ + if(GpiQueryBitmapParameters(hbm, &sl)) + { + /* Figure out the window size before clobbering the data */ + int width = rcl.xRight - rcl.xLeft, height = rcl.yTop - rcl.yBottom; + + /* If the control is bigger than the bitmap, center it */ + if(width > sl.cx) + rcl.xLeft = (width-sl.cx)/2; + if(height > sl.cy) + rcl.yBottom = (height-sl.cy)/2; + + } + /* Draw the bitmap unscaled at the desired location */ + WinDrawBitmap(hps, hbm, NULL, (PPOINTL) &rcl, + CLR_NEUTRAL, CLR_BACKGROUND, DBM_NORMAL); + } + + WinEndPaint(hps); + return 0; + } + if(blah && blah->oldproc) + return blah->oldproc(hwnd, msg, mp1, mp2); + return WinDefWindowProc(hwnd, msg, mp1, mp2); +} + +/* Function to handle tooltip messages from a variety of procedures */ +MRESULT EXPENTRY _TooltipProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2, WindowData *blah) +{ + static HWND hstart, hend; + + switch(msg) + { + case 0x041f: + /* Mouse has left the area.. remove tooltip and stop timer */ + if(hwndBubble) + { + WinDestroyWindow(hwndBubble); + hwndBubble = 0; + } + if(hstart) + WinStopTimer(dwhab, hstart, 1); + if(hend) + WinStopTimer(dwhab, hend, 2); + hstart = hend = 0; + break; + + case 0x041e: + /* Mouse has entered... stop any pending timer... + * then start a new timer to creat the tooltip delayed. + */ + if(hstart) + WinStopTimer(dwhab, hstart, 1); + /* Two seconds to create */ + WinStartTimer(dwhab, hwnd, 1, 2000); + hstart = hwnd; + break; + case WM_TIMER: + if((int)mp1 == 1 || (int)mp1 == 2) + { + if(hwndBubble) + { + WinDestroyWindow(hwndBubble); + hwndBubble = 0; + } + /* Either starting or ending... remove tooltip and timers */ + if(hstart) + WinStopTimer(dwhab, hstart, 1); + if(hend) + WinStopTimer(dwhab, hend, 2); + hstart = hend = 0; + /* If we are starting... create a new tooltip */ + if((int)mp1 == 1) + { + HPS hpsTemp = 0; + LONG lHight; + LONG lWidth; + POINTL txtPointl[TXTBOX_COUNT]; + POINTL ptlWork = {0,0}; + ULONG ulColor = CLR_YELLOW; + void *bubbleproc; + + hwndBubbleLast = hwnd; + hwndBubble = WinCreateWindow(HWND_DESKTOP, + WC_STATIC, + NULL, + SS_TEXT | + DT_CENTER | + DT_VCENTER, + 0,0,0,0, + HWND_DESKTOP, + HWND_TOP, + 0, + NULL, + NULL); + + WinSetPresParam(hwndBubble, + PP_FONTNAMESIZE, + strlen(DefaultFont)+1, + DefaultFont); + + + WinSetPresParam(hwndBubble, + PP_BACKGROUNDCOLORINDEX, + sizeof(ulColor), + &ulColor); + + WinSetWindowText(hwndBubble, + (PSZ)blah->bubbletext); + + WinMapWindowPoints(hwnd, HWND_DESKTOP, &ptlWork, 1); + + hpsTemp = WinGetPS(hwndBubble); + GpiQueryTextBox(hpsTemp, + strlen(blah->bubbletext), + (PCH)blah->bubbletext, + TXTBOX_COUNT, + txtPointl); + WinReleasePS(hpsTemp); + + lWidth = txtPointl[TXTBOX_TOPRIGHT].x - + txtPointl[TXTBOX_TOPLEFT ].x + 8; + + lHight = txtPointl[TXTBOX_TOPLEFT].y - + txtPointl[TXTBOX_BOTTOMLEFT].y + 8; + + ptlWork.y -= lHight + 2; + + /* Make sure it is visible on the screen */ + if(ptlWork.x + lWidth > dw_screen_width()) + { + ptlWork.x = dw_screen_width() - lWidth; + if(ptlWork.x < 0) + ptlWork.x = 0; + } + + bubbleproc = (void *)WinSubclassWindow(hwndBubble, _BubbleProc); + + if(bubbleproc) + WinSetWindowPtr(hwndBubble, QWP_USER, bubbleproc); + + WinSetWindowPos(hwndBubble, + HWND_TOP, + ptlWork.x, + ptlWork.y, + lWidth, + lHight, + SWP_SIZE | SWP_MOVE | SWP_SHOW); + + /* Start a timer to remove it after 15 seconds */ + WinStartTimer(dwhab, hwnd, 2, 15000); + hend = hwnd; + } + } + break; + } + return (MRESULT)FALSE; +} #define CALENDAR_BORDER 3 #define CALENDAR_ARROW 8 @@ -1634,13 +1877,15 @@ return rclPaint; } +/* These will be filled in during dw_init() */ +static char months[12][20]; +static char daysofweek[7][20]; + /* This procedure handles drawing of a status border */ MRESULT EXPENTRY _calendarproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2) { /* How many days are in each month usually (not including leap years) */ static int days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - static char *months[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; - static char *daysofweek[] = { "Sunday", "Monday", "Tuesday","Wednesday", "Thursday", "Friday", "Saturday" }; WindowData *blah = (WindowData *)WinQueryWindowPtr(hWnd, QWP_USER); PFNWP oldproc = 0; @@ -1648,6 +1893,9 @@ { oldproc = blah->oldproc; + if(blah->bubbletext[0]) + _TooltipProc(hWnd, msg, mp1, mp2, blah); + switch(msg) { case WM_BUTTON1DOWN: @@ -1883,14 +2131,21 @@ /* This procedure handles drawing of a status border */ MRESULT EXPENTRY _statusproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2) { - PFNWP *blah = WinQueryWindowPtr(hWnd, QWP_USER); + WindowData *blah = (WindowData *)WinQueryWindowPtr(hWnd, QWP_USER); + PFNWP oldproc = 0; if(msg == WM_MOUSEMOVE && _wndproc(hWnd, msg, mp1, mp2)) return MPFROMSHORT(FALSE); - if(blah && *blah) - { - PFNWP myfunc = *blah; + if(blah) + { + oldproc = blah->oldproc; + + if(blah->bubbletext[0]) + _TooltipProc(hWnd, msg, mp1, mp2, blah); + + if(blah->bubbletext[0]) + _TooltipProc(hWnd, msg, mp1, mp2, blah); switch(msg) { @@ -1925,7 +2180,8 @@ return (MRESULT)TRUE; } } - return myfunc(hWnd, msg, mp1, mp2); + if(oldproc) + return oldproc(hWnd, msg, mp1, mp2); } return WinDefWindowProc(hWnd, msg, mp1, mp2); @@ -1934,16 +2190,31 @@ /* This procedure handles pointer changes */ MRESULT EXPENTRY _textproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2) { - PFNWP *blah = WinQueryWindowPtr(hWnd, QWP_USER); + WindowData *blah = (WindowData *)WinQueryWindowPtr(hWnd, QWP_USER); + + if(blah && blah->bubbletext[0]) + _TooltipProc(hWnd, msg, mp1, mp2, blah); if(msg == WM_MOUSEMOVE &&_wndproc(hWnd, msg, mp1, mp2)) return MPFROMSHORT(FALSE); - if(blah && *blah) - { - PFNWP myfunc = *blah; - - return myfunc(hWnd, msg, mp1, mp2); + if(blah && blah->oldproc) + { + PFNWP myfunc = blah->oldproc; + + switch(msg) + { + case WM_PAINT: + { + HPS hpsPaint = WinBeginPaint(hWnd, 0, 0); + + _drawtext(hWnd, hpsPaint); + WinEndPaint(hpsPaint); + return (MRESULT)TRUE; + } + default: + return myfunc(hWnd, msg, mp1, mp2); + } } return WinDefWindowProc(hWnd, msg, mp1, mp2); @@ -1952,10 +2223,10 @@ /* This procedure handles scrollbox */ MRESULT EXPENTRY _scrollwndproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2) { - switch(msg) - { - case WM_PAINT: - { + switch(msg) + { + case WM_PAINT: + { HPS hpsPaint; RECTL rclPaint; @@ -1963,80 +2234,79 @@ WinQueryWindowRect(hWnd, &rclPaint); WinFillRect(hpsPaint, &rclPaint, CLR_PALEGRAY); WinEndPaint(hpsPaint); - break; - } - case WM_HSCROLL: - case WM_VSCROLL: - { - MPARAM res; - int *pos, min, max, page, which = SHORT2FROMMP(mp2); - HWND handle, client = WinWindowFromID(hWnd, FID_CLIENT); - HWND box = (HWND)dw_window_get_data(hWnd, "_dw_resizebox"); - HWND hscroll = WinWindowFromID(hWnd, FID_HORZSCROLL); - HWND vscroll = WinWindowFromID(hWnd, FID_VERTSCROLL); + } + case WM_HSCROLL: + case WM_VSCROLL: + { + MPARAM res; + int *pos, min, max, page, which = SHORT2FROMMP(mp2); + HWND handle, client = WinWindowFromID(hWnd, FID_CLIENT); + HWND box = (HWND)dw_window_get_data(hWnd, "_dw_resizebox"); + HWND hscroll = WinWindowFromID(hWnd, FID_HORZSCROLL); + HWND vscroll = WinWindowFromID(hWnd, FID_VERTSCROLL); int hpos = dw_scrollbar_get_pos(hscroll); int vpos = dw_scrollbar_get_pos(vscroll); - int cy = (int)dw_window_get_data(hWnd, "_dw_cy"); + int cy = (int)dw_window_get_data(hWnd, "_dw_cy"); RECTL rect; - WinQueryWindowRect(client, &rect); - - if(msg == WM_VSCROLL) - { - page = rect.yTop - rect.yBottom; - handle = vscroll; + WinQueryWindowRect(client, &rect); + + if(msg == WM_VSCROLL) + { + page = rect.yTop - rect.yBottom; + handle = vscroll; pos = &vpos; - } - else - { - page = rect.xRight - rect.xLeft; - handle = hscroll; + } + else + { + page = rect.xRight - rect.xLeft; + handle = hscroll; pos = &hpos; - } - - res = WinSendMsg(handle, SBM_QUERYRANGE, 0, 0); - min = SHORT1FROMMP(res); - max = SHORT2FROMMP(res); - - switch(which) - { - case SB_SLIDERTRACK: + } + + res = WinSendMsg(handle, SBM_QUERYRANGE, 0, 0); + min = SHORT1FROMMP(res); + max = SHORT2FROMMP(res); + + switch(which) + { + case SB_SLIDERTRACK: *pos = SHORT1FROMMP(mp2); break; - case SB_LINEUP: - (*pos)--; - if(*pos < min) - *pos = min; + case SB_LINEUP: + (*pos)--; + if(*pos < min) + *pos = min; break; - case SB_LINEDOWN: - (*pos)++; - if(*pos > max) - *pos = max; + case SB_LINEDOWN: + (*pos)++; + if(*pos > max) + *pos = max; break; - case SB_PAGEUP: - (*pos) -= page; - if(*pos < min) - *pos = min; + case SB_PAGEUP: + (*pos) -= page; + if(*pos < min) + *pos = min; break; - case SB_PAGEDOWN: - (*pos) += page; - if(*pos > max) - *pos = max; - break; - } + case SB_PAGEDOWN: + (*pos) += page; + if(*pos > max) + *pos = max; + break; + } WinSendMsg(handle, SBM_SETPOS, (MPARAM)*pos, 0); /* Position the scrolled box */ WinSetWindowPos(box, HWND_TOP, -hpos, -(cy - vpos), 0, 0, SWP_MOVE); - break; - } - } - return WinDefWindowProc(hWnd, msg, mp1, mp2); + break; + } + } + return WinDefWindowProc(hWnd, msg, mp1, mp2); } void _click_default(HWND handle) { - char tmpbuf[100]; + char tmpbuf[100] = {0}; WinQueryClassName(handle, 99, (PCH)tmpbuf); @@ -2053,7 +2323,7 @@ { if(tmp->message == WM_COMMAND) { - int (* API clickfunc)(HWND, void *) = (int (* API)(HWND, void *))tmp->signalfunction; + int (API_FUNC clickfunc)(HWND, void *) = (int (API_FUNC)(HWND, void *))tmp->signalfunction; /* Make sure it's the right window, and the right ID */ if(tmp->window == handle) @@ -2076,6 +2346,103 @@ #define ENTRY_UNDO 60904 #define ENTRY_SALL 60905 +#ifdef UNICODE +void _combine_text(HWND handle, USHORT pos1, char *text, char *pastetext) +{ + char *combined = calloc((text ? strlen(text) : 0) + strlen(pastetext) + 1, 1); + SHORT newsel = pos1 + strlen(pastetext); + + /* Combine the two strings into 1... or just use pastetext if no text */ + if(text) + strncpy(combined, text, pos1); + strcat(combined, pastetext); + if(text && pos1 < strlen(text)) + strcat(combined, &text[pos1]); + + /* Set the new combined text to the entryfield */ + dw_window_set_text(handle, combined); + /* Move the cursor to the old selection start plus paste length */ + WinSendMsg(handle, EM_SETSEL, MPFROM2SHORT(newsel, newsel), 0); + /* Free temporary memory */ + free(combined); +} + +/* Internal function to handle Unicode enabled MLE cut, copy and paste */ +void _MleCopyPaste(HWND hWnd, int command) +{ + /* MLE insertion points (for querying selection) */ + IPT ipt1, ipt2; + + /* Get the selected text */ + ipt1 = (IPT)WinSendMsg(hWnd, MLM_QUERYSEL, MPFROMSHORT(MLFQS_MINSEL), 0); + ipt2 = (IPT)WinSendMsg(hWnd, MLM_QUERYSEL, MPFROMSHORT(MLFQS_MAXSEL), 0); + + /* Get the selection and put on clipboard for copy and cut */ + if(command != ENTRY_PASTE) + { + char *text = (char *)malloc((ULONG)WinSendMsg(hWnd, MLM_QUERYFORMATTEXTLENGTH, MPFROMLONG(ipt1), MPFROMLONG(ipt2 - ipt1)) + 1); + ULONG ulCopied = (ULONG)WinSendMsg(hWnd, MLM_QUERYSELTEXT, MPFROMP(text), 0); + + dw_clipboard_set_text(text, ulCopied); + free(text); + } + /* Clear selection for cut and paste */ + if(command != ENTRY_COPY) + WinSendMsg(hWnd, MLM_CLEAR, 0, 0); + if(command == ENTRY_PASTE) + { + char *text = dw_clipboard_get_text(); + + if(text) + { + WinSendMsg(hWnd, MLM_INSERT, MPFROMP(text), 0); + dw_free(text); + } + } +} + +/* Internal function to handle Unicode enabled Entryfield cut, copy and paste */ +void _EntryCopyPaste(HWND handle, int command) +{ + /* Get the selected text */ + char *text = dw_window_get_text(handle); + ULONG sel = (ULONG)WinSendMsg(handle, EM_QUERYSEL, 0, 0); + SHORT pos1 = SHORT1FROMMP(sel), pos2 = SHORT2FROMMP(sel); + + /* Get the selection and put on clipboard for copy and cut */ + if(text) + { + if(command != ENTRY_PASTE) + { + if(pos2 > pos1) + { + text[pos2] = 0; + + dw_clipboard_set_text(&text[pos1], pos2 - pos1); + } + } + free(text); + } + /* Clear selection for cut and paste */ + if(command != ENTRY_COPY) + WinSendMsg(handle, EM_CLEAR, 0, 0); + text = dw_window_get_text(handle); + if(command == ENTRY_PASTE) + { + char *pastetext = dw_clipboard_get_text(); + + if(pastetext) + { + _combine_text(handle, pos1, text, pastetext); + /* Free temporary memory */ + dw_free(pastetext); + } + } + if(text) + free(text); +} +#endif + /* Originally just intended for entryfields, it now serves as a generic * procedure for handling TAB presses to change input focus on controls. */ @@ -2083,13 +2450,16 @@ { WindowData *blah = (WindowData *)WinQueryWindowPtr(hWnd, QWP_USER); PFNWP oldproc = 0; - char tmpbuf[100]; + char tmpbuf[100] = {0}; if(blah) oldproc = blah->oldproc; WinQueryClassName(hWnd, 99, (PCH)tmpbuf); + if(blah && blah->bubbletext[0]) + _TooltipProc(hWnd, msg, mp1, mp2, blah); + /* These are the window classes which should get a menu */ if(strncmp(tmpbuf, "#2", 3)==0 || /* Combobox */ strncmp(tmpbuf, "#6", 3)==0 || /* Entryfield */ @@ -2098,6 +2468,26 @@ { switch(msg) { +#ifdef UNICODE + case MLM_PASTE: + _MleCopyPaste(hWnd, ENTRY_PASTE); + return (MRESULT)TRUE; + case MLM_CUT: + _MleCopyPaste(hWnd, ENTRY_CUT); + return (MRESULT)TRUE; + case MLM_COPY: + _MleCopyPaste(hWnd, ENTRY_COPY); + return (MRESULT)TRUE; + case EM_PASTE: + _EntryCopyPaste(hWnd, ENTRY_PASTE); + return (MRESULT)TRUE; + case EM_CUT: + _EntryCopyPaste(hWnd, ENTRY_CUT); + return (MRESULT)TRUE; + case EM_COPY: + _EntryCopyPaste(hWnd, ENTRY_COPY); + return (MRESULT)TRUE; +#endif case WM_CONTEXTMENU: { HMENUI hwndMenu = dw_menu_new(0L); @@ -2188,11 +2578,11 @@ } break; case WM_CONTROL: - { - if(strncmp(tmpbuf, "#38", 4)==0) - _run_event(hWnd, msg, mp1, mp2); - } - break; + { + if(strncmp(tmpbuf, "#38", 4)==0) + _run_event(hWnd, msg, mp1, mp2); + } + break; case WM_SETFOCUS: _run_event(hWnd, msg, mp1, mp2); break; @@ -2214,7 +2604,52 @@ */ else if(SHORT1FROMMP(mp2) == 283) return (MRESULT)TRUE; - +#ifdef UNICODE + else if(!SHORT1FROMMP(mp2)) + { + UniChar uc[2] = {0}; + VDKEY vdk; + BYTE bscan; + char *utf8; + + UniTranslateKey(Keyboard, SHORT1FROMMP(mp1) & KC_SHIFT ? 1 : 0, CHAR4FROMMP(mp1), uc, &vdk, &bscan); + + if((utf8 = _WideToUTF8(uc)) != NULL) + { + if(*utf8) + { + /* MLE */ + if(strncmp(tmpbuf, "#10", 4)==0) + { + WinSendMsg(hWnd, MLM_INSERT, MPFROMP(utf8), 0); + } + else /* Other */ + { + HWND handle = hWnd; + + /* Get the entryfield handle from multi window controls */ + if(strncmp(tmpbuf, "#2", 3)==0) + handle = WinWindowFromID(hWnd, 667); + + if(handle) + { + char *text = dw_window_get_text(handle); + ULONG sel = (ULONG)WinSendMsg(hWnd, EM_QUERYSEL, 0, 0); + SHORT pos1 = SHORT1FROMMP(sel); + + WinSendMsg(handle, EM_CLEAR, 0, 0); + _combine_text(handle, pos1, text, utf8); + + if(text) + free(text); + } + } + } + free(utf8); + } + return (MRESULT)TRUE; + } +#endif break; case WM_SIZE: { @@ -2246,6 +2681,9 @@ { WindowData *blah = (WindowData *)WinQueryWindowPtr(hWnd, QWP_USER); + if(blah && blah->bubbletext[0]) + _TooltipProc(hWnd, msg, mp1, mp2, blah); + switch(msg) { case WM_MOUSEMOVE: @@ -2254,6 +2692,11 @@ break; case WM_CONTEXTMENU: case WM_COMMAND: +#ifdef UNICODE + case EM_PASTE: + case EM_CUT: + case EM_COPY: +#endif return _entryproc(hWnd, msg, mp1, mp2); case WM_SETFOCUS: _run_event(hWnd, msg, mp1, mp2); @@ -2299,6 +2742,9 @@ if(blah) oldproc = blah->oldproc; + if(blah && blah->bubbletext[0]) + _TooltipProc(hWnd, msg, mp1, mp2, blah); + switch(msg) { case WM_MOUSEMOVE: @@ -2307,7 +2753,12 @@ break; case WM_CONTEXTMENU: case WM_COMMAND: - return _entryproc(hWnd, msg, mp1, mp2); +#ifdef UNICODE + case EM_PASTE: + case EM_CUT: + case EM_COPY: +#endif + return _entryproc(hWnd, msg, mp1, mp2); } if(oldproc) @@ -2348,6 +2799,9 @@ if(blah) oldproc = blah->oldproc; + if(blah && blah->bubbletext[0]) + _TooltipProc(hWnd, msg, mp1, mp2, blah); + switch(msg) { case WM_MOUSEMOVE: @@ -2379,6 +2833,9 @@ if(blah) oldproc = blah->oldproc; + if(blah && blah->bubbletext[0]) + _TooltipProc(hWnd, msg, mp1, mp2, blah); + switch(msg) { case WM_MOUSEMOVE: @@ -2577,7 +3034,7 @@ { if((mp2 && tmp->message == WM_SETFOCUS) || (!mp2 && tmp->message == WM_USER+1)) { - int (* API setfocusfunc)(HWND, void *) = (int (* API)(HWND, void *))tmp->signalfunction; + int (API_FUNC setfocusfunc)(HWND, void *) = (int (API_FUNC)(HWND, void *))tmp->signalfunction; if(hWnd == tmp->window || WinWindowFromID(tmp->window, FID_CLIENT) == hWnd) { @@ -2589,7 +3046,7 @@ break; case WM_TIMER: { - int (* API timerfunc)(void *) = (int (* API)(void *))tmp->signalfunction; + int (API_FUNC timerfunc)(void *) = (int (API_FUNC)(void *))tmp->signalfunction; if(tmp->id == (int)mp1) { if(!timerfunc(tmp->data)) @@ -2601,7 +3058,7 @@ break; case WM_SIZE: { - int (* API sizefunc)(HWND, int, int, void *) = (int (* API)(HWND, int, int, void *))tmp->signalfunction; + int (API_FUNC sizefunc)(HWND, int, int, void *) = (int (API_FUNC)(HWND, int, int, void *))tmp->signalfunction; if((hWnd == tmp->window || WinWindowFromID(tmp->window, FID_CLIENT) == hWnd) && SHORT1FROMMP(mp2) && SHORT2FROMMP(mp2)) { @@ -2613,7 +3070,7 @@ case WM_BUTTON1DOWN: { POINTS pts = (*((POINTS*)&mp1)); - int (* API buttonfunc)(HWND, int, int, int, void *) = (int (* API)(HWND, int, int, int, void *))tmp->signalfunction; + int (API_FUNC buttonfunc)(HWND, int, int, int, void *) = (int (API_FUNC)(HWND, int, int, int, void *))tmp->signalfunction; if(hWnd == tmp->window || WinWindowFromID(tmp->window, FID_CLIENT) == hWnd || WinQueryCapture(HWND_DESKTOP) == tmp->window) { @@ -2640,7 +3097,7 @@ case WM_BUTTON1UP: { POINTS pts = (*((POINTS*)&mp1)); - int (* API buttonfunc)(HWND, int, int, int, void *) = (int (* API)(HWND, int, int, int, void *))tmp->signalfunction; + int (API_FUNC buttonfunc)(HWND, int, int, int, void *) = (int (API_FUNC)(HWND, int, int, int, void *))tmp->signalfunction; if(hWnd == tmp->window || WinWindowFromID(tmp->window, FID_CLIENT) == hWnd || WinQueryCapture(HWND_DESKTOP) == tmp->window) { @@ -2666,7 +3123,7 @@ break; case WM_MOUSEMOVE: { - int (* API motionfunc)(HWND, int, int, int, void *) = (int (* API)(HWND, int, int, int, void *))tmp->signalfunction; + int (API_FUNC motionfunc)(HWND, int, int, int, void *) = (int (API_FUNC)(HWND, int, int, int, void *))tmp->signalfunction; if(hWnd == tmp->window || WinWindowFromID(tmp->window, FID_CLIENT) == hWnd || WinQueryCapture(HWND_DESKTOP) == tmp->window) { @@ -2687,15 +3144,23 @@ break; case WM_CHAR: { - int (* API keypressfunc)(HWND, char, int, int, void *) = (int (* API)(HWND, char, int, int, void *))tmp->signalfunction; - - if((hWnd == tmp->window || _toplevel_window(hWnd) == tmp->window) && !(SHORT1FROMMP(mp1) & KC_KEYUP)) - { + int (API_FUNC keypressfunc)(HWND, char, int, int, void *, char *) = (int (API_FUNC)(HWND, char, int, int, void *, char *))tmp->signalfunction; + + if((hWnd == tmp->window || _toplevel_window(hWnd) == tmp->window) && !(SHORT1FROMMP(mp1) & KC_KEYUP)) + { int vk; - char ch = 0; + char ch[2] = {0}; + char *utf8 = NULL; +#ifdef UNICODE + UniChar uc[2] = {0}; + VDKEY vdk; + BYTE bscan; + UniTranslateKey(Keyboard, SHORT1FROMMP(mp1) & KC_SHIFT ? 1 : 0, CHAR4FROMMP(mp1), uc, &vdk, &bscan); + utf8 = _WideToUTF8(uc); +#endif if(SHORT1FROMMP(mp1) & KC_CHAR) - ch = (char)SHORT1FROMMP(mp2); + ch[0] = (char)SHORT1FROMMP(mp2); if(SHORT1FROMMP(mp1) & KC_VIRTUALKEY) vk = SHORT2FROMMP(mp2); else @@ -2704,21 +3169,24 @@ /* This is a hack to fix shift presses showing * up as tabs! */ - if(ch == '\t' && !(SHORT1FROMMP(mp1) & KC_CHAR)) + if(ch[0] == '\t' && !(SHORT1FROMMP(mp1) & KC_CHAR)) { - ch = 0; + ch[0] = 0; vk = VK_SHIFT; } - result = keypressfunc(tmp->window, ch, vk, - SHORT1FROMMP(mp1) & (KC_ALT | KC_SHIFT | KC_CTRL), tmp->data); + result = keypressfunc(tmp->window, ch[0], vk, + SHORT1FROMMP(mp1) & (KC_ALT | KC_SHIFT | KC_CTRL), tmp->data, utf8 ? utf8 : ch); tmp = NULL; + + if(utf8) + free(utf8); } } break; case WM_CLOSE: { - int (* API closefunc)(HWND, void *) = (int (* API)(HWND, void *))tmp->signalfunction; + int (API_FUNC closefunc)(HWND, void *) = (int (API_FUNC)(HWND, void *))tmp->signalfunction; if(hWnd == tmp->window || hWnd == WinWindowFromID(tmp->window, FID_CLIENT)) { @@ -2733,7 +3201,7 @@ { HPS hps; DWExpose exp; - int (* API exposefunc)(HWND, DWExpose *, void *) = (int (* API)(HWND, DWExpose *, void *))tmp->signalfunction; + int (API_FUNC exposefunc)(HWND, DWExpose *, void *) = (int (API_FUNC)(HWND, DWExpose *, void *))tmp->signalfunction; RECTL rc; if(hWnd == tmp->window) @@ -2742,7 +3210,7 @@ hps = WinBeginPaint(hWnd, 0L, &rc); exp.x = rc.xLeft; - exp.y = height - rc.yTop - 1; + exp.y = height - rc.yTop; exp.width = rc.xRight - rc. xLeft; exp.height = rc.yTop - rc.yBottom; result = exposefunc(hWnd, &exp, tmp->data); @@ -2752,7 +3220,7 @@ break; case WM_COMMAND: { - int (* API clickfunc)(HWND, void *) = (int (* API)(HWND, void *))tmp->signalfunction; + int (API_FUNC clickfunc)(HWND, void *) = (int (API_FUNC)(HWND, void *))tmp->signalfunction; ULONG command = COMMANDMSG(&msg)->cmd; if(tmp->id && command == tmp->id) @@ -2774,20 +3242,24 @@ break; case WM_CONTROL: if(origmsg == WM_VSCROLL || origmsg == WM_HSCROLL || tmp->message == SHORT2FROMMP(mp1) || - (tmp->message == SLN_SLIDERTRACK && SHORT2FROMMP(mp1) == SLN_CHANGE)) + (tmp->message == SLN_SLIDERTRACK && (SHORT2FROMMP(mp1) == SLN_CHANGE || SHORT2FROMMP(mp1) == SPBN_CHANGE))) { int svar = SLN_SLIDERTRACK; int id = SHORT1FROMMP(mp1); HWND notifyhwnd = dw_window_from_id(hWnd, id); if(origmsg == WM_CONTROL) - svar = SHORT2FROMMP(mp1); + { + svar = SHORT2FROMMP(mp1); + if(!notifyhwnd && WinIsWindow(dwhab, (HWND)mp2)) + notifyhwnd = (HWND)mp2; + } switch(svar) { case CN_ENTER: { - int (* API containerselectfunc)(HWND, char *, void *) = (int (* API)(HWND, char *, void *))tmp->signalfunction; + int (API_FUNC containerselectfunc)(HWND, char *, void *) = (int (API_FUNC)(HWND, char *, void *))tmp->signalfunction; char *text = NULL; if(mp2) @@ -2808,7 +3280,7 @@ break; case CN_EXPANDTREE: { - int (* API treeexpandfunc)(HWND, HTREEITEM, void *) = (int (* API)(HWND, HTREEITEM, void *))tmp->signalfunction; + int (API_FUNC treeexpandfunc)(HWND, HTREEITEM, void *) = (int (API_FUNC)(HWND, HTREEITEM, void *))tmp->signalfunction; if(tmp->window == notifyhwnd) { @@ -2819,7 +3291,7 @@ break; case CN_CONTEXTMENU: { - int (* API containercontextfunc)(HWND, char *, int, int, void *, void *) = (int (* API)(HWND, char *, int, int, void *, void *))tmp->signalfunction; + int (API_FUNC containercontextfunc)(HWND, char *, int, int, void *, void *) = (int (API_FUNC)(HWND, char *, int, int, void *, void *))tmp->signalfunction; char *text = NULL; void *user = NULL; LONG x,y; @@ -2884,7 +3356,7 @@ if(pci && pre->fEmphasisMask & CRA_CURSORED && (pci->rc.flRecordAttr & CRA_CURSORED)) { - int (* API treeselectfunc)(HWND, HTREEITEM, char *, void *, void *) = (int (* API)(HWND, HTREEITEM, char *, void *, void *))tmp->signalfunction; + int (API_FUNC treeselectfunc)(HWND, HTREEITEM, char *, void *, void *) = (int (API_FUNC)(HWND, HTREEITEM, char *, void *, void *))tmp->signalfunction; if(dw_window_get_data(tmp->window, "_dw_container")) result = treeselectfunc(tmp->window, 0, (char *)pci->rc.pszIcon, tmp->data, 0); @@ -2916,9 +3388,10 @@ WinQueryClassName(tmp->window, 99, (PCH)classbuf); + /* Slider/Percent */ if(strncmp(classbuf, "#38", 4) == 0) { - int (* API valuechangedfunc)(HWND, int, void *) = (int (* API)(HWND, int, void *))tmp->signalfunction; + int (API_FUNC valuechangedfunc)(HWND, int, void *) = (int (API_FUNC)(HWND, int, void *))tmp->signalfunction; if(tmp->window == hWnd || tmp->window == notifyhwnd) { @@ -2936,7 +3409,7 @@ } else { - int (* API listboxselectfunc)(HWND, int, void *) = (int (* API )(HWND, int, void *))tmp->signalfunction; + int (API_FUNC listboxselectfunc)(HWND, int, void *) = (int (API_FUNC)(HWND, int, void *))tmp->signalfunction; static int _recursing = 0; if(_recursing == 0 && (tmp->window == notifyhwnd || (!id && tmp->window == (HWND)mp2))) @@ -2948,6 +3421,7 @@ _recursing = 1; + /* Combobox */ if(id && strncmp(classbuf, "#2", 3)==0) { char *buf2; @@ -2972,9 +3446,25 @@ } } break; + case SPBN_CHANGE: + { + int (API_FUNC valuechangedfunc)(HWND, int, void *) = (int (API_FUNC)(HWND, int, void *))tmp->signalfunction; + + if(origmsg == WM_CONTROL && tmp->message == SLN_SLIDERTRACK) + { + /* Handle Spinbutton control */ + if(tmp->window == hWnd || tmp->window == notifyhwnd) + { + int position = dw_spinbutton_get_pos(tmp->window); + result = valuechangedfunc(tmp->window, position, tmp->data); + tmp = NULL; + } + } + } + break; case SLN_SLIDERTRACK: { - int (* API valuechangedfunc)(HWND, int, void *) = (int (* API)(HWND, int, void *))tmp->signalfunction; + int (API_FUNC valuechangedfunc)(HWND, int, void *) = (int (API_FUNC)(HWND, int, void *))tmp->signalfunction; if(origmsg == WM_CONTROL) { @@ -3018,7 +3508,7 @@ if(psn && tmp->window == psn->hwndBook) { - int (* API switchpagefunc)(HWND, unsigned long, void *) = (int (* API)(HWND, unsigned long, void *))tmp->signalfunction; + int (API_FUNC switchpagefunc)(HWND, unsigned long, void *) = (int (API_FUNC)(HWND, unsigned long, void *))tmp->signalfunction; result = switchpagefunc(tmp->window, psn->ulPageIdNew, tmp->data); tmp = NULL; @@ -3035,6 +3525,12 @@ tmp = tmp->next; } + if(result != -1) + { + /* Make sure any queued redraws are handled */ + _dw_redraw(0, FALSE); + /* Then finally return */ + } return (MRESULT)result; } @@ -3104,20 +3600,35 @@ _dw_color_spin_set(window, DW_RGB((val & 0xFF0000) >> 16, (val & 0xFF00) >> 8, val & 0xFF)); } break; + case WM_USER: + _run_event(hWnd, WM_CONTROL, mp1, mp2); + break; case WM_CONTROL: - if((SHORT2FROMMP(mp1) == SPBN_CHANGE || SHORT2FROMMP(mp1) == SPBN_ENDSPIN)) - { - HWND window = (HWND)dw_window_get_data(hWnd, "_dw_window"); - - if(window && !dw_window_get_data(window, "_dw_updating")) - { - unsigned long val = _dw_color_spin_get(window); - HWND col = (HWND)dw_window_get_data(window, "_dw_col"); - - _dw_col_set(col, val); - } - } - _run_event(hWnd, msg, mp1, mp2); + { + char tmpbuf[100]; + + WinQueryClassName((HWND)mp2, 99, (PCH)tmpbuf); + /* Don't set the ownership if it's an entryfield or spinbutton */ + if(strncmp(tmpbuf, "#32", 4)==0) + { + if((SHORT2FROMMP(mp1) == SPBN_CHANGE || SHORT2FROMMP(mp1) == SPBN_ENDSPIN)) + { + HWND window = (HWND)dw_window_get_data(hWnd, "_dw_window"); + + if(window && !dw_window_get_data(window, "_dw_updating")) + { + unsigned long val = _dw_color_spin_get(window); + HWND col = (HWND)dw_window_get_data(window, "_dw_col"); + + _dw_col_set(col, val); + } + } + if(!dw_window_get_data((HWND)mp2, "_dw_updating")) + WinPostMsg(hWnd, WM_USER, mp1, mp2); + } + else + _run_event(hWnd, msg, mp1, mp2); + } break; } @@ -3132,7 +3643,7 @@ { int result = -1; static int command_active = 0; - void (* API windowfunc)(PVOID) = 0L; + void (API_FUNC windowfunc)(PVOID) = 0L; if(!command_active) { @@ -3282,7 +3793,7 @@ } return MRFROMSHORT(FALSE); case WM_USER: - windowfunc = (void (* API)(void *))mp1; + windowfunc = (void (API_FUNC)(void *))mp1; if(windowfunc) windowfunc((void *)mp2); @@ -3533,60 +4044,6 @@ return WinDefWindowProc(hwnd, msg, mp1, mp2); } -/* Function: BubbleProc - * Abstract: Subclass procedure for bubble help - */ -MRESULT EXPENTRY _BubbleProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) -{ - MRESULT res; - PFNWP proc = (PFNWP)WinQueryWindowPtr(hwnd, QWL_USER); - - if(proc) - res = proc(hwnd, msg, mp1, mp2); - else - res = WinDefWindowProc(hwnd, msg, mp1, mp2); - - if(msg == WM_PAINT) - { - POINTL ptl; - HPS hpsTemp; - RECTL rcl; - int height, width; - - WinQueryWindowRect(hwnd, &rcl); - height = rcl.yTop - rcl.yBottom - 1; - width = rcl.xRight - rcl.xLeft - 1; - - /* Draw a border around the bubble help */ - hpsTemp = WinGetPS(hwnd); - GpiSetColor(hpsTemp, CLR_BLACK); - ptl.x = ptl.y = 0; - GpiMove(hpsTemp, &ptl); - ptl.x = 0; - ptl.y = height; - GpiLine(hpsTemp, &ptl); - ptl.x = ptl.y = 0; - GpiMove(hpsTemp, &ptl); - ptl.y = 0; - ptl.x = width; - GpiLine(hpsTemp, &ptl); - ptl.x = width; - ptl.y = height; - GpiMove(hpsTemp, &ptl); - ptl.x = 0; - ptl.y = height; - GpiLine(hpsTemp, &ptl); - ptl.x = width; - ptl.y = height; - GpiMove(hpsTemp, &ptl); - ptl.y = 0; - ptl.x = width; - GpiLine(hpsTemp, &ptl); - WinReleasePS(hpsTemp); - } - return res; -} - MRESULT EXPENTRY _button_draw(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2, PFNWP oldproc, int indent) { HPIXMAP pixmap = (HPIXMAP)dw_window_get_data(hwnd, "_dw_hpixmap"); @@ -3595,6 +4052,7 @@ MRESULT res; unsigned long width, height; int x = 5, y = 5; + ULONG style = WinQueryWindowULong(hwnd, QWL_STYLE); dw_window_get_pos_size(hwnd, NULL, NULL, &width, &height); @@ -3612,33 +4070,62 @@ if(dw_window_get_data(hwnd, "_dw_disabled")) halftone = DP_HALFTONED; - cx = width - 10; - cy = height - 10; + /* If there is a border take that into account */ + if(style & BS_NOBORDER) + { + cx = width; + cy = height; + } + else + { + cx = width - 8; + cy = height - 8; + } if(WinQueryPointerInfo(icon, &pi)) { BITMAPINFOHEADER sl; int newcx = cx, newcy = cy; + sl.cbFix = sizeof(BITMAPINFOHEADER); + /* Check the mini icon first */ if(GpiQueryBitmapParameters(pi.hbmMiniColor, &sl)) { - if(sl.cx && sl.cy && cx > sl.cx && cy > sl.cy) - { - newcx = sl.cx; - newcy = sl.cy; - } + if(sl.cx && sl.cy && cx > sl.cx && cy > sl.cy) + { + newcx = sl.cx; + newcy = sl.cy; + } } /* Check the normal icon second */ if(GpiQueryBitmapParameters(pi.hbmColor, &sl)) { - if(sl.cx && sl.cy && cx > sl.cx && cy > sl.cy) - { - newcx = sl.cx; - newcy = sl.cy; - } + if(sl.cx && sl.cy) + { + if(cx > sl.cx && cy > sl.cy) + { + newcx = sl.cx; + newcy = sl.cy; + } + /* In case there was no mini icon... cut it in half */ + else if(cx >= (sl.cx/2) && cy >= (sl.cy/2)) + { + newcx = sl.cx/2; + newcy = sl.cy/2; + } + } } cx = newcx; cy = newcy; + /* Safety check to avoid icon dimension stretching */ + if(cx != cy) + { + if(cx > cy) + cx = cy; + else + cy = cx; + } + /* Finally center it in the window */ x = (width - cx)/2; y = (height - cy)/2; } @@ -3664,15 +4151,17 @@ MRESULT EXPENTRY _BtProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { - BubbleButton *bubble; + WindowData *blah = WinQueryWindowPtr(hwnd, QWL_USER); PFNWP oldproc; - - bubble = (BubbleButton *)WinQueryWindowPtr(hwnd, QWL_USER); - - if(!bubble) + int retval = -1; + + if(!blah) return WinDefWindowProc(hwnd, msg, mp1, mp2); - oldproc = bubble->pOldProc; + oldproc = blah->oldproc; + + if(blah->bubbletext[0]) + _TooltipProc(hwnd, msg, mp1, mp2, blah); switch(msg) { @@ -3741,14 +4230,14 @@ break; case WM_USER: { - SignalHandler *tmp = (SignalHandler *)mp1; - int (* API clickfunc)(HWND, void *) = NULL; + SignalHandler *tmp = (SignalHandler *)mp1; + int (API_FUNC clickfunc)(HWND, void *) = NULL; if(tmp) { - clickfunc = (int (* API)(HWND, void *))tmp->signalfunction; - - clickfunc(tmp->window, tmp->data); + clickfunc = (int (API_FUNC)(HWND, void *))tmp->signalfunction; + + retval = clickfunc(tmp->window, tmp->data); } } break; @@ -3798,97 +4287,11 @@ } } break; - case 0x041f: - if (hwndBubble) - { - WinDestroyWindow(hwndBubble); - hwndBubble = 0; - } - break; - - case 0x041e: - - if(!*bubble->bubbletext) - break; - - if(hwndBubble) - { - WinDestroyWindow(hwndBubble); - hwndBubble = 0; - } - - if(!hwndBubble) - { - HPS hpsTemp = 0; - LONG lHight; - LONG lWidth; - POINTL txtPointl[TXTBOX_COUNT]; - POINTL ptlWork = {0,0}; - ULONG ulColor = CLR_YELLOW; - void *blah; - - hwndBubbleLast = hwnd; - hwndBubble = WinCreateWindow(HWND_DESKTOP, - WC_STATIC, - NULL, - SS_TEXT | - DT_CENTER | - DT_VCENTER, - 0,0,0,0, - HWND_DESKTOP, - HWND_TOP, - 0, - NULL, - NULL); - - WinSetPresParam(hwndBubble, - PP_FONTNAMESIZE, - strlen(DefaultFont)+1, - DefaultFont); - - - WinSetPresParam(hwndBubble, - PP_BACKGROUNDCOLORINDEX, - sizeof(ulColor), - &ulColor); - - WinSetWindowText(hwndBubble, - (PSZ)bubble->bubbletext); - - WinMapWindowPoints(hwnd, HWND_DESKTOP, &ptlWork, 1); - - hpsTemp = WinGetPS(hwndBubble); - GpiQueryTextBox(hpsTemp, - strlen(bubble->bubbletext), - (PCH)bubble->bubbletext, - TXTBOX_COUNT, - txtPointl); - WinReleasePS(hpsTemp); - - lWidth = txtPointl[TXTBOX_TOPRIGHT].x - - txtPointl[TXTBOX_TOPLEFT ].x + 8; - - lHight = txtPointl[TXTBOX_TOPLEFT].y - - txtPointl[TXTBOX_BOTTOMLEFT].y + 8; - - ptlWork.y -= lHight; - - blah = (void *)WinSubclassWindow(hwndBubble, _BubbleProc); - - if(blah) - WinSetWindowPtr(hwndBubble, QWP_USER, blah); - - WinSetWindowPos(hwndBubble, - HWND_TOP, - ptlWork.x, - ptlWork.y, - lWidth, - lHight, - SWP_SIZE | SWP_MOVE | SWP_SHOW); - } - break; - } - + } + + /* Make sure windows are up-to-date */ + if(retval != -1) + _dw_redraw(0, FALSE); if(!oldproc) return WinDefWindowProc(hwnd, msg, mp1, mp2); return oldproc(hwnd, msg, mp1, mp2); @@ -3896,8 +4299,12 @@ MRESULT EXPENTRY _RendProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { - int res = 0; - res = (int)_run_event(hwnd, msg, mp1, mp2); + WindowData *blah = (WindowData *)WinQueryWindowPtr(hwnd, QWP_USER); + int res = (int)_run_event(hwnd, msg, mp1, mp2); + + if(blah && blah->bubbletext[0]) + _TooltipProc(hwnd, msg, mp1, mp2, blah); + switch(msg) { case WM_MOUSEMOVE: @@ -3923,6 +4330,9 @@ if(blah) oldproc = blah->oldproc; + if(blah && blah->bubbletext[0]) + _TooltipProc(hwnd, msg, mp1, mp2, blah); + switch(msg) { case WM_MOUSEMOVE: @@ -3974,6 +4384,42 @@ return WinDefWindowProc(hwnd, msg, mp1, mp2); } +#ifdef UNICODE +/* Internal function to detect the active keyboard layout */ +UniChar *_detect_keyb(void) +{ + HFILE handle; + struct + { + USHORT length; + USHORT codepage; + CHAR strings[8]; + } kd; + ULONG action; + UniChar *buf = NULL; + + if(DosOpen((PSZ)"KBD$", &handle, &action, 0, 0, + OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, + NULL) == 0) + { + ULONG plen = 0, dlen = sizeof(kd); + + kd.length = dlen; + + if(DosDevIOCtl(handle, 4, 0x7b, NULL, plen, &plen, + &kd, dlen, &dlen) == 0 && strlen(kd.strings) > 0) + { + + /* Convert to Unicode */ + buf = _UTF8toWide(kd.strings); + } + DosClose (handle); + } + return buf; +} +#endif + /* * Initializes the Dynamic Windows engine. * Parameters: @@ -3984,18 +4430,68 @@ { APIRET rc; char objnamebuf[300] = ""; - - argc = argc; /* keep compiler happy */ - argv = argv; /* keep compiler happy */ + int x; + struct tm thistm = { 0 }; + + /* Setup the private data directory */ + if(argc > 0 && argv[0]) + { + char *pos = strrchr(argv[0], '\\'); + + /* Just to be safe try the unix style */ + if(!pos) + pos = strrchr(argv[0], '/'); + + if(pos) + strncpy(_dw_exec_dir, argv[0], (size_t)(pos - argv[0])); + } + /* If that failed... just get the current directory */ + if(!_dw_exec_dir[0]) + _getcwd(_dw_exec_dir, MAX_PATH); + if(newthread) { +#ifdef UNICODE + UniChar *kbd; + UniChar suCodepage[MAX_CP_SPEC]; /* conversion specifier */ +#endif dwhab = WinInitialize(0); dwhmq = WinCreateMsgQueue(dwhab, 0); +#ifdef UNICODE + /* Create the conversion object */ + UniMapCpToUcsCp(1208, suCodepage, MAX_CP_NAME); + UniStrcat(suCodepage, (UniChar *) L"@map=cdra,path=no"); + UniCreateUconvObject(suCodepage, &Uconv); + /* Create the Unicode atom for copy and paste */ + Unicode = WinAddAtom(WinQuerySystemAtomTable(), (PSZ)"text/unicode"); + /* Figure out how to determine the correct keyboard here */ + kbd = _detect_keyb(); + /* Default to US if could not detect */ + UniCreateKeyboard(&Keyboard, (UniChar *)kbd ? kbd : L"us", 0); + /* Free temporary memory */ + if(kbd) + free(kbd); + /* Set the codepage to 1208 (UTF-8) */ + WinSetCp(dwhmq, 1208); +#endif } rc = WinRegisterClass(dwhab, (PSZ)ClassName, _wndproc, CS_SIZEREDRAW | CS_CLIPCHILDREN, 32); rc = WinRegisterClass(dwhab, (PSZ)SplitbarClassName, _splitwndproc, 0L, 32); rc = WinRegisterClass(dwhab, (PSZ)ScrollClassName, _scrollwndproc, 0L, 32); + rc = WinRegisterClass(dwhab, (PSZ)CalendarClassName, _calendarproc, 0L, 32); + + /* Fill in the the calendar fields */ + for(x=0;x<7;x++) + { + thistm.tm_wday = x; + strftime(daysofweek[x], 19, "%A", &thistm); + } + for(x=0;x<12;x++) + { + thistm.tm_mon = x; + strftime(months[x], 19, "%B", &thistm); + } /* Get the OS/2 version. */ DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_MS_COUNT,(void *)aulBuffer, 4*sizeof(ULONG)); @@ -4018,9 +4514,33 @@ DosLoadModule((PSZ)objnamebuf, sizeof(objnamebuf), (PSZ)"WPCONFIG", &wpconfig); if(!DosLoadModule((PSZ)objnamebuf, sizeof(objnamebuf), (PSZ)"PMPRINTF", &pmprintf)) DosQueryProcAddr(pmprintf, 0, (PSZ)"PmPrintfString", (PFN*)&_PmPrintfString); + if(!DosLoadModule((PSZ)objnamebuf, sizeof(objnamebuf), (PSZ)"PMMERGE", &pmmerge)) + DosQueryProcAddr(pmmerge, 5469, NULL, (PFN*)&_WinQueryDesktopWorkArea); + if(!DosLoadModule((PSZ)objnamebuf, sizeof(objnamebuf), (PSZ)"GBM", &gbm)) + { + /* Load the _System versions of the functions from the library */ + DosQueryProcAddr(gbm, 0, (PSZ)"Gbm_err", (PFN*)&_gbm_err); + DosQueryProcAddr(gbm, 0, (PSZ)"Gbm_init", (PFN*)&_gbm_init); + DosQueryProcAddr(gbm, 0, (PSZ)"Gbm_deinit", (PFN*)&_gbm_deinit); + DosQueryProcAddr(gbm, 0, (PSZ)"Gbm_io_open", (PFN*)&_gbm_io_open); + DosQueryProcAddr(gbm, 0, (PSZ)"Gbm_io_close", (PFN*)&_gbm_io_close); + DosQueryProcAddr(gbm, 0, (PSZ)"Gbm_read_data", (PFN*)&_gbm_read_data); + DosQueryProcAddr(gbm, 0, (PSZ)"Gbm_read_header", (PFN*)&_gbm_read_header); + DosQueryProcAddr(gbm, 0, (PSZ)"Gbm_read_palette", (PFN*)&_gbm_read_palette); + DosQueryProcAddr(gbm, 0, (PSZ)"Gbm_query_n_filetypes", (PFN*)&_gbm_query_n_filetypes); + /* If we got the functions, try to initialize the library */ + if(!_gbm_init || _gbm_init()) + { + /* Otherwise clear out the function pointers */ + _gbm_init=0;_gbm_deinit=0;_gbm_io_open=0;_gbm_io_close=0;_gbm_query_n_filetypes=0; + _gbm_read_header=0;_gbm_read_palette=0;_gbm_read_data=0;_gbm_err=0; + } + } return rc; } +static int _dw_main_running = FALSE; + /* * Runs a message loop for Dynamic Windows. */ @@ -4029,16 +4549,27 @@ QMSG qmsg; _dwtid = dw_thread_id(); - - while(WinGetMsg(dwhab, &qmsg, 0, 0, 0)) + /* Make sure any queued redraws are handled */ + _dw_redraw(0, FALSE); + + /* Set the running flag to TRUE */ + _dw_main_running = TRUE; + + /* Run the loop until the flag is unset... or error */ + while(_dw_main_running && WinGetMsg(dwhab, &qmsg, 0, 0, 0)) { if(qmsg.msg == WM_TIMER && qmsg.hwnd == NULLHANDLE) _run_event(qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2); WinDispatchMsg(dwhab, &qmsg); } - - WinDestroyMsgQueue(dwhmq); - WinTerminate(dwhab); +} + +/* + * Causes running dw_main() to return. + */ +void API dw_main_quit(void) +{ + _dw_main_running = FALSE; } /* @@ -4181,14 +4712,25 @@ void API dw_debug(char *format, ...) { va_list args; - char outbuf[1024]; + char outbuf[1025] = { 0 }; va_start(args, format); +#if defined(__IBMC__) vsprintf(outbuf, format, args); +#else + vsnprintf(outbuf, 1024, format, args); +#endif va_end(args); if(_PmPrintfString) + { + int len = strlen(outbuf); + + /* Trim off trailing newline for PMPrintf */ + if(len > 0 && outbuf[len-1] == '\n') + outbuf[len-1] = 0; _PmPrintfString(outbuf); + } else fprintf(stderr, "%s", outbuf); } @@ -4204,11 +4746,15 @@ int API dw_messagebox(char *title, int flags, char *format, ...) { va_list args; - char outbuf[1024]; + char outbuf[1025] = { 0 }; int rc; va_start(args, format); +#if defined(__IBMC__) vsprintf(outbuf, format, args); +#else + vsnprintf(outbuf, 1024, format, args); +#endif va_end(args); rc = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, (PSZ)outbuf, (PSZ)title, 0, flags | MB_MOVEABLE); @@ -4250,7 +4796,7 @@ */ int API dw_window_show(HWND handle) { - int rc = WinSetWindowPos(handle, NULLHANDLE, 0, 0, 0, 0, SWP_SHOW); + int rc = WinShowWindow(handle, TRUE); HSWITCH hswitch; SWCNTRL swcntrl; @@ -4272,27 +4818,82 @@ if(blah && !(blah->flags & DW_OS2_NEW_WINDOW)) { + /* Handle auto-positioning and auto-sizing */ ULONG cx = dw_screen_width(), cy = dw_screen_height(); + HWND parent = WinQueryWindow(handle, QW_PARENT); int newx, newy, changed = 0; SWP swp; + /* If it is an MDI window... + * find the MDI area. + */ + if(parent && parent != desktop) + { + WinQueryWindowPos(parent, &swp); + cx = swp.cx; + cy = swp.cy; + /* If the MDI parent isn't visible... + * we can't calculate. Drop out. + */ + if(cx < 1 || cy < 1) + { + WinSetWindowPos(handle, NULLHANDLE, 0, 0, 0, 0, SWP_MOVE); + return rc; + } + } + blah->flags |= DW_OS2_NEW_WINDOW; WinQueryWindowPos(handle, &swp); - newx = swp.x; - newy = swp.y; - - if((swp.x+swp.cx) > cx) + /* If the size is 0 then auto-size */ + if(swp.cx == 0 || swp.cy == 0) + { + dw_window_set_size(handle, 0, 0); + WinQueryWindowPos(handle, &swp); + } + + /* If the position was not set... generate a default + * default one in a similar pattern to SHELLPOSITION. + */ + if(swp.x == -2000 || swp.y == -2000) + { + static int defaultx = 0, defaulty = 0; + int maxx = cx / 4, maxy = cy / 4; + + defaultx += 20; + defaulty += 20; + + if(defaultx > maxx) + defaultx = 20; + if(defaulty > maxy) + defaulty = 20; + + newx = defaultx; + /* Account for flipped Y */ + newy = cy - defaulty - swp.cy; + changed = 1; + } + else + { + newx = swp.x; + newy = swp.y; + } + + /* Make sure windows shown for the first time are + * completely visible if possible. + */ + if(swp.cx < cx && (newx+swp.cx) > cx) { newx = (cx - swp.cx)/2; changed = 1; } - if((swp.y+swp.cy) > cy) + if(swp.cy < cy && (newy+swp.cy) > cy) { newy = (cy - swp.cy)/2; changed = 1; } + if(changed) WinSetWindowPos(handle, NULLHANDLE, newx, newy, 0, 0, SWP_MOVE); } @@ -4351,12 +4952,25 @@ */ int API dw_window_destroy(HWND handle) { - HWND frame, menu, parent = WinQueryWindow(handle, QW_PARENT); - Box *thisbox = WinQueryWindowPtr(parent, QWP_USER); + HWND frame, menu, parent; if(!handle) - return -1; - + return DW_ERROR_UNKNOWN; + + /* Handle special case for menu handle */ + if(handle < 65536) + { + char buffer[30]; + + sprintf(buffer, "_dw_id%ld", handle); + menu = (HWND)dw_window_get_data(hwndApp, buffer); + + if(menu && WinIsWindow(dwhab, menu)) + return dw_menu_delete_item((HMENUI)menu, handle); + return DW_ERROR_UNKNOWN; + } + + parent = WinQueryWindow(handle, QW_PARENT); frame = (HWND)dw_window_get_data(handle, "_dw_combo_box"); if((menu = WinWindowFromID(handle, FID_MENU)) != NULLHANDLE) @@ -4365,39 +4979,7 @@ /* If it is a desktop window let WM_DESTROY handle it */ if(parent != desktop) { - /* If the parent box has items... - * try to remove it from the layout - */ - if(thisbox && thisbox->count) - { - int z, index = -1; - Item *tmpitem, *thisitem = thisbox->items; - - for(z=0;z<thisbox->count;z++) - { - if(thisitem[z].hwnd == handle) - index = z; - } - - if(index == -1) - return 0; - - tmpitem = malloc(sizeof(Item)*(thisbox->count-1)); - - /* Copy all but the current entry to the new list */ - for(z=0;z<index;z++) - { - tmpitem[z] = thisitem[z]; - } - for(z=index+1;z<thisbox->count;z++) - { - tmpitem[z-1] = thisitem[z]; - } - - thisbox->items = tmpitem; - free(thisitem); - thisbox->count--; - } + dw_box_unpack(handle); _free_window_memory(frame ? frame : handle); } return WinDestroyWindow(frame ? frame : handle); @@ -4472,6 +5054,10 @@ strcpy(fd.fAttrs.szFacename, currfont); } } +#ifdef UNICODE + fd.fAttrs.usCodePage = 1208; +#endif + fd.fAttrs.usRecordLength = sizeof(FATTRS); /* Fill in the font dialog struct */ fd.cbSize = sizeof(fd); @@ -4511,6 +5097,424 @@ free(oldfont); } +/* Internal function to return a pointer to an item struct + * with information about the packing information regarding object. + */ +Item *_box_item(HWND handle) +{ + HWND parent = WinQueryWindow(handle, QW_PARENT); + Box *thisbox = (Box *)WinQueryWindowPtr(parent, QWP_USER); + + /* If it is a desktop window let WM_DESTROY handle it */ + if(parent != HWND_DESKTOP) + { + if(thisbox && thisbox->count) + { + int z; + Item *thisitem = thisbox->items; + + for(z=0;z<thisbox->count;z++) + { + if(thisitem[z].hwnd == handle) + return &thisitem[z]; + } + } + } + return NULL; +} + +/* Internal function to calculate the widget's required size.. + * These are the general rules for widget sizes: + * + * Render/Unspecified: 1x1 + * Scrolled(Container,Tree,MLE): Guessed size clamped to min and max in dw.h + * Entryfield/Combobox/Spinbutton: 150x(maxfontheight) + * Spinbutton: 50x(maxfontheight) + * Text/Status: (textwidth)x(textheight) + * Ranged: 100x14 or 14x100 for vertical. + * Buttons/Bitmaps: Size of text or image and border. + */ +void _control_size(HWND handle, int *width, int *height) +{ + int thiswidth = 1, thisheight = 1, extrawidth = 0, extraheight = 0; + char tmpbuf[100] = {0}, *buf = dw_window_get_text(handle); + static char testtext[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + WinQueryClassName(handle, 99, (PCH)tmpbuf); + + /* If we have a string... + * calculate the size with the current font. + */ + if(buf) + { + if(*buf) + dw_font_text_extents_get(handle, NULL, buf, &thiswidth, &thisheight); + dw_free(buf); + } + + /* Combobox */ + if(strncmp(tmpbuf, "#2", 3)==0) + { + dw_font_text_extents_get(handle, NULL, testtext, NULL, &thisheight); + thiswidth = 150; + extraheight = 4; + if(thisheight < 18) + thisheight = 18; + } + /* Calendar */ + else if(strncmp(tmpbuf, CalendarClassName, strlen(CalendarClassName)+1)==0) + { + thiswidth = 200; + thisheight = 150; + } + /* Bitmap/Static */ + else if(strncmp(tmpbuf, "#5", 3)==0) + { + HBITMAP hbm = (HBITMAP)dw_window_get_data(handle, "_dw_bitmap"); + + /* If we got a bitmap handle */ + if(hbm) + { + BITMAPINFOHEADER2 bmp; + bmp.cbFix = sizeof(BITMAPINFOHEADER2); + /* Get the parameters of the bitmap */ + if(GpiQueryBitmapInfoHeader(hbm, &bmp)) + { + thiswidth = bmp.cx; + thisheight = bmp.cy; + } + } + else if(dw_window_get_data(handle, "_dw_status")) + { + extrawidth = 4; + extraheight = 4; + } + } + /* Ranged: Slider/Percent */ + else if(strncmp(tmpbuf, "#38", 4)== 0) + { + thiswidth = 100; + thisheight = 20; + } + /* Scrollbar */ + else if(strncmp(tmpbuf, "#8", 3)== 0) + { + /* Check for vertical scrollbar */ + if(WinQueryWindowULong(handle, QWL_STYLE) & SBS_VERT) + { + thiswidth = WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL); + thisheight = 100; + } + else + { + thiswidth = 100; + thisheight = WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL); + } + } + /* Spinbutton */ + else if(strncmp(tmpbuf, "#32", 4)==0) + { + dw_font_text_extents_get(handle, NULL, testtext, NULL, &thisheight); + thiswidth = 50; + extraheight = 6; + } + /* Entryfield */ + else if(strncmp(tmpbuf, "#6", 3)==0) + { + dw_font_text_extents_get(handle, NULL, testtext, NULL, &thisheight); + thiswidth = 150; + extraheight = 6; + } + /* MLE */ + else if(strncmp(tmpbuf, "#10", 4)==0) + { + unsigned long bytes; + int height, width; + char *buf, *ptr; + int basicwidth; + int wrap = (int)WinSendMsg(handle, MLM_QUERYWRAP, 0,0); + + thisheight = 8; + basicwidth = thiswidth = WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL) + 8; + + dw_mle_get_size(handle, &bytes, NULL); + + ptr = buf = alloca(bytes + 2); + dw_mle_export(handle, buf, 0, (int)bytes); + buf[bytes] = 0; + strcat(buf, "\n"); + + /* MLE */ + while((ptr = strstr(buf, "\n")) != NULL) + { + ptr[0] = 0; + width = 0; + if(strlen(buf)) + dw_font_text_extents_get(handle, NULL, buf, &width, &height); + else + dw_font_text_extents_get(handle, NULL, testtext, NULL, &height); + + width += basicwidth; + + if(wrap && width > _DW_SCROLLED_MAX_WIDTH) + { + thiswidth = _DW_SCROLLED_MAX_WIDTH; + thisheight += height * (width / _DW_SCROLLED_MAX_WIDTH); + + } + else + { + if(width > thiswidth) + thiswidth = width > _DW_SCROLLED_MAX_WIDTH ? _DW_SCROLLED_MAX_WIDTH : width; + } + thisheight += height; + buf = &ptr[1]; + } + + if(thiswidth < _DW_SCROLLED_MIN_WIDTH) + thiswidth = _DW_SCROLLED_MIN_WIDTH; + if(thisheight < _DW_SCROLLED_MIN_HEIGHT) + thisheight = _DW_SCROLLED_MIN_HEIGHT; + if(thisheight > _DW_SCROLLED_MAX_HEIGHT) + thisheight = _DW_SCROLLED_MAX_HEIGHT; + } + /* Listbox */ + else if(strncmp(tmpbuf, "#7", 3)==0) + { + char buf[1025] = {0}; + int x, count = dw_listbox_count(handle); + int basicwidth = thiswidth = WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL) + 8; + + thisheight = 8; + + for(x=0;x<count;x++) + { + int height, width = 0; + + dw_listbox_get_text(handle, x, buf, 1024); + + if(strlen(buf)) + dw_font_text_extents_get(handle, NULL, buf, &width, &height); + else + dw_font_text_extents_get(handle, NULL, testtext, NULL, &height); + + width += basicwidth; + + if(width > thiswidth) + thiswidth = width > _DW_SCROLLED_MAX_WIDTH ? _DW_SCROLLED_MAX_WIDTH : width; + thisheight += height; + } + + if(thiswidth < _DW_SCROLLED_MIN_WIDTH) + thiswidth = _DW_SCROLLED_MIN_WIDTH; + if(thisheight < _DW_SCROLLED_MIN_HEIGHT) + thisheight = _DW_SCROLLED_MIN_HEIGHT; + if(thisheight > _DW_SCROLLED_MAX_HEIGHT) + thisheight = _DW_SCROLLED_MAX_HEIGHT; + } + /* Container and Tree */ + else if(strncmp(tmpbuf, "#37", 4)==0) + { + /* Container */ + if(dw_window_get_data(handle, "_dw_container")) + { + CNRINFO ci; + + if(WinSendMsg(handle, CM_QUERYCNRINFO, MPFROMP(&ci), MPFROMSHORT(sizeof(CNRINFO)))) + { + RECTL item; + PRECORDCORE pCore = NULL; + int right = FALSE, max = 0; + /* Get the left title window */ + HWND title = WinWindowFromID(handle, 32752); + + thiswidth = WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL); + thisheight = WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL); + + /* If the pFieldInfoList is filled in we want to look at the right side */ + if(ci.pFieldInfoLast) + { + right = TRUE; + /* Left side include splitbar position */ + thiswidth += ci.xVertSplitbar + 4; + /* If split... find the right side */ + title = WinWindowFromID(handle, 32753); + } + + /* If there are column titles ... */ + if(title) + { + unsigned long height = 0; + + dw_window_get_pos_size(title, 0, 0, 0, &height); + if(height) + thisheight += height; + else + thisheight += 28; + } + + /* Cycle through all the records finding the maximums */ + pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)0L, MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER)); + + /* Method 1: With items in container */ + if(pCore) + { + while(pCore) + { + QUERYRECORDRECT qrr; + int vector; + + qrr.cb = sizeof(QUERYRECORDRECT); + qrr.pRecord = pCore; + qrr.fRightSplitWindow = right; + qrr.fsExtent = CMA_TEXT; + + WinSendMsg(handle, CM_QUERYRECORDRECT, (MPARAM)&item, (MPARAM)&qrr); + + vector = item.xRight - item.xLeft; + + if(vector > max) + max = vector; + + thisheight += (item.yTop - item.yBottom); + + pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)pCore, MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)); + } + + /* Add the widest item to the width */ + thiswidth += max; + } + else + { + /* Method 2: No items */ + unsigned long width, height; + HWND hscroll = WinWindowFromID(handle, right ? 32756 : 32755); + MRESULT mr; + + /* Save the original size */ + dw_window_get_pos_size(handle, 0, 0, &width, &height); + + /* Set the size to the minimum */ + dw_window_set_size(handle, _DW_SCROLLED_MIN_WIDTH, _DW_SCROLLED_MIN_HEIGHT); + + /* With the minimum size check to see what the scrollbar says */ + mr = WinSendMsg(hscroll, SBM_QUERYRANGE, 0, 0); + if(right) + thiswidth += SHORT2FROMMP(mr); + else if(SHORT2FROMMP(mr) != _DW_SCROLLED_MIN_HEIGHT) + thiswidth += SHORT2FROMMP(mr) + _DW_SCROLLED_MIN_HEIGHT + WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL); + + /* Reload the original size */ + dw_window_set_size(handle, width, height); + } + + /* Clamp to min and max */ + if(thiswidth > _DW_SCROLLED_MAX_WIDTH) + thiswidth = _DW_SCROLLED_MAX_WIDTH; + if(thiswidth < _DW_SCROLLED_MIN_WIDTH) + thiswidth = _DW_SCROLLED_MIN_WIDTH; + if(thisheight < _DW_SCROLLED_MIN_HEIGHT) + thisheight = _DW_SCROLLED_MIN_HEIGHT; + if(thisheight > _DW_SCROLLED_MAX_HEIGHT) + thisheight = _DW_SCROLLED_MAX_HEIGHT; + } + } + else + { + /* Tree */ + thiswidth = (int)((_DW_SCROLLED_MAX_WIDTH + _DW_SCROLLED_MIN_WIDTH)/2); + thisheight = (int)((_DW_SCROLLED_MAX_HEIGHT + _DW_SCROLLED_MIN_HEIGHT)/2); + } + } + /* Button */ + else if(strncmp(tmpbuf, "#3", 3)==0) + { + ULONG style = WinQueryWindowULong(handle, QWL_STYLE); + + if(style & BS_AUTOCHECKBOX || style & BS_AUTORADIOBUTTON) + { + extrawidth = 24; + extraheight = 4; + } + else + { + /* Handle bitmap buttons */ + if(dw_window_get_data(handle, "_dw_bitmapbutton")) + { + HPOINTER hpr = (HPOINTER)dw_window_get_data(handle, "_dw_button_icon"); + HBITMAP hbm = 0; + int iconwidth = DW_POINTER_TO_INT(dw_window_get_data(handle, "_dw_button_icon_width")); + HPIXMAP pixmap = (HPIXMAP)dw_window_get_data(handle, "_dw_hpixmap"); + + /* Handle case of icon resource */ + if(hpr) + { + if(iconwidth) + thisheight = thiswidth = iconwidth; + else + { + POINTERINFO pi; + + /* Get the internal HBITMAP handles */ + if(WinQueryPointerInfo(hpr, &pi)) + hbm = pi.hbmColor ? pi.hbmColor : pi.hbmPointer; + } + } + /* Handle case of pixmap resource */ + else if(pixmap) + { + thiswidth = pixmap->width; + thisheight = pixmap->height; + } + + /* If we didn't load it from the icon... */ + if(!hbm && !iconwidth) + { + WNDPARAMS wp; + BTNCDATA bcd; + + wp.fsStatus = WPM_CTLDATA; + wp.cbCtlData = sizeof(BTNCDATA); + wp.pCtlData = &bcd; + + /* Query the button's bitmap */ + if(WinSendMsg(handle, WM_QUERYWINDOWPARAMS, (MPARAM)&wp, MPVOID) && bcd.hImage) + hbm = bcd.hImage; + } + + /* If we got a bitmap handle */ + if(hbm) + { + BITMAPINFOHEADER2 bmp; + bmp.cbFix = sizeof(BITMAPINFOHEADER2); + /* Get the parameters of the bitmap */ + if(GpiQueryBitmapInfoHeader(hbm, &bmp)) + { + thiswidth = bmp.cx; + thisheight = bmp.cy; + } + } + } + else + { + extrawidth = 4; + extraheight = 4; + } + if(!(style & BS_NOBORDER)) + { + extrawidth += 4; + extraheight += 4; + } + } + } + + /* Set the requested sizes */ + if(width) + *width = thiswidth + extrawidth; + if(height) + *height = thisheight + extraheight; +} + /* * Sets the font used by a specified window (widget) handle. * Parameters: @@ -4520,7 +5524,21 @@ int API dw_window_set_font(HWND handle, char *fontname) { HWND group = (HWND)dw_window_get_data(handle, "_dw_buddy"); - return WinSetPresParam(group ? group : handle, PP_FONTNAMESIZE, strlen(fontname)+1, fontname); + /* If we changed the font... */ + if(!WinSetPresParam(group ? group : handle, PP_FONTNAMESIZE, strlen(fontname)+1, fontname)) + { + Item *item = _box_item(handle); + + /* Check to see if any of the sizes need to be recalculated */ + if(item && (item->origwidth == -1 || item->origheight == -1)) + { + _control_size(handle, item->origwidth == -1 ? &item->width : NULL, item->origheight == -1 ? &item->height : NULL); + /* Queue a redraw on the top-level window */ + _dw_redraw(_toplevel_window(handle), TRUE); + } + return DW_ERROR_NONE; + } + return DW_ERROR_UNKNOWN; } /* @@ -4538,9 +5556,36 @@ return NULL; } +/* Internal function to handle transparent children */ +void _handle_transparent(HWND handle) +{ + ULONG pcolor, which = PP_BACKGROUNDCOLOR;; + + + if(!WinQueryPresParam(handle, which, 0, NULL, sizeof(pcolor), &pcolor, QPF_NOINHERIT)) + which = PP_BACKGROUNDCOLORINDEX; + + if(which == PP_BACKGROUNDCOLOR || + WinQueryPresParam(handle, which, 0, NULL, sizeof(pcolor), &pcolor, QPF_NOINHERIT)) + { + HWND child; + HENUM henum = WinBeginEnumWindows(handle); + + while((child = WinGetNextWindow(henum)) != NULLHANDLE) + { + if(dw_window_get_data(child, "_dw_transparent")) + { + WinSetPresParam(child, which, sizeof(pcolor), &pcolor); + } + } + WinEndEnumWindows(henum); + } +} + /* Internal version */ int _dw_window_set_color(HWND handle, ULONG fore, ULONG back) { + /* Handle foreground */ if((fore & DW_RGB_COLOR) == DW_RGB_COLOR) { RGB2 rgb2; @@ -4559,7 +5604,23 @@ WinSetPresParam(handle, PP_FOREGROUNDCOLORINDEX, sizeof(ULONG), &fore); } - if((back & DW_RGB_COLOR) == DW_RGB_COLOR) + /* Handle background */ + if(back == DW_RGB_TRANSPARENT) + { + /* Special case for setting transparent */ + ULONG pcolor; + HWND parent = WinQueryWindow(handle, QW_PARENT); + + dw_window_set_data(handle, "_dw_transparent", DW_INT_TO_POINTER(1)); + + if(WinQueryPresParam(parent, PP_BACKGROUNDCOLOR, 0, NULL, + sizeof(pcolor), &pcolor, QPF_NOINHERIT | QPF_PURERGBCOLOR)) + WinSetPresParam(handle, PP_BACKGROUNDCOLOR, sizeof(pcolor), &pcolor); + else if(WinQueryPresParam(parent, PP_BACKGROUNDCOLORINDEX, 0, NULL, + sizeof(pcolor), &pcolor, QPF_NOINHERIT)) + WinSetPresParam(handle, PP_BACKGROUNDCOLORINDEX, sizeof(pcolor), &pcolor); + } + else if((back & DW_RGB_COLOR) == DW_RGB_COLOR) { RGB2 rgb2; @@ -4569,15 +5630,18 @@ rgb2.fcOptions = 0; WinSetPresParam(handle, PP_BACKGROUNDCOLOR, sizeof(RGB2), &rgb2); - return 0; + dw_window_set_data(handle, "_dw_transparent", NULL); } else if(back != DW_CLR_DEFAULT) { back = _internal_color(back); WinSetPresParam(handle, PP_BACKGROUNDCOLORINDEX, sizeof(ULONG), &back); - } - return 0; + dw_window_set_data(handle, "_dw_transparent", NULL); + } + /* If this is a box... check if any of the children are transparent */ + _handle_transparent(handle); + return DW_ERROR_NONE; } /* * Sets the colors used by a specified window (widget) handle. @@ -4671,9 +5735,8 @@ WindowData *blah = calloc(1, sizeof(WindowData)); ULONG winStyle = 0L; - newbox->pad = 0; newbox->type = DW_VERT; - newbox->count = 0; + newbox->vsize = newbox->hsize = SIZEEXPAND; flStyle |= FCF_NOBYTEALIGN; @@ -4682,9 +5745,6 @@ else flStyle |= FCF_TITLEBAR; - if(!(flStyle & FCF_SHELLPOSITION)) - blah->flags |= DW_OS2_NEW_WINDOW; - if(flStyle & WS_MAXIMIZED) { winStyle |= WS_MAXIMIZED; @@ -4696,14 +5756,17 @@ flStyle &= ~WS_MINIMIZED; } + /* Then create the real window window without FCF_SHELLPOSITION */ + flStyle &= ~FCF_SHELLPOSITION; hwndframe = WinCreateStdWindow(hwndOwner, winStyle, &flStyle, (PSZ)ClassName, (PSZ)title, 0L, NULLHANDLE, 0L, &newbox->hwnd); + /* Default the window to a ridiculus place so it can't possibly be intentional */ + WinSetWindowPos(hwndframe, NULLHANDLE, -2000, -2000, 0, 0, SWP_MOVE); newbox->hwndtitle = WinWindowFromID(hwndframe, FID_TITLEBAR); if(!newbox->titlebar && newbox->hwndtitle) WinSetParent(newbox->hwndtitle, HWND_OBJECT, FALSE); blah->oldproc = WinSubclassWindow(hwndframe, _sizeproc); WinSetWindowPtr(hwndframe, QWP_USER, blah); WinSetWindowPtr(newbox->hwnd, QWP_USER, newbox); - return hwndframe; } @@ -4872,7 +5935,7 @@ NULL, WS_VISIBLE | WS_CLIPCHILDREN | FS_NOBYTEALIGN, - 0,0,2000,1000, + 0,0,0,0, NULLHANDLE, HWND_TOP, id, @@ -4890,16 +5953,20 @@ */ HWND API dw_bitmap_new(ULONG id) { - return WinCreateWindow(HWND_OBJECT, - WC_STATIC, - NULL, - WS_VISIBLE | SS_TEXT, - 0,0,2000,1000, - NULLHANDLE, - HWND_TOP, - id, - NULL, - NULL); + WindowData *blah = calloc(1, sizeof(WindowData)); + HWND tmp = WinCreateWindow(HWND_OBJECT, + WC_STATIC, + NULL, + WS_VISIBLE | SS_TEXT, + 0,0,0,0, + NULLHANDLE, + HWND_TOP, + id, + NULL, + NULL); + blah->oldproc = WinSubclassWindow(tmp, _BitmapProc); + WinSetWindowPtr(tmp, QWP_USER, blah); + return tmp; } /* @@ -5198,6 +6265,27 @@ } /* + * Deletes the menu item specified + * Parameters: + * menu: The handle to the menu in which the item was appended. + * id: Menuitem id. + * Returns: + * DW_ERROR_NONE (0) on success or DW_ERROR_UNKNOWN on failure. + */ +int API dw_menu_delete_item(HMENUI menux, unsigned long id) +{ + if(id < 65536 && menux) + { + WinSendMsg(menux, MM_DELETEITEM, MPFROM2SHORT(id, FALSE), 0); + /* If the ID was autogenerated it is safe to remove it */ + if(id >= 30000) + dw_signal_disconnect_by_window((HWND)id); + return DW_ERROR_NONE; + } + return DW_ERROR_UNKNOWN; +} + +/* * Pops up a context menu at given x and y coordinates. * Parameters: * menu: The handle the the existing menu. @@ -5260,7 +6348,7 @@ WS_VISIBLE | CCS_READONLY | (multi ? CCS_EXTENDSEL : CCS_SINGLESEL) | CCS_AUTOPOSITION, - 0,0,2000,1000, + 0,0,0,0, NULLHANDLE, HWND_TOP, id ? id : _GlobalID(), @@ -5332,7 +6420,7 @@ blah->oldproc = WinSubclassWindow(tmp, _textproc); WinSetWindowPtr(tmp, QWP_USER, blah); dw_window_set_font(tmp, DefaultFont); - dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_PALEGRAY); + dw_window_set_color(tmp, DW_CLR_BLACK, DW_RGB_TRANSPARENT); return tmp; } @@ -5359,6 +6447,7 @@ WinSetWindowPtr(tmp, QWP_USER, blah); dw_window_set_font(tmp, DefaultFont); dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_PALEGRAY); + dw_window_set_data(tmp, "_dw_status", DW_INT_TO_POINTER(1)); return tmp; } @@ -5377,10 +6466,9 @@ HWND tmp = WinCreateWindow(HWND_OBJECT, WC_MLE, NULL, - WS_VISIBLE | + WS_VISIBLE | MLS_WORDWRAP | MLS_BORDER | MLS_IGNORETAB | - MLS_VSCROLL | - MLS_LIMITVSCROLL, + MLS_VSCROLL | MLS_LIMITVSCROLL, 0,0,2000,1000, NULLHANDLE, HWND_TOP, @@ -5499,8 +6587,7 @@ */ HWND API dw_button_new(char *text, ULONG id) { - BubbleButton *bubble = calloc(sizeof(BubbleButton), 1); - + WindowData *blah = calloc(1, sizeof(WindowData)); HWND tmp = WinCreateWindow(HWND_OBJECT, WC_BUTTON, (PSZ)text, @@ -5512,11 +6599,9 @@ NULL, NULL); - bubble->id = id; - bubble->bubbletext[0] = '\0'; - bubble->pOldProc = WinSubclassWindow(tmp, _BtProc); - - WinSetWindowPtr(tmp, QWP_USER, bubble); + blah->oldproc = WinSubclassWindow(tmp, _BtProc); + + WinSetWindowPtr(tmp, QWP_USER, blah); dw_window_set_font(tmp, DefaultFont); dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_PALEGRAY); return tmp; @@ -5565,7 +6650,7 @@ { char idbuf[256], *name = NULL; HWND tmp; - BubbleButton *bubble = calloc(sizeof(BubbleButton), 1); + WindowData *blah = calloc(1, sizeof(WindowData)); HPOINTER icon = WinLoadPointer(HWND_DESKTOP, 0L, id); if(!icon) @@ -5587,16 +6672,45 @@ NULL, NULL); - bubble->id = id; - strncpy(bubble->bubbletext, text, BUBBLE_HELP_MAX - 1); - bubble->bubbletext[BUBBLE_HELP_MAX - 1] = '\0'; - bubble->pOldProc = WinSubclassWindow(tmp, _BtProc); - - WinSetWindowPtr(tmp, QWP_USER, bubble); + if(text) + strncpy(blah->bubbletext, text, BUBBLE_HELP_MAX - 1); + blah->oldproc = WinSubclassWindow(tmp, _BtProc); + + WinSetWindowPtr(tmp, QWP_USER, blah); if(icon) - dw_window_set_data(tmp, "_dw_button_icon", (void *)icon); - dw_window_set_data(tmp, "_dw_bitmapbutton", (void *)1); + { + PVOID ResPtr; + ULONG ResSize; + + /* Since WinLoadPointer() can change the size of the icon... + * We will query the resource directly and check the size ourselves. + */ + if(DosQueryResourceSize(NULLHANDLE, RT_POINTER, id, &ResSize) == NO_ERROR && ResSize && + DosGetResource(NULLHANDLE, RT_POINTER, id, &ResPtr) == NO_ERROR) + { + PBITMAPFILEHEADER2 header = ResPtr; + + /* We can only check for icons and pointers */ + if(header->usType == 0x4943 /* Icon 'CI' */ || + header->usType == 0x5043 /* Pointer 'CP' */) + { + /* Check the new style header */ + if(header->bmp2.cbFix == sizeof(BITMAPINFOHEADER2)) + dw_window_set_data(tmp, "_dw_button_icon_width", DW_INT_TO_POINTER(header->bmp2.cx)); + else if(header->bmp2.cbFix == sizeof(BITMAPINFOHEADER)) + { + /* Check the old style header */ + PBITMAPINFOHEADER bi = (PBITMAPINFOHEADER)&(header->bmp2); + + dw_window_set_data(tmp, "_dw_button_icon_width", DW_INT_TO_POINTER(((int)bi->cx))); + } + } + DosFreeResource(ResPtr); + } + dw_window_set_data(tmp, "_dw_button_icon", DW_POINTER(icon)); + } + dw_window_set_data(tmp, "_dw_bitmapbutton", DW_INT_TO_POINTER(1)); return tmp; } @@ -5611,7 +6725,7 @@ */ HWND API dw_bitmapbutton_new_from_file(char *text, unsigned long id, char *filename) { - BubbleButton *bubble = calloc(sizeof(BubbleButton), 1); + WindowData *blah = calloc(1, sizeof(WindowData)); HWND tmp = WinCreateWindow(HWND_OBJECT, WC_BUTTON, NULL, @@ -5623,7 +6737,7 @@ id, NULL, NULL); - char *file = alloca(strlen(filename) + 5); + char *file = alloca(strlen(filename) + 6); HPIXMAP pixmap = NULL, disabled = NULL; HPOINTER icon = 0; @@ -5643,7 +6757,7 @@ if(stricmp(file + len - 4, ".ico") == 0) icon = WinLoadFileIcon((PSZ)file, FALSE); else - _load_bitmap_file(file, tmp, &pixmap->hbm, &pixmap->hdc, &pixmap->hps, &pixmap->width, &pixmap->height); + _load_bitmap_file(file, tmp, &pixmap->hbm, &pixmap->hdc, &pixmap->hps, &pixmap->width, &pixmap->height, &pixmap->depth); } } else @@ -5654,10 +6768,14 @@ icon = WinLoadFileIcon((PSZ)file, FALSE); else { - strcpy(file, filename); - strcat(file, ".bmp"); - if(access(file, 04) == 0) - _load_bitmap_file(file, tmp, &pixmap->hbm, &pixmap->hdc, &pixmap->hps, &pixmap->width, &pixmap->height); + for(z=0;z<(_gbm_init?NUM_EXTS:1);z++) + { + strcpy(file, filename); + strcat(file, image_exts[z]); + if(access(file, 04) == 0 && + _load_bitmap_file(file, tmp, &pixmap->hbm, &pixmap->hdc, &pixmap->hps, &pixmap->width, &pixmap->height, &pixmap->depth)) + break; + } } } @@ -5686,12 +6804,11 @@ } } - bubble->id = id; - strncpy(bubble->bubbletext, text, BUBBLE_HELP_MAX - 1); - bubble->bubbletext[BUBBLE_HELP_MAX - 1] = '\0'; - bubble->pOldProc = WinSubclassWindow(tmp, _BtProc); - - WinSetWindowPtr(tmp, QWP_USER, bubble); + if(text) + strncpy(blah->bubbletext, text, BUBBLE_HELP_MAX - 1); + blah->oldproc = WinSubclassWindow(tmp, _BtProc); + + WinSetWindowPtr(tmp, QWP_USER, blah); if(icon) dw_window_set_data(tmp, "_dw_button_icon", (void *)icon); @@ -5716,7 +6833,7 @@ HWND API dw_bitmapbutton_new_from_data(char *text, unsigned long id, char *data, int len) { FILE *fp; - BubbleButton *bubble = calloc(sizeof(BubbleButton), 1); + WindowData *blah = calloc(1, sizeof(WindowData)); HWND tmp = WinCreateWindow(HWND_OBJECT, WC_BUTTON, NULL, @@ -5732,7 +6849,7 @@ HPIXMAP pixmap = NULL, disabled = NULL; HPOINTER icon = 0; - if ( ( pixmap = calloc( 1, sizeof(struct _hpixmap) ) ) ) + if((pixmap = calloc(1, sizeof(struct _hpixmap))) != NULL) { int z, j, lim; LONG fore; @@ -5744,11 +6861,7 @@ { fwrite( data, 1, len, fp ); fclose( fp ); - if ( len > 1 && data[0] == 'B' && data[1] == 'M' ) /* first 2 chars of data is BM, then its a BMP */ - { - _load_bitmap_file( file, tmp, &pixmap->hbm, &pixmap->hdc, &pixmap->hps, &pixmap->width, &pixmap->height ); - } - else /* otherwise its assumed to be an ico */ + if(!_load_bitmap_file( file, tmp, &pixmap->hbm, &pixmap->hdc, &pixmap->hps, &pixmap->width, &pixmap->height, &pixmap->depth)) { icon = WinLoadFileIcon((PSZ)file, FALSE); } @@ -5786,12 +6899,11 @@ } } - bubble->id = id; - strncpy(bubble->bubbletext, text, BUBBLE_HELP_MAX - 1); - bubble->bubbletext[BUBBLE_HELP_MAX - 1] = '\0'; - bubble->pOldProc = WinSubclassWindow(tmp, _BtProc); - - WinSetWindowPtr(tmp, QWP_USER, bubble); + if(text) + strncpy(blah->bubbletext, text, BUBBLE_HELP_MAX - 1); + blah->oldproc = WinSubclassWindow(tmp, _BtProc); + + WinSetWindowPtr(tmp, QWP_USER, blah); if(icon) dw_window_set_data(tmp, "_dw_button_icon", (void *)icon); @@ -5860,7 +6972,7 @@ blah->oldproc = WinSubclassWindow(tmp, _entryproc); WinSetWindowPtr(tmp, QWP_USER, blah); dw_window_set_font(tmp, DefaultFont); - dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_PALEGRAY); + dw_window_set_color(tmp, DW_CLR_BLACK, DW_RGB_TRANSPARENT); return tmp; } @@ -5879,7 +6991,7 @@ HWND tmp; sldcData.cbSize = sizeof(SLDCDATA); - sldcData.usScale1Increments = increments; + sldcData.usScale1Increments = increments; tmp = WinCreateWindow(HWND_OBJECT, WC_SLIDER, @@ -5953,7 +7065,7 @@ */ HWND API dw_checkbox_new(char *text, ULONG id) { - BubbleButton *bubble = calloc(sizeof(BubbleButton), 1); + WindowData *blah = calloc(1, sizeof(WindowData)); HWND tmp = WinCreateWindow(HWND_OBJECT, WC_BUTTON, (PSZ)text, @@ -5964,12 +7076,10 @@ id, NULL, NULL); - bubble->id = id; - bubble->bubbletext[0] = '\0'; - bubble->pOldProc = WinSubclassWindow(tmp, _BtProc); - WinSetWindowPtr(tmp, QWP_USER, bubble); + blah->oldproc = WinSubclassWindow(tmp, _BtProc); + WinSetWindowPtr(tmp, QWP_USER, blah); dw_window_set_font(tmp, DefaultFont); - dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_PALEGRAY); + dw_window_set_color(tmp, DW_CLR_BLACK, DW_RGB_TRANSPARENT); return tmp; } @@ -6012,109 +7122,217 @@ WinSendMsg(handle, WM_SETICON, (MPARAM)hptr, 0); } +/* GBM seems to be compiled with VisualAge which defines O_BINARY and O_RDONLY + * as follows... but other compilers (GCC and Watcom at least) define them + * differently... so we add defines that are compatible with VAC here. + */ +#define GBM_O_BINARY 0x00008000 +#define GBM_O_RDONLY 0x00000004 + /* Internal function to load a bitmap from a file and return handles * to the bitmap, presentation space etc. */ -int _load_bitmap_file(char *file, HWND handle, HBITMAP *hbm, HDC *hdc, HPS *hps, unsigned long *width, unsigned long *height) -{ - HFILE BitmapFileHandle = NULLHANDLE; /* handle for the file */ - ULONG OpenAction = 0; - PBYTE BitmapFileBegin; /* pointer to the first byte of bitmap data */ - FILESTATUS BitmapStatus; - ULONG cbRead; - PBITMAPFILEHEADER2 pBitmapFileHeader; - PBITMAPINFOHEADER2 pBitmapInfoHeader; - ULONG ScanLines, ulFlags; - HPS hps1; - HDC hdc1; - SIZEL sizl = { 0, 0 }; - - /* open bitmap file */ - DosOpen((PSZ)file, &BitmapFileHandle, &OpenAction, 0L, - FILE_ARCHIVED | FILE_NORMAL | FILE_READONLY, - OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, - OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY | - OPEN_FLAGS_NOINHERIT, 0L); - - if(!BitmapFileHandle) - return 0; - - /* find out how big the file is */ - DosQueryFileInfo(BitmapFileHandle, 1, &BitmapStatus, - sizeof(BitmapStatus)); - - /* allocate memory to load the bitmap */ - DosAllocMem((PPVOID)&BitmapFileBegin, (ULONG)BitmapStatus.cbFile, - PAG_READ | PAG_WRITE | PAG_COMMIT); - - /* read bitmap file into memory buffer */ - DosRead(BitmapFileHandle, (PVOID)BitmapFileBegin, - BitmapStatus.cbFile, &cbRead); - - /* access first bytes as bitmap header */ - pBitmapFileHeader = (PBITMAPFILEHEADER2)BitmapFileBegin; - - /* check if it's a valid bitmap data file */ - if((pBitmapFileHeader->usType != BFT_BITMAPARRAY) && - (pBitmapFileHeader->usType != BFT_BMAP)) - { - /* free memory of bitmap file buffer */ - DosFreeMem(BitmapFileBegin); - /* close the bitmap file */ - DosClose(BitmapFileHandle); - return 0; - } - - /* check if it's a file with multiple bitmaps */ - if(pBitmapFileHeader->usType == BFT_BITMAPARRAY) - { - /* we'll just use the first bitmap and ignore the others */ - pBitmapFileHeader = &(((PBITMAPARRAYFILEHEADER2)BitmapFileBegin)->bfh2); - } - - /* set pointer to bitmap information block */ - pBitmapInfoHeader = &pBitmapFileHeader->bmp2; - - /* find out if it's the new 2.0 format or the old format */ - /* and query number of lines */ - if(pBitmapInfoHeader->cbFix == sizeof(BITMAPINFOHEADER)) - { - *height = ScanLines = (ULONG)((PBITMAPINFOHEADER)pBitmapInfoHeader)->cy; - *width = (ULONG)((PBITMAPINFOHEADER)pBitmapInfoHeader)->cx; - } - else - { - *height = ScanLines = pBitmapInfoHeader->cy; - *width = pBitmapInfoHeader->cx; - } - - /* now we need a presentation space, get it from static control */ - hps1 = WinGetPS(handle); - - hdc1 = GpiQueryDevice(hps1); - ulFlags = GpiQueryPS(hps1, &sizl); - - *hdc = DevOpenDC(dwhab, OD_MEMORY, (PSZ)"*", 0L, NULL, hdc1); - *hps = GpiCreatePS (dwhab, *hdc, &sizl, ulFlags | GPIA_ASSOC); - - /* create bitmap now using the parameters from the info block */ - *hbm = GpiCreateBitmap(*hps, pBitmapInfoHeader, 0L, NULL, NULL); - - /* select the new bitmap into presentation space */ - GpiSetBitmap(*hps, *hbm); - - /* now copy the bitmap data into the bitmap */ - GpiSetBitmapBits(*hps, 0L, ScanLines, - BitmapFileBegin + pBitmapFileHeader->offBits, - (PBITMAPINFO2)pBitmapInfoHeader); - - WinReleasePS(hps1); - - /* free memory of bitmap file buffer */ - DosFreeMem(BitmapFileBegin); - /* close the bitmap file */ - DosClose(BitmapFileHandle); - return 1; +int _load_bitmap_file(char *file, HWND handle, HBITMAP *hbm, HDC *hdc, HPS *hps, unsigned long *width, unsigned long *height, int *depth) +{ + PBITMAPINFOHEADER2 pBitmapInfoHeader; + /* pointer to the first byte of bitmap data */ + PBYTE BitmapFileBegin, BitmapBits; + ULONG ulFlags; + SIZEL sizl = { 0 }; + HPS hps1; + HDC hdc1; + + /* If we have GBM support open the file using GBM */ + if(_gbm_init) + { + int fd, z, err = -1, ft = 0; + GBM gbm; + GBMRGB *gbmrgb; + ULONG byteswidth; + + /* Try to open the file */ + if((fd = _gbm_io_open(file, GBM_O_RDONLY|GBM_O_BINARY)) == -1) + { +#ifdef DEBUG + dw_debug("Failed to open file %s\n", file); +#endif + return 0; + } + + /* guess the source file type from the source filename */ + _gbm_query_n_filetypes(&ft); + + for(z=0;z<ft;z++) + { + /* Read the file header */ + if((err = _gbm_read_header(file, fd, z, &gbm, "")) == 0) + break; + } + + /* If we failed to load the header */ + if(err) + { +#ifdef DEBUG + dw_debug("GBM: Read header type %d \"%s\" %d %s\n", z, file, err, _gbm_err(err)); +#endif + _gbm_io_close(fd); + return 0; + } + + /* if less than 24-bit, then have palette */ + if(gbm.bpp < 24) + { + gbmrgb = alloca(sizeof(GBMRGB)); + /* Read the palette from the file */ + if((err = _gbm_read_palette(fd, z, &gbm, gbmrgb)) != 0) + { +#ifdef DEBUG + dw_debug("GBM: Read palette type %d \"%s\" %d %s\n", z, file, err, _gbm_err(err)); +#endif + _gbm_io_close(fd); + return 0; + } + } + else + gbmrgb = NULL; + + /* Save the dimension for return */ + *width = gbm.w; + *height = gbm.h; + *depth = gbm.bpp; + byteswidth = (((gbm.w*gbm.bpp + 31)/32)*4); + + /* Allocate a buffer to store the image */ + DosAllocMem((PPVOID)&BitmapFileBegin, (ULONG)byteswidth * gbm.h, + PAG_READ | PAG_WRITE | PAG_COMMIT); + + /* Read the data into our buffer */ + if((err = _gbm_read_data(fd, z, &gbm, BitmapFileBegin)) != 0) + { +#ifdef DEBUG + dw_debug("GBM: Read data type %d \"%s\" %d %s\n", z, file, err, _gbm_err(err)); +#endif + _gbm_io_close(fd); + DosFreeMem(BitmapFileBegin); + return 0; + } + + /* Close the file */ + _gbm_io_close(fd); + + pBitmapInfoHeader = alloca(sizeof(BITMAPINFOHEADER2)); + memset(pBitmapInfoHeader, 0, sizeof(BITMAPINFOHEADER2)); + pBitmapInfoHeader->cbFix = sizeof(BITMAPINFOHEADER2); + pBitmapInfoHeader->cx = (SHORT)gbm.w; + pBitmapInfoHeader->cy = (SHORT)gbm.h; + pBitmapInfoHeader->cPlanes = (SHORT)1; + pBitmapInfoHeader->cBitCount = (SHORT)gbm.bpp; + + /* Put the bitmap bits into the destination */ + BitmapBits = BitmapFileBegin; + } + else + { + HFILE BitmapFileHandle = NULLHANDLE; /* handle for the file */ + ULONG OpenAction = 0; + FILESTATUS BitmapStatus; + ULONG cbRead; + PBITMAPFILEHEADER2 pBitmapFileHeader; + + /* open bitmap file */ + DosOpen((PSZ)file, &BitmapFileHandle, &OpenAction, 0L, + FILE_ARCHIVED | FILE_NORMAL | FILE_READONLY, + OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY | + OPEN_FLAGS_NOINHERIT, 0L); + + if(!BitmapFileHandle) + return 0; + + /* find out how big the file is */ + DosQueryFileInfo(BitmapFileHandle, 1, &BitmapStatus, + sizeof(BitmapStatus)); + + /* allocate memory to load the bitmap */ + DosAllocMem((PPVOID)&BitmapFileBegin, (ULONG)BitmapStatus.cbFile, + PAG_READ | PAG_WRITE | PAG_COMMIT); + + /* read bitmap file into memory buffer */ + DosRead(BitmapFileHandle, (PVOID)BitmapFileBegin, + BitmapStatus.cbFile, &cbRead); + + /* access first bytes as bitmap header */ + pBitmapFileHeader = (PBITMAPFILEHEADER2)BitmapFileBegin; + + /* check if it's a valid bitmap data file */ + if((pBitmapFileHeader->usType != BFT_BITMAPARRAY) && + (pBitmapFileHeader->usType != BFT_BMAP)) + { + /* free memory of bitmap file buffer */ + DosFreeMem(BitmapFileBegin); + /* close the bitmap file */ + DosClose(BitmapFileHandle); + return 0; + } + + /* check if it's a file with multiple bitmaps */ + if(pBitmapFileHeader->usType == BFT_BITMAPARRAY) + { + /* we'll just use the first bitmap and ignore the others */ + pBitmapFileHeader = &(((PBITMAPARRAYFILEHEADER2)BitmapFileBegin)->bfh2); + } + + /* set pointer to bitmap information block */ + pBitmapInfoHeader = &pBitmapFileHeader->bmp2; + + /* find out if it's the new 2.0 format or the old format */ + /* and query number of lines */ + if(pBitmapInfoHeader->cbFix == sizeof(BITMAPINFOHEADER)) + { + *height = (ULONG)((PBITMAPINFOHEADER)pBitmapInfoHeader)->cy; + *width = (ULONG)((PBITMAPINFOHEADER)pBitmapInfoHeader)->cx; + *depth = (int)((PBITMAPINFOHEADER)pBitmapInfoHeader)->cBitCount; + } + else + { + *height = pBitmapInfoHeader->cy; + *width = pBitmapInfoHeader->cx; + *depth = pBitmapInfoHeader->cBitCount; + } + + /* Put the bitmap bits into the destination */ + BitmapBits = BitmapFileBegin + pBitmapFileHeader->offBits; + + /* close the bitmap file */ + DosClose(BitmapFileHandle); + } + + /* now we need a presentation space, get it from static control */ + hps1 = WinGetPS(handle); + + hdc1 = GpiQueryDevice(hps1); + ulFlags = GpiQueryPS(hps1, &sizl); + + *hdc = DevOpenDC(dwhab, OD_MEMORY, (PSZ)"*", 0L, NULL, hdc1); + *hps = GpiCreatePS (dwhab, *hdc, &sizl, ulFlags | GPIA_ASSOC); + + /* create bitmap now using the parameters from the info block */ + *hbm = GpiCreateBitmap(*hps, pBitmapInfoHeader, 0L, NULL, NULL); + + /* select the new bitmap into presentation space */ + GpiSetBitmap(*hps, *hbm); + + /* now copy the bitmap data into the bitmap */ + GpiSetBitmapBits(*hps, 0L, *height, + BitmapBits, + (PBITMAPINFO2)pBitmapInfoHeader); + + WinReleasePS(hps1); + + /* free memory of bitmap file buffer */ + if(BitmapFileBegin) + DosFreeMem(BitmapFileBegin); + return 1; } /* @@ -6143,9 +7361,10 @@ } else if ( filename ) { - HDC hdc; + HDC hdc = 0; unsigned long width, height; - char *file = alloca(strlen(filename) + 5); + char *file = alloca(strlen(filename) + 6); + int depth; if(!file) return; @@ -6155,13 +7374,22 @@ /* check if we can read from this file (it exists and read permission) */ if(access(file, 04) != 0) { - /* Try with .bmp extention */ - strcat(file, ".bmp"); - if(access(file, 04) != 0) - return; - } - - if(!_load_bitmap_file(file, handle, &hbm, &hdc, &hps, &width, &height)) + int z; + + /* Try with supported extensions */ + for(z=0;z<(_gbm_init?NUM_EXTS:1);z++) + { + strcpy(file, filename); + strcat(file, image_exts[z]); + if(access(file, 04) == 0 && + _load_bitmap_file(file, handle, &hbm, &hdc, &hps, &width, &height, &depth)) + break; + } + } + else + _load_bitmap_file(file, handle, &hbm, &hdc, &hps, &width, &height, &depth); + + if(!hdc) return; dw_window_set_data(handle, "_dw_hps", (void *)hps); @@ -6172,11 +7400,22 @@ else return; - WinSetWindowBits(handle,QWL_STYLE,SS_BITMAP,SS_BITMAP | 0x7f); - WinSendMsg( handle, SM_SETHANDLE, MPFROMP(hbm), NULL ); if ( id ) WinReleasePS(hps); dw_window_set_data(handle, "_dw_bitmap", (void *)hbm); + + /* If we changed the bitmap... */ + { + Item *item = _box_item(handle); + + /* Check to see if any of the sizes need to be recalculated */ + if(item && (item->origwidth == -1 || item->origheight == -1)) + { + _control_size(handle, item->origwidth == -1 ? &item->width : NULL, item->origheight == -1 ? &item->height : NULL); + /* Queue a redraw on the top-level window */ + _dw_redraw(_toplevel_window(handle), TRUE); + } + } } /* @@ -6197,17 +7436,12 @@ unsigned long width, height; char *file; FILE *fp; + int depth; /* Destroy any old bitmap data */ _free_bitmap(handle); - /* If id is non-zero use the resource */ - if ( id ) - { - hps = WinGetPS( handle ); - hbm = GpiLoadBitmap( hps, NULLHANDLE, id, 0, 0 ); - } - else if ( data ) + if ( data ) { file = tmpnam( NULL ); if ( file != NULL ) @@ -6217,11 +7451,9 @@ { fwrite( data, 1, len, fp ); fclose( fp ); - if ( len > 1 && data[0] == 'B' && data[1] == 'M' ) /* first 2 chars of data is BM, then its a BMP */ - _load_bitmap_file(file, handle, &hbm, &hdc, &hps, &width, &height); - else /* otherwise its assumed to be an ico */ + if(!_load_bitmap_file(file, handle, &hbm, &hdc, &hps, &width, &height, &depth)) { - /* con't use ICO ? */ + /* can't use ICO ? */ unlink( file ); return; } @@ -6239,11 +7471,15 @@ dw_window_set_data(handle, "_dw_width", (void *)width); dw_window_set_data(handle, "_dw_height", (void *)height); } + /* If id is non-zero use the resource */ + else if ( id ) + { + hps = WinGetPS( handle ); + hbm = GpiLoadBitmap( hps, NULLHANDLE, id, 0, 0 ); + } else return; - WinSetWindowBits(handle,QWL_STYLE,SS_BITMAP,SS_BITMAP | 0x7f); - WinSendMsg( handle, SM_SETHANDLE, MPFROMP(hbm), NULL ); if ( id ) WinReleasePS(hps); dw_window_set_data(handle, "_dw_bitmap", (void *)hbm); @@ -6259,6 +7495,38 @@ { HWND entryfield = (HWND)dw_window_get_data(handle, "_dw_buddy"); WinSetWindowText(entryfield ? entryfield : handle, (PSZ)text); + /* If we changed the text... */ + { + Item *item = _box_item(handle); + + /* Check to see if any of the sizes need to be recalculated */ + if(item && (item->origwidth == -1 || item->origheight == -1)) + { + _control_size(handle, item->origwidth == -1 ? &item->width : NULL, item->origheight == -1 ? &item->height : NULL); + /* Queue a redraw on the top-level window */ + _dw_redraw(_toplevel_window(handle), TRUE); + } + } +} + +/* + * Sets the text used for a given window's floating bubble help. + * Parameters: + * handle: Handle to the window (widget). + * bubbletext: The text in the floating bubble tooltip. + */ +void API dw_window_set_tooltip(HWND handle, char *bubbletext) +{ + HWND buddy = (HWND)dw_window_get_data(handle, "_dw_comboentry"); + WindowData *blah = (WindowData *)WinQueryWindowPtr(buddy ? buddy : handle, QWP_USER); + char *text = bubbletext ? bubbletext : ""; + + buddy = (HWND)dw_window_get_data(handle, "_dw_buddy"); + + if(blah) + strncpy(blah->bubbletext, text, BUBBLE_HELP_MAX - 1); + if(buddy && (blah = (WindowData *)WinQueryWindowPtr(buddy, QWP_USER))) + strncpy(blah->bubbletext, text, BUBBLE_HELP_MAX - 1); } /* @@ -6286,7 +7554,7 @@ */ void API dw_window_disable(HWND handle) { - char tmpbuf[100]; + char tmpbuf[100] = {0}; if(handle < 65536) { @@ -6387,7 +7655,7 @@ { HENUM henum; HWND child; - char tmpbuf[100]; + char tmpbuf[100] = {0}; henum = WinBeginEnumWindows(handle); while((child = WinGetNextWindow(henum)) != NULLHANDLE) @@ -6437,7 +7705,6 @@ else { box = WinWindowFromID(box, FID_CLIENT); - hsize = vsize = TRUE; } } @@ -6447,16 +7714,18 @@ { int z, x = 0; Item *tmpitem, *thisitem = thisbox->items; - char tmpbuf[100]; + char tmpbuf[100] = {0}; HWND frame = (HWND)dw_window_get_data(item, "_dw_combo_box"); /* Do some sanity bounds checking */ + if(!thisitem) + thisbox->count = 0; if(index < 0) index = 0; if(index > thisbox->count) index = thisbox->count; - tmpitem = malloc(sizeof(Item)*(thisbox->count+1)); + tmpitem = calloc(sizeof(Item), (thisbox->count+1)); for(z=0;z<thisbox->count;z++) { @@ -6466,7 +7735,6 @@ x++; } - WinQueryClassName(item, 99, (PCH)tmpbuf); if(vsize && !height) @@ -6474,7 +7742,7 @@ if(hsize && !width) width = 1; - if(strncmp(tmpbuf, "#1", 3)==0) + if(strncmp(tmpbuf, "#1", 3)==0 && !dw_window_get_data(item, "_dw_render")) tmpitem[index].type = TYPEBOX; else { @@ -6490,36 +7758,160 @@ tmpitem[index].origwidth = tmpitem[index].width = width; tmpitem[index].origheight = tmpitem[index].height = height; tmpitem[index].pad = pad; - if(hsize) - tmpitem[index].hsize = SIZEEXPAND; - else - tmpitem[index].hsize = SIZESTATIC; - - if(vsize) - tmpitem[index].vsize = SIZEEXPAND; - else - tmpitem[index].vsize = SIZESTATIC; + tmpitem[index].hsize = hsize ? SIZEEXPAND : SIZESTATIC; + tmpitem[index].vsize = vsize ? SIZEEXPAND : SIZESTATIC; + + /* If either of the parameters are -1 ... calculate the size */ + if(width == -1 || height == -1) + _control_size(item, width == -1 ? &tmpitem[index].width : NULL, height == -1 ? &tmpitem[index].height : NULL); thisbox->items = tmpitem; - if(thisbox->count) + if(thisitem) free(thisitem); thisbox->count++; WinQueryClassName(item, 99, (PCH)tmpbuf); - /* Don't set the ownership if it's an entryfield or spinbutton */ - if(strncmp(tmpbuf, "#6", 3)!=0 && strncmp(tmpbuf, "#32", 4)!=0 && strncmp(tmpbuf, "#2", 3)!=0) - WinSetOwner(item, box); + /* Don't set the ownership if it's an entryfield + * NOTE: spinbutton used to be in this list but it was preventing value change events + * from firing, so I removed it. If spinbuttons cause problems revisit this. + */ + if(strncmp(tmpbuf, "#6", 3)!=0 && /*strncmp(tmpbuf, "#32", 4)!=0 &&*/ strncmp(tmpbuf, "#2", 3)!=0) + WinSetOwner(item, box); WinSetParent(frame ? frame : item, box, FALSE); - } + _handle_transparent(box); + /* Queue a redraw on the top-level window */ + _dw_redraw(_toplevel_window(box), TRUE); + } +} + +/* + * Remove windows (widgets) from the box they are packed into. + * Parameters: + * handle: Window handle of the packed item to be removed. + * Returns: + * DW_ERROR_NONE on success and DW_ERROR_GENERAL on failure. + */ +int API dw_box_unpack(HWND handle) +{ + HWND parent = WinQueryWindow(handle, QW_PARENT); + + if(parent != desktop) + { + Box *thisbox = WinQueryWindowPtr(parent, QWP_USER); + + /* If the parent box has items... + * try to remove it from the layout + */ + if(thisbox && thisbox->count) + { + int z, index = -1; + Item *tmpitem = NULL, *thisitem = thisbox->items; + + if(!thisitem) + thisbox->count = 0; + + for(z=0;z<thisbox->count;z++) + { + if(thisitem[z].hwnd == handle) + index = z; + } + + if(index == -1) + return DW_ERROR_GENERAL; + + if(thisbox->count > 1) + { + tmpitem = calloc(sizeof(Item), (thisbox->count-1)); + + /* Copy all but the current entry to the new list */ + for(z=0;z<index;z++) + { + tmpitem[z] = thisitem[z]; + } + for(z=index+1;z<thisbox->count;z++) + { + tmpitem[z-1] = thisitem[z]; + } + } + + thisbox->items = tmpitem; + if(thisitem) + free(thisitem); + if(tmpitem) + thisbox->count--; + else + thisbox->count = 0; + + /* If it isn't padding, reset the parent */ + if(handle) + WinSetParent(handle, HWND_OBJECT, FALSE); + /* Queue a redraw on the top-level window */ + _dw_redraw(_toplevel_window(parent), TRUE); + return DW_ERROR_NONE; + } + } + return DW_ERROR_GENERAL; +} + +/* + * Remove windows (widgets) from a box at an arbitrary location. + * Parameters: + * box: Window handle of the box to be removed from. + * index: 0 based index of packed items. + * Returns: + * Handle to the removed item on success, 0 on failure or padding. + */ +HWND API dw_box_unpack_at_index(HWND box, int index) +{ + Box *thisbox = WinQueryWindowPtr(box, QWP_USER); + + /* Try to remove it from the layout */ + if(thisbox && index > -1 && index < thisbox->count) + { + int z; + Item *tmpitem = NULL, *thisitem = thisbox->items; + HWND handle = thisitem[index].hwnd; + + if(thisbox->count > 1) + { + tmpitem = calloc(sizeof(Item), (thisbox->count-1)); + + /* Copy all but the current entry to the new list */ + for(z=0;z<index;z++) + { + tmpitem[z] = thisitem[z]; + } + for(z=index+1;z<thisbox->count;z++) + { + tmpitem[z-1] = thisitem[z]; + } + } + + thisbox->items = tmpitem; + if(thisitem) + free(thisitem); + if(tmpitem) + thisbox->count--; + else + thisbox->count = 0; + + /* If it isn't padding, reset the parent */ + if(handle) + WinSetParent(handle, HWND_OBJECT, FALSE); + /* Queue a redraw on the top-level window */ + _dw_redraw(_toplevel_window(box), TRUE); + return handle; + } + return 0; } /* * Pack windows (widgets) into a box at an arbitrary location. * Parameters: * box: Window handle of the box to be packed into. - * item: Window handle of the item to be back. + * item: Window handle of the item to pack. * index: 0 based index of packed items. * width: Width in pixels of the item or -1 to be self determined. * height: Height in pixels of the item or -1 to be self determined. @@ -6536,7 +7928,7 @@ * Pack windows (widgets) into a box from the start (or top). * Parameters: * box: Window handle of the box to be packed into. - * item: Window handle of the item to be back. + * item: Window handle of the item to pack. * width: Width in pixels of the item or -1 to be self determined. * height: Height in pixels of the item or -1 to be self determined. * hsize: TRUE if the window (widget) should expand horizontally to fill space given. @@ -6555,7 +7947,7 @@ * Pack windows (widgets) into a box from the end (or bottom). * Parameters: * box: Window handle of the box to be packed into. - * item: Window handle of the item to be back. + * item: Window handle of the item to pack. * width: Width in pixels of the item or -1 to be self determined. * height: Height in pixels of the item or -1 to be self determined. * hsize: TRUE if the window (widget) should expand horizontally to fill space given. @@ -6568,6 +7960,34 @@ } /* + * The following is an attempt to dynamically size a window based on the size of its + * children before realization. Only applicable when width or height is less than one. + */ +void _get_window_for_size(HWND handle, unsigned long *width, unsigned long *height) +{ + HWND box = WinWindowFromID(handle, FID_CLIENT); + Box *thisbox = WinQueryWindowPtr(box, QWP_USER); + + if(thisbox) + { + int depth = 0; + RECTL rect = { 0 }; + + /* Calculate space requirements */ + _resize_box(thisbox, &depth, *width, *height, 1); + + rect.xRight = thisbox->minwidth; + rect.yTop = thisbox->minheight; + + /* Take into account the window border and menu here */ + WinCalcFrameRect(handle, &rect, FALSE); + + if(*width < 1) *width = rect.xRight - rect.xLeft; + if(*height < 1) *height = rect.yTop - rect.yBottom; + } +} + +/* * Sets the size of a given window (widget). * Parameters: * handle: Window (widget) handle. @@ -6576,7 +7996,61 @@ */ void API dw_window_set_size(HWND handle, ULONG width, ULONG height) { - WinSetWindowPos(handle, NULLHANDLE, 0, 0, width, height, SWP_SHOW | SWP_SIZE); + /* Attempt to auto-size */ + if ( width < 1 || height < 1 ) + _get_window_for_size(handle, &width, &height); + + /* Finally set the size */ + WinSetWindowPos(handle, NULLHANDLE, 0, 0, width, height, SWP_SIZE); +} + +/* + * Gets the size the system thinks the widget should be. + * Parameters: + * handle: Window handle of the item to be back. + * width: Width in pixels of the item or NULL if not needed. + * height: Height in pixels of the item or NULL if not needed. + */ +void API dw_window_get_preferred_size(HWND handle, int *width, int *height) +{ + char tmpbuf[100] = {0}; + + WinQueryClassName(handle, 99, (PCH)tmpbuf); + + if(strncmp(tmpbuf, "#1", 3)==0) + { + HWND box = WinWindowFromID(handle, FID_CLIENT); + + if(box) + { + unsigned long thiswidth = 0, thisheight = 0; + + /* Get the size with the border */ + _get_window_for_size(handle, &thiswidth, &thisheight); + + /* Return what was requested */ + if(width) *width = (int)thiswidth; + if(height) *height = (int)thisheight; + } + else + { + Box *thisbox = WinQueryWindowPtr(handle, QWP_USER); + + if(thisbox) + { + int depth = 0; + + /* Calculate space requirements */ + _resize_box(thisbox, &depth, 0, 0, 1); + + /* Return what was requested */ + if(width) *width = thisbox->minwidth; + if(height) *height = thisbox->minheight; + } + } + } + else + _control_size(handle, width, height); } /* @@ -6606,6 +8080,70 @@ return colors; } +/* + * Sets the gravity of a given window (widget). + * Gravity controls which corner of the screen and window the position is relative to. + * Parameters: + * handle: Window (widget) handle. + * horz: DW_GRAV_LEFT (default), DW_GRAV_RIGHT or DW_GRAV_CENTER. + * vert: DW_GRAV_TOP (default), DW_GRAV_BOTTOM or DW_GRAV_CENTER. + */ +void API dw_window_set_gravity(HWND handle, int horz, int vert) +{ + dw_window_set_data(handle, "_dw_grav_horz", DW_INT_TO_POINTER(horz)); + dw_window_set_data(handle, "_dw_grav_vert", DW_INT_TO_POINTER(vert)); +} + +/* Convert the coordinates based on gravity */ +void _handle_gravity(HWND handle, long *x, long *y, unsigned long width, unsigned long height) +{ + int horz = DW_POINTER_TO_INT(dw_window_get_data(handle, "_dw_grav_horz")); + int vert = DW_POINTER_TO_INT(dw_window_get_data(handle, "_dw_grav_vert")); + + /* Do any gravity calculations */ + if(horz || (vert & 0xf) != DW_GRAV_BOTTOM) + { + long newx = *x, newy = *y; + + /* Handle horizontal center gravity */ + if((horz & 0xf) == DW_GRAV_CENTER) + newx += ((dw_screen_width() / 2) - (width / 2)); + /* Handle right gravity */ + else if((horz & 0xf) == DW_GRAV_RIGHT) + newx = dw_screen_width() - width - *x; + /* Handle vertical center gravity */ + if((vert & 0xf) == DW_GRAV_CENTER) + newy += ((dw_screen_height() / 2) - (height / 2)); + else if((vert & 0xf) == DW_GRAV_TOP) + newy = dw_screen_height() - height - *y; + + /* Save the new values */ + *x = newx; + *y = newy; + } + /* Adjust the values to avoid WarpCenter/XCenter/eCenter if requested */ + if(_WinQueryDesktopWorkArea && (horz | vert) & DW_GRAV_OBSTACLES) + { + RECTL rect; + + _WinQueryDesktopWorkArea(HWND_DESKTOP, &rect); + + if(horz & DW_GRAV_OBSTACLES) + { + if((horz & 0xf) == DW_GRAV_LEFT) + *x += rect.xLeft; + else if((horz & 0xf) == DW_GRAV_RIGHT) + *x -= dw_screen_width() - rect.xRight; + } + if(vert & DW_GRAV_OBSTACLES) + { + if((vert & 0xf) == DW_GRAV_BOTTOM) + *y += rect.yBottom; + else if((vert & 0xf) == DW_GRAV_TOP) + *y -= dw_screen_height() - rect.yTop; + } + } +} /* * Sets the position of a given window (widget). @@ -6616,9 +8154,17 @@ */ void API dw_window_set_pos(HWND handle, LONG x, LONG y) { - int myy = _get_frame_height(handle) - (y + _get_height(handle)); - - WinSetWindowPos(handle, NULLHANDLE, x, myy, 0, 0, SWP_MOVE); + unsigned long width, height; + + dw_window_get_pos_size(handle, NULL, NULL, &width, &height); + /* Can't position an unsized window, so attempt to auto-size */ + if(width == 0 || height == 0) + { + dw_window_set_size(handle, 0, 0); + dw_window_get_pos_size(handle, NULL, NULL, &width, &height); + } + _handle_gravity(handle, &x, &y, width, height); + WinSetWindowPos(handle, NULLHANDLE, x, y, 0, 0, SWP_MOVE); } /* @@ -6632,9 +8178,13 @@ */ void API dw_window_set_pos_size(HWND handle, LONG x, LONG y, ULONG width, ULONG height) { - int myy = _get_frame_height(handle) - (y + height); - - WinSetWindowPos(handle, NULLHANDLE, x, myy, width, height, SWP_MOVE | SWP_SIZE | SWP_SHOW); + /* Attempt to auto-size */ + if ( width < 1 || height < 1 ) + _get_window_for_size(handle, &width, &height); + + _handle_gravity(handle, &x, &y, width, height); + /* Finally set the size */ + WinSetWindowPos(handle, NULLHANDLE, x, y, width, height, SWP_MOVE | SWP_SIZE); } /* @@ -6927,7 +8477,7 @@ */ void API dw_listbox_select(HWND handle, int index, int state) { - char tmpbuf[100]; + char tmpbuf[100] = {0}; WinSendMsg(handle, LM_SELECTITEM, MPFROMSHORT(index), (MPARAM)state); @@ -7309,7 +8859,9 @@ */ void API dw_spinbutton_set_pos(HWND handle, long position) { + dw_window_set_data(handle, "_dw_updating", (void *)1); WinSendMsg(handle, SPBM_SETCURRENTVALUE, MPFROMLONG((long)position), 0L); + dw_window_set_data(handle, "_dw_updating", NULL); } /* @@ -7687,7 +9239,7 @@ details->cb = sizeof(FIELDINFO); details->flData = flags[z]; details->flTitle = CFA_FITITLEREADONLY; - details->pTitleData = titles[z]; + details->pTitleData = strdup(titles[z]); details->offStruct = offStruct[z]; details = details->pNextFieldInfo; } @@ -7719,6 +9271,19 @@ } /* + * Configures the main filesystem columnn title for localization. + * Parameters: + * handle: Handle to the container to be configured. + * title: The title to be displayed in the main column. + */ +void API dw_filesystem_set_column_title(HWND handle, char *title) +{ + char *newtitle = strdup(title ? title : ""); + + dw_window_set_data(handle, "_dw_coltitle", newtitle); +} + +/* * Sets up the filesystem columns, note: filesystem always has an icon/filename field. * Parameters: * handle: Handle to the container to be configured. @@ -7730,9 +9295,10 @@ { char **newtitles = malloc(sizeof(char *) * (count + 2)); unsigned long *newflags = malloc(sizeof(unsigned long) * (count + 2)); - - newtitles[0] = "Icon"; - newtitles[1] = "Filename"; + char *coltitle = (char *)dw_window_get_data(handle, "_dw_coltitle"); + + newtitles[0] = ""; + newtitles[1] = coltitle ? coltitle : "Filename"; newflags[0] = DW_CFA_BITMAPORICON | DW_CFA_CENTER | DW_CFA_HORZSEPARATOR | DW_CFA_SEPARATOR; newflags[1] = DW_CFA_STRING | DW_CFA_LEFT | DW_CFA_HORZSEPARATOR; @@ -7760,6 +9326,43 @@ return WinLoadPointer(HWND_DESKTOP,module,id); } +/* Internal function to create an icon from an existing pixmap */ +HICN _create_icon(HPIXMAP src) +{ + HPIXMAP pntr = dw_pixmap_new(hwndApp, WinQuerySysValue(HWND_DESKTOP, SV_CXICON), WinQuerySysValue(HWND_DESKTOP, SV_CYICON), src->depth); + HPIXMAP mask = dw_pixmap_new(hwndApp, pntr->width, pntr->height*2, 1); + HPIXMAP minipntr = dw_pixmap_new(hwndApp, pntr->width/2, pntr->height/2, src->depth); + HPIXMAP minimask = dw_pixmap_new(hwndApp, minipntr->width, minipntr->height*2, 1); + ULONG oldcol = _foreground; + POINTERINFO pi = {0}; + + /* Create the color pointers, stretching it to the necessary size */ + dw_pixmap_stretch_bitblt(0, pntr, 0, 0, pntr->width, pntr->height, 0, src, 0, 0, src->width, src->height); + dw_pixmap_stretch_bitblt(0, minipntr, 0, 0, minipntr->width, minipntr->height, 0, src, 0, 0, src->width, src->height); + + /* Create the masks, all in black */ + dw_color_foreground_set(DW_CLR_BLACK); + dw_draw_rect(0, mask, DW_DRAW_FILL, 0, 0, mask->width, mask->height); + dw_draw_rect(0, minimask, DW_DRAW_FILL, 0, 0, minimask->width, minimask->height); + _foreground = oldcol; + + /* Assemble the Pointer Info structure */ + pi.hbmPointer = mask->hbm; + pi.hbmColor = pntr->hbm; + pi.hbmMiniPointer = minimask->hbm; + pi.hbmMiniColor = minipntr->hbm; + + /* Destroy the pixmaps but not the bitmaps */ + mask->hbm = pntr->hbm = minimask->hbm = minipntr->hbm = 0; + dw_pixmap_destroy(mask); + dw_pixmap_destroy(pntr); + dw_pixmap_destroy(minimask); + dw_pixmap_destroy(minipntr); + + /* Generate the icon */ + return WinCreatePointerIndirect(HWND_DESKTOP, &pi); +} + /* * Obtains an icon from a file. * Parameters: @@ -7769,9 +9372,11 @@ */ HICN API dw_icon_load_from_file(char *filename) { - char *file = alloca(strlen(filename) + 5); - - if(!file) + char *file = alloca(strlen(filename) + 6); + HPIXMAP src = alloca(sizeof(struct _hpixmap)); + HICN icon = 0; + + if(!file || !src) return 0; strcpy(file, filename); @@ -7779,12 +9384,39 @@ /* check if we can read from this file (it exists and read permission) */ if(access(file, 04) != 0) { - /* Try with .bmp extention */ - strcat(file, ".ico"); - if(access(file, 04) != 0) - return 0; - } - return WinLoadFileIcon((PSZ)file, FALSE); + int z; + + /* Try with .ico extention */ + strcat(file, ".ico"); + if(access(file, 04) == 0) + return WinLoadFileIcon((PSZ)file, FALSE); + + /* Try with supported extensions */ + for(z=0;z<(_gbm_init?NUM_EXTS:1);z++) + { + strcpy(file, filename); + strcat(file, image_exts[z]); + if(access(file, 04) == 0 && + _load_bitmap_file(file, hwndApp, &src->hbm, &src->hdc, &src->hps, &src->width, &src->height, &src->depth)) + { + icon = _create_icon(src); + break; + } + } + } + else if(_load_bitmap_file(file, hwndApp, &src->hbm, &src->hdc, &src->hps, &src->width, &src->height, &src->depth)) + icon = _create_icon(src); + /* Free temporary resources if in use */ + if(icon) + { + GpiSetBitmap(src->hps, NULLHANDLE); + GpiDeleteBitmap(src->hbm); + GpiAssociate(src->hps, NULLHANDLE); + GpiDestroyPS(src->hps); + DevCloseDC(src->hdc); + } + /* Otherwise fall back to the classic method */ + return icon ? icon : WinLoadFileIcon((PSZ)file, FALSE); } /* @@ -7810,12 +9442,7 @@ { fwrite( data, 1, len, fp ); fclose( fp ); - icon = WinLoadFileIcon( (PSZ)file, FALSE ); - } - else - { - unlink( file ); - return 0; + icon = dw_icon_load_from_file(file); } unlink( file ); } @@ -7899,7 +9526,7 @@ ULONG totalsize, size = 0, *flags = blah ? blah->data : 0; int z, currentcount; CNRINFO cnr; - void *dest; + void *dest; if(!flags) return; @@ -7932,7 +9559,12 @@ dest = (void *)(((ULONG)temp)+((ULONG)totalsize)); if(flags[column] & DW_CFA_BITMAPORICON) - memcpy(dest, data, sizeof(HPOINTER)); + { + if(data) + memcpy(dest, data, sizeof(HPOINTER)); + else + memset(dest, 0, sizeof(HPOINTER)); + } else if(flags[column] & DW_CFA_STRING) { char **newstr = (char **)data, **str = dest; @@ -7946,11 +9578,26 @@ *str = NULL; } else if(flags[column] & DW_CFA_ULONG) - memcpy(dest, data, sizeof(ULONG)); + { + if(data) + memcpy(dest, data, sizeof(ULONG)); + else + memset(dest, 0, sizeof(ULONG)); + } else if(flags[column] & DW_CFA_DATE) - memcpy(dest, data, sizeof(CDATE)); + { + if(data) + memcpy(dest, data, sizeof(CDATE)); + else + memset(dest, 0, sizeof(CDATE)); + } else if(flags[column] & DW_CFA_TIME) - memcpy(dest, data, sizeof(CTIME)); + { + if(data) + memcpy(dest, data, sizeof(CTIME)); + else + memset(dest, 0, sizeof(CTIME)); + } } /* Internal function that free()s any strings allocated for a container item */ @@ -8274,7 +9921,7 @@ free(ci); - if((pCore = _dw_container_start(handle, CRA_CURSORED))) + if((pCore = _dw_container_start(handle, CRA_CURSORED)) != NULL) { NOTIFYRECORDEMPHASIS pre; @@ -8603,6 +10250,7 @@ NULL, NULL); WinSubclassWindow(hwndframe, _RendProc); + dw_window_set_data(hwndframe, "_dw_render", DW_INT_TO_POINTER(1)); return hwndframe; } @@ -8672,7 +10320,7 @@ DWDialog *dwwait; HMTX mtx = dw_mutex_new(); - window = dw_window_new( HWND_DESKTOP, "Choose Color", FCF_SHELLPOSITION | FCF_TITLEBAR | FCF_DLGBORDER | FCF_CLOSEBUTTON | FCF_SYSMENU); + window = dw_window_new( HWND_DESKTOP, "Choose Color", FCF_TITLEBAR | FCF_DLGBORDER | FCF_CLOSEBUTTON | FCF_SYSMENU); vbox = dw_box_new(DW_VERT, 5); @@ -8802,7 +10450,7 @@ if(handle) { hps = _set_colors(handle); - height = _get_height(handle); + height = _get_height(handle); } else if(pixmap) { @@ -8816,7 +10464,7 @@ ptl.y = height - y - 1; GpiSetPel(hps, &ptl); - if(!pixmap) + if(handle) WinReleasePS(hps); } @@ -8838,7 +10486,7 @@ if(handle) { hps = _set_colors(handle); - height = _get_height(handle); + height = _get_height(handle); } else if(pixmap) { @@ -8856,8 +10504,8 @@ GpiMove(hps, &ptl[0]); GpiLine(hps, &ptl[1]); - if(!pixmap) - WinReleasePS(hps); + if(handle) + WinReleasePS(hps); } @@ -8873,6 +10521,9 @@ fat.usRecordLength = sizeof(FATTRS); fat.lMatch = fm.lMatch; +#ifdef UNICODE + fat.usCodePage = 1208; +#endif strcpy(fat.szFacename, fm.szFacename); GpiCreateLogFont(hpsDst, 0, 1L, &fat); @@ -8936,7 +10587,7 @@ else WinDrawText(hps, -1, (PCH)text, &rcl, _internal_color(_foreground), _internal_color(_background), DT_VCENTER | DT_LEFT | DT_ERASERECT); - if(!pixmap) + if(handle) WinReleasePS(hps); } @@ -8976,7 +10627,7 @@ if(height) *height = aptl[TXTBOX_TOPLEFT].y - aptl[TXTBOX_BOTTOMLEFT].y; - if(!pixmap) + if(handle) WinReleasePS(hps); } @@ -9041,7 +10692,7 @@ if ( flags & DW_DRAW_FILL ) GpiEndArea( hps ); } - if ( !pixmap ) + if(handle) WinReleasePS(hps); free( pptl ); } @@ -9065,7 +10716,7 @@ if(handle) { hps = _set_colors(handle); - thisheight = _get_height(handle); + thisheight = _get_height(handle); } else if(pixmap) { @@ -9083,7 +10734,7 @@ GpiMove(hps, &ptl[0]); GpiBox(hps, (flags & DW_DRAW_FILL) ? DRO_OUTLINEFILL : DRO_OUTLINE, &ptl[1], 0, 0); - if(!pixmap) + if(handle) WinReleasePS(hps); } @@ -9169,7 +10820,7 @@ GpiEndArea(hps); } - if(!pixmap) + if(handle) WinReleasePS(hps); } @@ -9198,7 +10849,7 @@ HDC hdc; HPS hps; ULONG ulFlags; - LONG cPlanes, cBitCount; + LONG cPlanes, cBitCount; if (!(pixmap = calloc(1,sizeof(struct _hpixmap)))) return NULL; @@ -9228,6 +10879,7 @@ pixmap->width = width; pixmap->height = height; pixmap->transcolor = DW_CLR_DEFAULT; + pixmap->depth = depth; pixmap->hbm = GpiCreateBitmap(pixmap->hps, (PBITMAPINFOHEADER2)&bmih, 0L, NULL, NULL); @@ -9264,17 +10916,21 @@ /* check if we can read from this file (it exists and read permission) */ if ( access(file, 04) != 0 ) { - /* Try with .bmp extention */ - strcat(file, ".bmp"); - if ( access(file, 04) != 0 ) - { - free(pixmap); - return NULL; - } + int z; + + /* Try with supported extensions */ + for(z=0;z<(_gbm_init?NUM_EXTS:1);z++) + { + strcpy(file, filename); + strcat(file, image_exts[z]); + if(access(file, 04) == 0 && + _load_bitmap_file(file, handle, &pixmap->hbm, &pixmap->hdc, &pixmap->hps, &pixmap->width, &pixmap->height, &pixmap->depth)) + break; + } } /* Try to load the bitmap from file */ - if ( !_load_bitmap_file(file, handle, &pixmap->hbm, &pixmap->hdc, &pixmap->hps, &pixmap->width, &pixmap->height) ) + if(!pixmap->hbm) { free(pixmap); return NULL; @@ -9314,18 +10970,9 @@ { fwrite( data, 1, len, fp ); fclose( fp ); - if ( len > 1 && data[0] == 'B' && data[1] == 'M' ) /* first 2 chars of data is BM, then its a BMP */ - { - /* Try to load the bitmap from file */ - if ( !_load_bitmap_file(file, handle, &pixmap->hbm, &pixmap->hdc, &pixmap->hps, &pixmap->width, &pixmap->height) ) - { - free(pixmap); - return NULL; - } - } - else /* otherwise its assumed to be an ico */ - { - /* con't use ICO ? */ + if(!_load_bitmap_file(file, handle, &pixmap->hbm, &pixmap->hdc, &pixmap->hps, &pixmap->width, &pixmap->height, &pixmap->depth)) + { + /* can't use ICO ? */ unlink( file ); return NULL; } @@ -9513,7 +11160,7 @@ } else { - if(!destp) + if(dest) WinReleasePS(hpsdest); return DW_ERROR_GENERAL; } @@ -9549,9 +11196,9 @@ GpiBitBlt(hpsdest, hpssrc, count, ptl, ROP_SRCCOPY, BBO_IGNORE); } - if(!destp) + if(dest) WinReleasePS(hpsdest); - if(!srcp) + if(src) WinReleasePS(hpssrc); return DW_ERROR_NONE; } @@ -9949,11 +11596,16 @@ void _dwthreadstart(void *data) { HAB thishab = WinInitialize(0); - HMQ thishmq = WinCreateMsgQueue(dwhab, 0); - void (* API threadfunc)(void *) = NULL; + HMQ thishmq = WinCreateMsgQueue(thishab, 0); + void (API_FUNC threadfunc)(void *) = NULL; void **tmp = (void **)data; - threadfunc = (void (* API)(void *))tmp[0]; +#ifdef UNICODE + /* Set the codepage to 1208 (UTF-8) */ + WinSetCp(thishmq, 1208); +#endif + + threadfunc = (void (API_FUNC)(void *))tmp[0]; threadfunc(tmp[1]); free(tmp); @@ -9971,12 +11623,19 @@ */ DWTID API dw_thread_new(void *func, void *data, int stack) { - void **tmp = malloc(sizeof(void *) * 2); - - tmp[0] = func; - tmp[1] = data; - - return (DWTID)_beginthread((void (*)(void *))_dwthreadstart, NULL, stack, (void *)tmp); + void **tmp = malloc(sizeof(void *) * 2); + int z = 1; + + /* Clamp the stack size to 4K blocks... + * since some CRTs require it (VAC) + */ + while(stack > (4096*z)) + z++; + + tmp[0] = func; + tmp[1] = data; + + return (DWTID)_beginthread((void (*)(void *))_dwthreadstart, NULL, (z*4096), (void *)tmp); } /* @@ -10011,7 +11670,28 @@ */ Root = NULL; + /* Deinit the GBM */ + if(_gbm_deinit) + _gbm_deinit(); + +#ifdef UNICODE + /* Free the conversion object */ + UniFreeUconvObject(Uconv); + /* Deregister the Unicode clipboard format */ + WinDeleteAtom(WinQuerySystemAtomTable(), Unicode); +#endif + + /* Destroy the main message queue and anchor block */ + WinDestroyMsgQueue(dwhmq); + WinTerminate(dwhab); + + /* Free any in use modules */ DosFreeModule(wpconfig); + DosFreeModule(pmprintf); + DosFreeModule(pmmerge); + DosFreeModule(gbm); + + /* And finally exit */ exit(exitcode); } @@ -10216,19 +11896,27 @@ * Pointer to an allocated string of text or NULL if clipboard empty or contents could not * be converted to text. */ -char *dw_clipboard_get_text() -{ - APIRET rc; +char * API dw_clipboard_get_text(void) +{ char *retbuf = NULL; - ULONG fmtInfo; +#ifdef UNICODE + UniChar *unistr; +#endif WinOpenClipbrd(dwhab); - rc = WinQueryClipbrdFmtInfo(dwhab, CF_TEXT, &fmtInfo); - if (rc) /* Text data in clipboard */ +#ifdef UNICODE + if(!Unicode || !(unistr = (UniChar *)WinQueryClipbrdData(dwhab, Unicode)) || + !(retbuf = _WideToUTF8(unistr))) +#endif { - PSZ pszClipText = (PSZ)WinQueryClipbrdData(dwhab, CF_TEXT); /* Query data handle */ - retbuf = strdup((char *)pszClipText); + ULONG fmtInfo; + + if (WinQueryClipbrdFmtInfo(dwhab, CF_TEXT, &fmtInfo)) /* Text data in clipboard */ + { + PSZ pszClipText = (PSZ)WinQueryClipbrdData(dwhab, CF_TEXT); /* Query data handle */ + retbuf = strdup((char *)pszClipText); + } } WinCloseClipbrd(dwhab); return retbuf; @@ -10239,25 +11927,57 @@ * Parameters: * Text. */ -void dw_clipboard_set_text( char *str, int len ) -{ - APIRET rc; +void API dw_clipboard_set_text( char *str, int len ) +{ static PVOID shared; + PVOID old = shared, src = str; + int buflen = len + 1; WinOpenClipbrd(dwhab); /* Open clipboard */ WinEmptyClipbrd(dwhab); /* Empty clipboard */ /* Ok, clipboard wants giveable unnamed shared memory */ - shared = NULL; - rc = DosAllocSharedMem(&shared, NULL, len, OBJ_GIVEABLE | PAG_COMMIT | PAG_READ | PAG_WRITE); - - if (rc == 0) + if(!DosAllocSharedMem(&shared, NULL, buflen, OBJ_GIVEABLE | PAG_COMMIT | PAG_READ | PAG_WRITE)) { - memcpy(shared, str, len); + memcpy(shared, src, buflen); WinSetClipbrdData(dwhab, (ULONG)shared, CF_TEXT, CFI_POINTER); } + if(old) + DosFreeMem(old); + +#ifdef UNICODE + if(Unicode) + { + UniChar *unistr = NULL; + static PVOID ushared; + PVOID uold = ushared; + + src = calloc(len + 1, 1); + + memcpy(src, str, len); + unistr = _UTF8toWide((char *)src); + free(src); + + if(unistr) + { + buflen = (UniStrlen(unistr) + 1) * sizeof(UniChar); + src = unistr; + /* Ok, clipboard wants giveable unnamed shared memory */ + ushared = NULL; + if(!DosAllocSharedMem(&ushared, NULL, buflen, OBJ_GIVEABLE | PAG_COMMIT | PAG_READ | PAG_WRITE)) + { + memcpy(ushared, src, buflen); + + WinSetClipbrdData(dwhab, (ULONG)ushared, Unicode, CFI_POINTER); + } + free(unistr); + } + if(uold) + DosFreeMem(uold); + } +#endif WinCloseClipbrd(dwhab); /* Close clipboard */ return; @@ -10488,7 +12208,7 @@ DWDialog *dwwait; HMTX mtx = dw_mutex_new(); - window = dw_window_new( HWND_DESKTOP, title, FCF_SHELLPOSITION | FCF_TITLEBAR | FCF_SIZEBORDER | FCF_MINMAX); + window = dw_window_new( HWND_DESKTOP, title, FCF_TITLEBAR | FCF_SIZEBORDER | FCF_MINMAX); vbox = dw_box_new(DW_VERT, 5); @@ -10621,7 +12341,11 @@ int API dw_exec(char *program, int type, char **params) { type = type; /* keep compiler happy */ +#ifdef __EMX__ return spawnvp(P_NOWAIT, program, (char * const *)params); +#else + return spawnvp(P_NOWAIT, program, (const char * const *)params); +#endif } /* @@ -10747,7 +12471,7 @@ { HDC hdc; char *printername; - int (* API drawfunc)(HPRINT, HPIXMAP, int, void *); + int (API_FUNC drawfunc)(HPRINT, HPIXMAP, int, void *); void *drawdata; unsigned long flags; unsigned int startpage, endpage; @@ -10864,7 +12588,7 @@ if(!drawfunc || !(print = calloc(1, sizeof(DWPrint)))) return NULL; - print->drawfunc = drawfunc; + print->drawfunc = (int (API_FUNC)(HPRINT, HPIXMAP, int, void *))drawfunc; print->drawdata = drawdata; print->jobname = jobname ? jobname : "Dynamic Windows Print Job"; print->startpage = 1; @@ -10902,7 +12626,7 @@ } /* Create the print dialog */ - window = dw_window_new(HWND_DESKTOP, "Choose Printer", FCF_SHELLPOSITION | FCF_TITLEBAR | FCF_DLGBORDER | FCF_CLOSEBUTTON | FCF_SYSMENU); + window = dw_window_new(HWND_DESKTOP, "Choose Printer", FCF_TITLEBAR | FCF_DLGBORDER | FCF_CLOSEBUTTON | FCF_SYSMENU); vbox = dw_box_new(DW_VERT, 5); @@ -11099,7 +12823,7 @@ */ char * API dw_user_dir(void) { - static char _user_dir[1024] = ""; + static char _user_dir[MAX_PATH+1] = {0}; if(!_user_dir[0]) { @@ -11114,6 +12838,15 @@ } /* + * Returns a pointer to a static buffer which containes the + * private application data directory. + */ +char * API dw_app_dir(void) +{ + return _dw_exec_dir; +} + +/* * Call a function from the window (widget)'s context. * Parameters: * handle: Window handle of the widget. @@ -11490,16 +13223,15 @@ WindowData *blah = calloc(sizeof(WindowData), 1); DATETIME dt; HWND tmp = WinCreateWindow(HWND_OBJECT, - WC_STATIC, + (PSZ)CalendarClassName, NULL, - WS_VISIBLE | SS_TEXT, + WS_VISIBLE, 0,0,2000,1000, NULLHANDLE, HWND_TOP, id, NULL, NULL); - blah->oldproc = WinSubclassWindow(tmp, _calendarproc); WinSetWindowPtr(tmp, QWP_USER, blah); dw_window_set_font(tmp, DefaultFont); if(!DosGetDateTime(&dt)) @@ -11547,3 +13279,37 @@ if(day) *day = DW_POINTER_TO_UINT(dw_window_get_data(window, "_dw_day")) + 1; } + +/* + * Converts a UTF-8 encoded string into a wide string. + * Parameters: + * utf8string: UTF-8 encoded source string. + * Returns: + * Wide string that needs to be freed with dw_free() + * or NULL on failure. + */ +wchar_t * API dw_utf8_to_wchar(char *utf8string) +{ +#ifdef UNICODE + return _UTF8toWide(utf8string); +#else + return NULL; +#endif +} + +/* + * Converts a wide string into a UTF-8 encoded string. + * Parameters: + * wstring: Wide source string. + * Returns: + * UTF-8 encoded string that needs to be freed with dw_free() + * or NULL on failure. + */ +char * API dw_wchar_to_utf8(wchar_t *wstring) +{ +#ifdef UNICODE + return _WideToUTF8(wstring); +#else + return NULL; +#endif +}
--- a/rexx.c Sun Nov 20 11:11:53 2011 -0600 +++ b/rexx.c Wed Jul 25 00:05:29 2012 -0500 @@ -113,7 +113,8 @@ TRUE = 1\r\n\ FALSE = 0\r\n"; -unsigned long savedx = 0, savedy = 0, savedwidth = 0, savedheight = 0; +long savedx = 0, savedy = 0; +unsigned long savedwidth = 0, savedheight = 0; HWND windowhandle; RexxVar *root = NULL; @@ -1182,7 +1183,7 @@ int len = str ? strlen(str) : 0; char *newstr = NULL; - DosAllocMem(&newstr, len+1, PAG_READ|PAG_WRITE|PAG_COMMIT); + DosAllocMem((void **)&newstr, len+1, PAG_READ|PAG_WRITE|PAG_COMMIT); if(newstr) strncpy(newstr, str, len+1);
--- a/sfxace/makefile.vac Sun Nov 20 11:11:53 2011 -0600 +++ b/sfxace/makefile.vac Wed Jul 25 00:05:29 2012 -0500 @@ -47,7 +47,7 @@ $(OBJECTS) dw.obj install.obj instsup.obj rexx.obj dirent.obj ..\install.def << - rc -x2 ..\sfxos2.res sfxos2.exe + rc -x1 ..\sfxos2.res sfxos2.exe lxlite sfxos2.exe copy sfxos2.exe ..\sfx.exe
--- a/win/dw.c Sun Nov 20 11:11:53 2011 -0600 +++ b/win/dw.c Wed Jul 25 00:05:29 2012 -0500 @@ -2,18 +2,25 @@ * Dynamic Windows: * A GTK like implementation of the Win32 GUI * - * (C) 2000-2011 Brian Smith <brian@dbsoft.org> - * (C) 2003-2011 Mark Hessling <m.hessling@qut.edu.au> + * (C) 2000-2012 Brian Smith <brian@dbsoft.org> + * (C) 2003-2011 Mark Hessling <mark@rexx.org> * */ + +#ifdef AEROGLASS +#define _WIN32_IE 0x0501 +#define WINVER 0x501 +#else #define _WIN32_IE 0x0500 #define WINVER 0x500 +#endif #include <windows.h> #include <windowsx.h> #include <commctrl.h> #include <shlwapi.h> #include <shlobj.h> #include <userenv.h> +#include <tchar.h> #include <stdlib.h> #include <string.h> #include <stdio.h> @@ -21,11 +28,33 @@ #include <malloc.h> #include <io.h> #include <time.h> +#define _USE_MATH_DEFINES #include <math.h> #include "dw.h" #ifdef BUILD_DLL #include "XBrowseForFolder.h" #endif +#ifdef AEROGLASS +#include <uxtheme.h> +#endif +#include <richedit.h> + +#define STATICCLASSNAME TEXT("STATIC") +#define COMBOBOXCLASSNAME TEXT("COMBOBOX") +#define LISTBOXCLASSNAME TEXT("LISTBOX") +#define BUTTONCLASSNAME TEXT("BUTTON") +#define POPUPMENUCLASSNAME TEXT("POPUPMENU") +#define EDITCLASSNAME TEXT("EDIT") +#define FRAMECLASSNAME TEXT("FRAME") +#define SCROLLBARCLASSNAME TEXT("SCROLLBAR") + +#define ClassName TEXT("dynamicwindows") +#define SplitbarClassName TEXT("dwsplitbar") +#define ObjectClassName TEXT("dwobjectclass") +#define BrowserClassName TEXT("dwbrowserclass") +#define ScrollClassName TEXT("dwscrollclass") +#define StatusbarClassName TEXT("dwstatusbar") +#define DefaultFont NULL #ifdef GDIPLUS /* GDI+ Headers are not C compatible... so define what we need here instead */ @@ -60,15 +89,89 @@ PropertyNotFound = 19, PropertyNotSupported = 20, ProfileNotFound = 21 -} Status; - -Status WINAPI GdipCreateBitmapFromFile(const WCHAR* filename, void **bitmap); -Status WINAPI GdipCreateHBITMAPFromBitmap(void *bitmap, HBITMAP* hbmReturn, DWORD background); -Status WINAPI GdipCreateHICONFromBitmap(void *bitmap, HICON *hbmReturn); -Status WINAPI GdipDisposeImage(void *image); -Status WINAPI GdipGetImagePixelFormat(void *image, INT *format); -Status WINAPI GdiplusStartup(ULONG_PTR *token, const struct GdiplusStartupInput *input, void *output); +} GpStatus; + +typedef enum { + UnitWorld, + UnitDisplay, + UnitPixel, + UnitPoint, + UnitInch, + UnitDocument, + UnitMillimeter +} GpUnit; + +typedef enum { + FlushIntentionFlush = 0, + FlushIntentionSync = 1 +} GpFlushIntention; + +typedef enum { + QualityModeInvalid = -1, + QualityModeDefault = 0, + QualityModeLow = 1, + QualityModeHigh = 2 +} QualityMode; + +typedef enum { + SmoothingModeInvalid = QualityModeInvalid, + SmoothingModeDefault = QualityModeDefault, + SmoothingModeHighSpeed = QualityModeLow, + SmoothingModeHighQuality = QualityModeHigh, + SmoothingModeNone, + SmoothingModeAntiAlias +} SmoothingMode; + +typedef void GpGraphics; +typedef void GpPen; +typedef void GpBrush; +typedef void GpBitmap; +typedef void GpImage; +typedef POINT GpPoint; +typedef DWORD ARGB; +typedef float REAL; + +#define ALPHA_SHIFT 24 +#define RED_SHIFT 16 +#define GREEN_SHIFT 8 +#define BLUE_SHIFT 0 +#define ALPHA_MASK ((ARGB) 0xff << ALPHA_SHIFT) + +#define MAKEARGB(a, r, g, b) \ + (((ARGB) ((a) & 0xff) << ALPHA_SHIFT)| \ + ((ARGB) ((r) & 0xff) << RED_SHIFT) | \ + ((ARGB) ((g) & 0xff) << GREEN_SHIFT)| \ + ((ARGB) ((b) & 0xff) << BLUE_SHIFT)) + +/* Graphic conversion functions */ +GpStatus WINAPI GdipCreateBitmapFromFile(const WCHAR* filename, GpBitmap **bitmap); +GpStatus WINAPI GdipCreateHBITMAPFromBitmap(GpBitmap *bitmap, HBITMAP* hbmReturn, DWORD background); +GpStatus WINAPI GdipCreateHICONFromBitmap(GpBitmap *bitmap, HICON *hbmReturn); +GpStatus WINAPI GdipDisposeImage(GpImage *image); +GpStatus WINAPI GdipGetImagePixelFormat(GpImage *image, INT *format); +/* Startup and Shutdown */ +GpStatus WINAPI GdiplusStartup(ULONG_PTR *token, const struct GdiplusStartupInput *input, void *output); VOID WINAPI GdiplusShutdown(ULONG_PTR token); +/* Drawing functions */ +GpStatus WINAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics); +GpStatus WINAPI GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics); +GpStatus WINAPI GdipDeleteGraphics(GpGraphics *graphics); +GpStatus WINAPI GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode smoothingMode); +GpStatus WINAPI GdipCreatePen1(ARGB color, REAL width, GpUnit unit, GpPen **pen); +GpStatus WINAPI GdipDeletePen(GpPen *pen); +GpStatus WINAPI GdipCreateSolidFill(ARGB color, GpBrush **brush); +GpStatus WINAPI GdipDeleteBrush(GpBrush *brush); +GpStatus WINAPI GdipSetSolidFillColor(GpBrush *brush, ARGB color); +GpStatus WINAPI GdipDrawLineI(GpGraphics *graphics, GpPen *pen, INT x1, INT y1, INT x2, INT y2); +GpStatus WINAPI GdipDrawLinesI(GpGraphics *graphics, GpPen *pen, const GpPoint *points, INT count); +GpStatus WINAPI GdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x, INT y, INT width, INT height); +GpStatus WINAPI GdipFillRectangleI(GpGraphics *graphics, GpBrush *brush, INT x, INT y, INT width, INT height); +GpStatus WINAPI GdipDrawArcI(GpGraphics *graphics, GpPen *pen, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle); +GpStatus WINAPI GdipDrawPolygonI(GpGraphics *graphics, GpPen *pen, const GpPoint *points, INT count); +GpStatus WINAPI GdipFillPolygon2I(GpGraphics *graphics, GpBrush *brush, const GpPoint *points, INT count); +GpStatus WINAPI GdipDrawEllipseI(GpGraphics *graphics, GpPen *pen, INT x, INT y, INT width, INT height); +GpStatus WINAPI GdipFillEllipseI(GpGraphics *graphics, GpBrush *brush, INT x, INT y, INT width, INT height); +GpStatus WINAPI GdipFlush(GpGraphics *graphics, GpFlushIntention intention); /* Pixel format information */ #define PixelFormatIndexed 0x00010000 @@ -101,13 +204,37 @@ ULONG_PTR gdiplusToken; #endif +#ifdef AEROGLASS +HRESULT (WINAPI *_DwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS *pMarInset) = 0; +HRESULT (WINAPI *_DwmIsCompositionEnabled)(BOOL *pfEnabled) = 0; +HTHEME (WINAPI *_OpenThemeData)(HWND hwnd, LPCWSTR pszClassList) = 0; +HPAINTBUFFER (WINAPI *_BeginBufferedPaint)(HDC hdcTarget, const RECT *prcTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS *pPaintParams, HDC *phdc) = 0; +HRESULT (WINAPI *_BufferedPaintSetAlpha)(HPAINTBUFFER hBufferedPaint, const RECT *prc, BYTE alpha) = 0; +HRESULT (WINAPI *_DrawThemeTextEx)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwFlags, LPRECT pRect, const DTTOPTS *pOptions) = 0; +HRESULT (WINAPI *_EndBufferedPaint)(HPAINTBUFFER hBufferedPaint, BOOL fUpdateTarget) = 0; +HRESULT (WINAPI *_CloseThemeData)(HTHEME hTheme) = 0; +BOOL _dw_composition = FALSE; +COLORREF _dw_transparencykey = RGB(200,201,202); +HANDLE hdwm = 0; +#endif +/* Aero related but separate functions and handles */ +HRESULT (WINAPI *_SetWindowTheme)(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList) = 0; +HANDLE huxtheme = 0; + +/* Needed for Rich Edit controls */ +HANDLE hrichedit = 0; + /* * MinGW Is missing a bunch of definitions * so #define them here... */ -#if !defined( MIM_MENUDATA ) -# define MIM_MENUDATA 0x00000008 +#if !defined( _tstol ) +#if defined(UNICODE) +# define _tstol _wtol +#else +# define _tstol atol +#endif #endif #if !defined(PBS_MARQUEE) # define PBS_MARQUEE 0x08 @@ -119,7 +246,7 @@ # define LVS_EX_DOUBLEBUFFER 0x10000 #endif -HWND popup = (HWND)NULL, DW_HWND_OBJECT = (HWND)NULL; +HWND popup = (HWND)NULL, DW_HWND_OBJECT = (HWND)NULL, hwndTooltip = (HWND)0; HINSTANCE DWInstance = NULL; @@ -143,7 +270,8 @@ * an alternate temporary directory if TMP is not set, so we get the value * of TEMP and store it here. */ -static char _dw_alternate_temp_dir[MAX_PATH+1]; +static char _dw_alternate_temp_dir[MAX_PATH+1] = {0}; +static char _dw_exec_dir[MAX_PATH+1] = {0}; int main(int argc, char *argv[]); @@ -158,6 +286,10 @@ DWORD _background; DWORD _hPen; DWORD _hBrush; +#ifdef GDIPLUS +DWORD _gpPen; +DWORD _gpBrush; +#endif BYTE _red[] = { 0x00, 0xbb, 0x00, 0xaa, 0x00, 0xbb, 0x00, 0xaa, 0x77, 0xff, 0x00, 0xee, 0x00, 0xff, 0x00, 0xff, 0xaa, 0x00 }; @@ -168,12 +300,12 @@ HBRUSH _colors[18]; -static int screenx, screeny; HFONT _DefaultFont = NULL; #if (defined(BUILD_DLL) || defined(BUILD_HTML)) && !defined(__MINGW32__) LRESULT CALLBACK _browserWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); #endif +LRESULT CALLBACK _colorwndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2); void _resize_notebook_page(HWND handle, int pageid); void _handle_splitbar_resize(HWND hwnd, float percent, int type, int x, int y); int _lookup_icon(HWND handle, HICON hicon, int type); @@ -181,6 +313,22 @@ void _click_default(HWND handle); void _do_resize(Box *thisbox, int x, int y); +/* Internal function to queue a window redraw */ +void _dw_redraw(HWND window, int skip) +{ + static HWND lastwindow = 0; + HWND redraw = lastwindow; + + if(skip && !window) + return; + + lastwindow = window; + if(redraw != lastwindow && redraw) + { + dw_window_redraw(redraw); + } +} + typedef struct _sighandler { struct _sighandler *next; @@ -269,7 +417,7 @@ argv = (char **)malloc(sizeof(char *) * ((*count)+1)); argv[0] = malloc(260); - GetModuleFileName(DWInstance, argv[0], 260); + GetModuleFileNameA(DWInstance, argv[0], 260); argstart = tmp = start; @@ -292,7 +440,7 @@ else if(*tmp == ' ' && !inquotes) { *tmp = 0; - argv[loc] = strdup(argstart); + argv[loc] = _strdup(argstart); /* Push past any white space */ while(*(tmp+1) == ' ') @@ -310,7 +458,7 @@ tmp++; } if(*argstart) - argv[loc] = strdup(argstart); + argv[loc] = _strdup(argstart); } argv[loc+1] = NULL; return argv; @@ -330,6 +478,31 @@ } #endif +#ifdef UNICODE +/* Macro and internal function to convert UTF8 to Unicode wide characters */ +#define UTF8toWide(a) _myUTF8toWide(a, a ? _alloca(MultiByteToWideChar(CP_UTF8, 0, a, -1, NULL, 0) * sizeof(WCHAR)) : NULL) +LPWSTR _myUTF8toWide(char *utf8string, void *outbuf) +{ + LPWSTR retbuf = outbuf; + + if(retbuf) + MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, retbuf, MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, NULL, 0) * sizeof(WCHAR)); + return retbuf; +} +#define WideToUTF8(a) _myWideToUTF8(a, a ? _alloca(WideCharToMultiByte(CP_UTF8, 0, a, -1, NULL, 0, NULL, NULL)) : NULL) +char *_myWideToUTF8(LPWSTR widestring, void *outbuf) +{ + char *retbuf = outbuf; + + if(retbuf) + WideCharToMultiByte(CP_UTF8, 0, widestring, -1, retbuf, WideCharToMultiByte(CP_UTF8, 0, widestring, -1, NULL, 0, NULL, NULL), NULL, NULL); + return retbuf; +} +#else +#define UTF8toWide(a) a +#define WideToUTF8(a) a +#endif + DWORD GetDllVersion(LPCTSTR lpszDllName) { @@ -392,7 +565,7 @@ /* Section for loading files of types besides BMP and ICO and return HBITMAP or HICON */ void *_dw_load_gpbitmap( char *filename ) { - int found_ext = 0,i, wclen = (strlen(filename) + 6) * sizeof(wchar_t); + int i, wclen = (int)(strlen(filename) + 6) * sizeof(wchar_t); char *file = _alloca(strlen(filename) + 6); wchar_t *wfile = _alloca(wclen); void *image; @@ -405,7 +578,7 @@ if ( _access( file, 04 ) == 0 ) { /* Convert to wide format */ - MultiByteToWideChar(CP_ACP, 0, file, strlen(file)+1, wfile, wclen); + MultiByteToWideChar(CP_ACP, 0, file, (int)strlen(file)+1, wfile, wclen); if(!GdipCreateBitmapFromFile(wfile, &image)) return image; } @@ -540,26 +713,34 @@ for(z=0;z<SIGNALMAX;z++) { - if(stricmp(signame, SignalTranslate[z].name) == 0) + if(_stricmp(signame, SignalTranslate[z].name) == 0) return SignalTranslate[z].message; } return 0L; } -/* This function removes and handlers on windows and frees - * the user memory allocated to it. +/* This function removes any handlers on windows and frees + * the user memory and resources allocated to it. */ BOOL CALLBACK _free_window_memory(HWND handle, LPARAM lParam) { ColorInfo *thiscinfo = (ColorInfo *)GetWindowLongPtr(handle, GWLP_USERDATA); HFONT oldfont = (HFONT)SendMessage(handle, WM_GETFONT, 0, 0); HICON oldicon = (HICON)SendMessage(handle, WM_GETICON, 0, 0); - char tmpbuf[100]; - + TCHAR tmpbuf[100] = {0}; + + TOOLINFO ti = { 0 }; + + ti.cbSize = sizeof(TOOLINFO); + ti.hwnd = handle; + ti.hinst = DWInstance; + + SendMessage(hwndTooltip, TTM_DELTOOL, 0, (LPARAM) (LPTOOLINFO) &ti); + GetClassName(handle, tmpbuf, 99); /* Don't try to free memory from an OLE embedded IE */ - if(strncmp(tmpbuf, "Internet Explorer_Server", 25) == 0) + if(_tcsncmp(tmpbuf, TEXT("Internet Explorer_Server"), 25) == 0) return TRUE; /* Delete font, icon and bitmap GDI objects in use */ @@ -568,39 +749,58 @@ if(oldicon) DeleteObject(oldicon); - if(strnicmp(tmpbuf, STATICCLASSNAME, strlen(STATICCLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, STATICCLASSNAME, _tcslen(STATICCLASSNAME)+1)==0) { HBITMAP oldbitmap = (HBITMAP)SendMessage(handle, STM_GETIMAGE, IMAGE_BITMAP, 0); if(oldbitmap) DeleteObject(oldbitmap); } - if(strnicmp(tmpbuf, BUTTONCLASSNAME, strlen(BUTTONCLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, BUTTONCLASSNAME, _tcslen(BUTTONCLASSNAME)+1)==0) { HBITMAP oldbitmap = (HBITMAP)SendMessage(handle, BM_GETIMAGE, IMAGE_BITMAP, 0); + HICON oldicon = (HICON)SendMessage(handle, BM_GETIMAGE, IMAGE_ICON, 0); if(oldbitmap) DeleteObject(oldbitmap); - } - else if(strnicmp(tmpbuf, FRAMECLASSNAME, strlen(FRAMECLASSNAME)+1)==0) + if(oldicon) + DestroyIcon(oldicon); + } +#ifdef TOOLBAR + /* Bitmap Buttons */ + else if(_tcsnicmp(tmpbuf, TOOLBARCLASSNAME, _tcslen(TOOLBARCLASSNAME)+1) == 0) + { + HIMAGELIST imlist = (HIMAGELIST)SendMessage(handle, TB_GETIMAGELIST, 0, 0); + HIMAGELIST dimlist = (HIMAGELIST)SendMessage(handle, TB_GETDISABLEDIMAGELIST, 0, 0); + + SendMessage(handle, TB_SETIMAGELIST, 0, 0); + SendMessage(handle, TB_SETDISABLEDIMAGELIST, 0, 0); + + if(imlist) + ImageList_Destroy(imlist); + if(dimlist) + ImageList_Destroy(dimlist); + } +#endif + else if(_tcsnicmp(tmpbuf, FRAMECLASSNAME, _tcslen(FRAMECLASSNAME)+1)==0) { Box *box = (Box *)thiscinfo; if(box && box->count && box->items) free(box->items); } - else if(strnicmp(tmpbuf, SplitbarClassName, strlen(SplitbarClassName)+1)==0) + else if(_tcsnicmp(tmpbuf, SplitbarClassName, _tcslen(SplitbarClassName)+1)==0) { void *data = dw_window_get_data(handle, "_dw_percent"); if(data) free(data); } - else if(strnicmp(tmpbuf, WC_TREEVIEW, strlen(WC_TREEVIEW)+1)==0) + else if(_tcsnicmp(tmpbuf, WC_TREEVIEW, _tcslen(WC_TREEVIEW)+1)==0) { dw_tree_clear(handle); } - else if(strnicmp(tmpbuf, WC_TABCONTROL, strlen(WC_TABCONTROL)+1)==0) /* Notebook */ + else if(_tcsnicmp(tmpbuf, WC_TABCONTROL, _tcslen(WC_TABCONTROL)+1)==0) /* Notebook */ { NotebookPage **array = (NotebookPage **)dw_window_get_data(handle, "_dw_array"); @@ -621,7 +821,7 @@ free(array); } } - else if(strnicmp(tmpbuf, UPDOWN_CLASS, strlen(UPDOWN_CLASS)+1)==0) + else if(_tcsnicmp(tmpbuf, UPDOWN_CLASS, _tcslen(UPDOWN_CLASS)+1)==0) { /* for spinbuttons, we need to get the spinbutton's "buddy", the text window associated and destroy it */ ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(handle, GWLP_USERDATA); @@ -634,7 +834,8 @@ if(thiscinfo) { - SubclassWindow(handle, thiscinfo->pOldProc); + if(thiscinfo->pOldProc) + SetWindowLongPtr(handle, GWLP_WNDPROC, (LPARAM)(WNDPROC)thiscinfo->pOldProc); /* Delete the brush so as not to leak GDI objects */ if(thiscinfo->hbrush) @@ -701,7 +902,7 @@ */ int _validate_focus(HWND handle) { - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; if(!handle) return 0; @@ -714,31 +915,31 @@ /* These are the window classes which can * obtain input focus. */ - if(strnicmp(tmpbuf, EDITCLASSNAME, strlen(EDITCLASSNAME)+1)==0 || /* Entryfield */ - strnicmp(tmpbuf, BUTTONCLASSNAME, strlen(BUTTONCLASSNAME)+1)==0 || /* Button */ - strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1)==0 || /* Combobox */ - strnicmp(tmpbuf, LISTBOXCLASSNAME, strlen(LISTBOXCLASSNAME)+1)==0 || /* List box */ - strnicmp(tmpbuf, UPDOWN_CLASS, strlen(UPDOWN_CLASS)+1)==0 || /* Spinbutton */ - strnicmp(tmpbuf, TRACKBAR_CLASS, strlen(TRACKBAR_CLASS)+1)==0 || /* Slider */ - strnicmp(tmpbuf, WC_LISTVIEW, strlen(WC_LISTVIEW)+1)== 0 || /* Container */ - strnicmp(tmpbuf, WC_TREEVIEW, strlen(WC_TREEVIEW)+1)== 0) /* Tree */ + if(_tcsnicmp(tmpbuf, EDITCLASSNAME, _tcslen(EDITCLASSNAME)+1)==0 || /* Entryfield */ + _tcsnicmp(tmpbuf, BUTTONCLASSNAME, _tcslen(BUTTONCLASSNAME)+1)==0 || /* Button */ + _tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1)==0 || /* Combobox */ + _tcsnicmp(tmpbuf, LISTBOXCLASSNAME, _tcslen(LISTBOXCLASSNAME)+1)==0 || /* List box */ + _tcsnicmp(tmpbuf, UPDOWN_CLASS, _tcslen(UPDOWN_CLASS)+1)==0 || /* Spinbutton */ + _tcsnicmp(tmpbuf, TRACKBAR_CLASS, _tcslen(TRACKBAR_CLASS)+1)==0 || /* Slider */ + _tcsnicmp(tmpbuf, WC_LISTVIEW, _tcslen(WC_LISTVIEW)+1)== 0 || /* Container */ + _tcsnicmp(tmpbuf, WC_TREEVIEW, _tcslen(WC_TREEVIEW)+1)== 0) /* Tree */ return 1; return 0; } HWND _normalize_handle(HWND handle) { - char tmpbuf[100] = ""; + TCHAR tmpbuf[100] = {0}; GetClassName(handle, tmpbuf, 99); - if(strnicmp(tmpbuf, UPDOWN_CLASS, strlen(UPDOWN_CLASS))==0) /* Spinner */ + if(_tcsnicmp(tmpbuf, UPDOWN_CLASS, _tcslen(UPDOWN_CLASS))==0) /* Spinner */ { ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(handle, GWLP_USERDATA); if(cinfo && cinfo->buddy) return cinfo->buddy; } - if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME))==0) /* Combobox */ + if(_tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME))==0) /* Combobox */ { ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(handle, GWLP_USERDATA); @@ -752,7 +953,7 @@ { int z; static HWND lasthwnd, firsthwnd; - static int finish_searching; + static int finish_searching; /* Start is 2 when we have cycled completely and * need to set the focus to the last widget we found @@ -823,11 +1024,11 @@ } else { - char tmpbuf[100] = ""; + TCHAR tmpbuf[100] = {0}; GetClassName(box->items[z].hwnd, tmpbuf, 99); - if(strncmp(tmpbuf, SplitbarClassName, strlen(SplitbarClassName)+1)==0) + if(_tcsncmp(tmpbuf, SplitbarClassName, _tcslen(SplitbarClassName)+1)==0) { /* Then try the bottom or right box */ HWND mybox = (HWND)dw_window_get_data(box->items[z].hwnd, "_dw_bottomright"); @@ -851,7 +1052,7 @@ return 1; } } - else if(strnicmp(tmpbuf, WC_TABCONTROL, strlen(WC_TABCONTROL))==0) /* Notebook */ + else if(_tcsnicmp(tmpbuf, WC_TABCONTROL, _tcslen(WC_TABCONTROL))==0) /* Notebook */ { NotebookPage **array = (NotebookPage **)dw_window_get_data(box->items[z].hwnd, "_dw_array"); int pageid = TabCtrl_GetCurSel(box->items[z].hwnd); @@ -869,7 +1070,7 @@ } } } - else if(strnicmp(tmpbuf, ScrollClassName, strlen(ScrollClassName))==0) /* Scroll Box */ + else if(_tcsnicmp(tmpbuf, ScrollClassName, _tcslen(ScrollClassName))==0) /* Scroll Box */ { ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(box->items[z].hwnd, GWLP_USERDATA); Box *scrollbox = (Box *)GetWindowLongPtr(cinfo->combo, GWLP_USERDATA); @@ -887,7 +1088,7 @@ { int z; static HWND lasthwnd, firsthwnd; - static int finish_searching; + static int finish_searching; /* Start is 2 when we have cycled completely and * need to set the focus to the last widget we found @@ -958,11 +1159,11 @@ } else { - char tmpbuf[100] = ""; + TCHAR tmpbuf[100] = {0}; GetClassName(box->items[z].hwnd, tmpbuf, 99); - if(strncmp(tmpbuf, SplitbarClassName, strlen(SplitbarClassName)+1)==0) + if(_tcsncmp(tmpbuf, SplitbarClassName, _tcslen(SplitbarClassName)+1)==0) { /* Try the top or left box */ HWND mybox = (HWND)dw_window_get_data(box->items[z].hwnd, "_dw_topleft"); @@ -986,7 +1187,7 @@ return 1; } } - else if(strnicmp(tmpbuf, WC_TABCONTROL, strlen(WC_TABCONTROL))==0) /* Notebook */ + else if(_tcsnicmp(tmpbuf, WC_TABCONTROL, _tcslen(WC_TABCONTROL))==0) /* Notebook */ { NotebookPage **array = (NotebookPage **)dw_window_get_data(box->items[z].hwnd, "_dw_array"); int pageid = TabCtrl_GetCurSel(box->items[z].hwnd); @@ -1004,7 +1205,7 @@ } } } - else if(strnicmp(tmpbuf, ScrollClassName, strlen(ScrollClassName))==0) /* Scroll Box */ + else if(_tcsnicmp(tmpbuf, ScrollClassName, _tcslen(ScrollClassName))==0) /* Scroll Box */ { ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(box->items[z].hwnd, GWLP_USERDATA); Box *scrollbox = (Box *)GetWindowLongPtr(cinfo->combo, GWLP_USERDATA); @@ -1024,14 +1225,14 @@ void _initial_focus(HWND handle) { Box *thisbox; - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; if(!handle) return; GetClassName(handle, tmpbuf, 99); - if(strnicmp(tmpbuf, ClassName, strlen(ClassName))!=0) + if(_tcsnicmp(tmpbuf, ClassName, _tcslen(ClassName)+1)!=0) return; @@ -1051,11 +1252,21 @@ /* Find the toplevel window */ while((box = GetParent(lastbox))) { + /* If it hasn't been packed yet.. */ + if(box == DW_HWND_OBJECT) + return 0; lastbox = box; } if(lastbox) - return lastbox; - return handle; + { + TCHAR tmpbuf[100] = {0}; + + GetClassName(lastbox, tmpbuf, 99); + + if(_tcsncmp(tmpbuf, ClassName, _tcslen(ClassName)+1)==0) + return lastbox; + } + return 0; } /* This function finds the current widget in the @@ -1103,193 +1314,107 @@ _focus_check_box_back(thisbox, handle, 2, 0); } } - /* This function calculates how much space the widgets and boxes require * and does expansion as necessary. */ -int _resize_box(Box *thisbox, int *depth, int x, int y, int *usedx, int *usedy, - int pass, int *usedpadx, int *usedpady) -{ - int z, currentx = 0, currenty = 0; +static void _resize_box(Box *thisbox, int *depth, int x, int y, int pass) +{ + /* Current item position */ + int z, currentx = thisbox->pad, currenty = thisbox->pad; + /* Used x, y and padding maximum values... + * These will be used to find the widest or + * tallest items in a box. + */ int uymax = 0, uxmax = 0; int upymax = 0, upxmax = 0; - /* Used for the SIZEEXPAND */ - int nux = *usedx, nuy = *usedy; - int nupx = *usedpadx, nupy = *usedpady; - - (*usedx) += (thisbox->pad * 2); - (*usedy) += (thisbox->pad * 2); + + /* Reset the box sizes */ + thisbox->minwidth = thisbox->minheight = thisbox->usedpadx = thisbox->usedpady = thisbox->pad * 2; if(thisbox->grouphwnd) { - char *text = dw_window_get_text(thisbox->grouphwnd); - - thisbox->grouppady = 0; - - if(text) - { - dw_font_text_extents_get(thisbox->grouphwnd, 0, text, NULL, &thisbox->grouppady); - dw_free(text); - } - - if(thisbox->grouppady) - thisbox->grouppady += 3; - else - thisbox->grouppady = 6; - - thisbox->grouppadx = 6; - - (*usedx) += thisbox->grouppadx; - (*usedpadx) += thisbox->grouppadx; - (*usedy) += thisbox->grouppady; - (*usedpady) += thisbox->grouppady; - } - + /* Only calculate the size on the first pass... + * use the cached values on second. + */ + if(pass == 1) + { + char *text = dw_window_get_text(thisbox->grouphwnd); + + thisbox->grouppady = 9; + + if(text) + { + if(*text) + dw_font_text_extents_get(thisbox->grouphwnd, 0, text, NULL, &thisbox->grouppady); + dw_free(text); + } + /* If the string height is less than 9... + * set it to 9 anyway since that is the minimum. + */ + if(thisbox->grouppady < 9) + thisbox->grouppady = 9; + + if(thisbox->grouppady) + thisbox->grouppady += 3; + else + thisbox->grouppady = 6; + + thisbox->grouppadx = 6; + } + + thisbox->minwidth += thisbox->grouppadx; + thisbox->usedpadx += thisbox->grouppadx; + thisbox->minheight += thisbox->grouppady; + thisbox->usedpady += thisbox->grouppady; + } + + /* Count up all the space for all items in the box */ for(z=0;z<thisbox->count;z++) { + int itempad, itemwidth, itemheight; + if(thisbox->items[z].type == TYPEBOX) { - int initialx, initialy; Box *tmp = (Box *)GetWindowLongPtr(thisbox->items[z].hwnd, GWLP_USERDATA); - initialx = x - (*usedx); - initialy = y - (*usedy); - if(tmp) { - int newx, newy; - int nux = *usedx, nuy = *usedy; - int upx = *usedpadx + (tmp->pad*2), upy = *usedpady + (tmp->pad*2); - - /* On the second pass we know how big the box needs to be and how - * much space we have, so we can calculate a ratio for the new box. - */ - if(pass == 2) + /* On the first pass calculate the box contents */ + if(pass == 1) { - int deep = *depth + 1; - - _resize_box(tmp, &deep, x, y, &nux, &nuy, 1, &upx, &upy); - - tmp->upx = upx - *usedpadx; - tmp->upy = upy - *usedpady; - - newx = x - nux; - newy = y - nuy; - - tmp->width = thisbox->items[z].width = initialx - newx; - tmp->height = thisbox->items[z].height = initialy - newy; - - tmp->parentxratio = thisbox->xratio; - tmp->parentyratio = thisbox->yratio; - - tmp->parentpad = tmp->pad; - - /* Just in case */ - tmp->xratio = thisbox->xratio; - tmp->yratio = thisbox->yratio; - - if(thisbox->type == DW_VERT) - { - int tmppad = (thisbox->items[z].pad*2)+(tmp->pad*2)+tmp->grouppady; - - if((thisbox->items[z].width - tmppad)!=0) - tmp->xratio = ((float)((thisbox->items[z].width * thisbox->xratio)-tmppad))/((float)(thisbox->items[z].width-tmppad)); - } - else - { - if((thisbox->items[z].width-tmp->upx)!=0) - tmp->xratio = ((float)((thisbox->items[z].width * thisbox->xratio)-tmp->upx))/((float)(thisbox->items[z].width-tmp->upx)); - } - if(thisbox->type == DW_HORZ) - { - int tmppad = (thisbox->items[z].pad*2)+(tmp->pad*2)+tmp->grouppadx; - - if((thisbox->items[z].height-tmppad)!=0) - tmp->yratio = ((float)((thisbox->items[z].height * thisbox->yratio)-tmppad))/((float)(thisbox->items[z].height-tmppad)); - } - else - { - if((thisbox->items[z].height-tmp->upy)!=0) - tmp->yratio = ((float)((thisbox->items[z].height * thisbox->yratio)-tmp->upy))/((float)(thisbox->items[z].height-tmp->upy)); - } - - nux = *usedx; nuy = *usedy; - upx = *usedpadx + (tmp->pad*2); upy = *usedpady + (tmp->pad*2); + (*depth)++; + + /* Save the newly calculated values on the box */ + _resize_box(tmp, depth, x, y, pass); + + /* Duplicate the values in the item list for use below */ + thisbox->items[z].width = tmp->minwidth; + thisbox->items[z].height = tmp->minheight; + + /* If the box has no contents but is expandable... default the size to 1 */ + if(!thisbox->items[z].width && thisbox->items[z].hsize) + thisbox->items[z].width = 1; + if(!thisbox->items[z].height && thisbox->items[z].vsize) + thisbox->items[z].height = 1; + + (*depth)--; } - - (*depth)++; - - _resize_box(tmp, depth, x, y, &nux, &nuy, pass, &upx, &upy); - - (*depth)--; - - newx = x - nux; - newy = y - nuy; - - tmp->minwidth = thisbox->items[z].width = initialx - newx; - tmp->minheight = thisbox->items[z].height = initialy - newy; - } - } - - if(pass > 1 && *depth > 0) - { - if(thisbox->type == DW_VERT) - { - int tmppad = (thisbox->items[z].pad*2)+(thisbox->parentpad*2)+thisbox->grouppadx; - - if((thisbox->minwidth-tmppad) == 0) - thisbox->items[z].xratio = 1.0; - else - thisbox->items[z].xratio = ((float)((thisbox->width * thisbox->parentxratio)-tmppad))/((float)(thisbox->minwidth-tmppad)); - } - else - { - if(thisbox->minwidth-thisbox->upx == 0) - thisbox->items[z].xratio = 1.0; - else - thisbox->items[z].xratio = ((float)((thisbox->width * thisbox->parentxratio)-thisbox->upx))/((float)(thisbox->minwidth-thisbox->upx)); - } - - if(thisbox->type == DW_HORZ) - { - int tmppad = (thisbox->items[z].pad*2)+(thisbox->parentpad*2)+thisbox->grouppady; - - if((thisbox->minheight-tmppad) == 0) - thisbox->items[z].yratio = 1.0; - else - thisbox->items[z].yratio = ((float)((thisbox->height * thisbox->parentyratio)-tmppad))/((float)(thisbox->minheight-tmppad)); - } - else - { - if(thisbox->minheight-thisbox->upy == 0) - thisbox->items[z].yratio = 1.0; - else - thisbox->items[z].yratio = ((float)((thisbox->height * thisbox->parentyratio)-thisbox->upy))/((float)(thisbox->minheight-thisbox->upy)); - } - - if(thisbox->items[z].type == TYPEBOX) - { - Box *tmp = (Box *)GetWindowLongPtr(thisbox->items[z].hwnd, GWLP_USERDATA); - - if(tmp) - { - tmp->parentxratio = thisbox->items[z].xratio; - tmp->parentyratio = thisbox->items[z].yratio; - } - } - } - else - { - thisbox->items[z].xratio = thisbox->xratio; - thisbox->items[z].yratio = thisbox->yratio; - } - + } + } + + /* Precalculate these values, since they will + * be used used repeatedly in the next section. + */ + itempad = thisbox->items[z].pad * 2; + itemwidth = thisbox->items[z].width + itempad; + itemheight = thisbox->items[z].height + itempad; + + /* Calculate the totals and maximums */ if(thisbox->type == DW_VERT) { - int itemwidth = (thisbox->items[z].pad*2) + thisbox->items[z].width; - if(itemwidth > uxmax) uxmax = itemwidth; + if(thisbox->items[z].hsize != SIZEEXPAND) { if(itemwidth > upxmax) @@ -1297,30 +1422,17 @@ } else { - if(thisbox->items[z].pad*2 > upxmax) - upxmax = thisbox->items[z].pad*2; - } + if(itempad > upxmax) + upxmax = itempad; + } + thisbox->minheight += itemheight; + if(thisbox->items[z].vsize != SIZEEXPAND) + thisbox->usedpady += itemheight; + else + thisbox->usedpady += itempad; } else { - if(thisbox->items[z].width == -1) - { - /* figure out how much space this item requires */ - /* thisbox->items[z].width = */ - } - else - { - (*usedx) += thisbox->items[z].width + (thisbox->items[z].pad*2); - if(thisbox->items[z].hsize != SIZEEXPAND) - (*usedpadx) += (thisbox->items[z].pad*2) + thisbox->items[z].width; - else - (*usedpadx) += thisbox->items[z].pad*2; - } - } - if(thisbox->type == DW_HORZ) - { - int itemheight = (thisbox->items[z].pad*2) + thisbox->items[z].height; - if(itemheight > uymax) uymax = itemheight; if(thisbox->items[z].vsize != SIZEEXPAND) @@ -1330,150 +1442,109 @@ } else { - if(thisbox->items[z].pad*2 > upymax) - upymax = thisbox->items[z].pad*2; - } - } - else - { - if(thisbox->items[z].height == -1) - { - /* figure out how much space this item requires */ - /* thisbox->items[z].height = */ - } + if(itempad > upymax) + upymax = itempad; + } + thisbox->minwidth += itemwidth; + if(thisbox->items[z].hsize != SIZEEXPAND) + thisbox->usedpadx += itemwidth; else - { - (*usedy) += thisbox->items[z].height + (thisbox->items[z].pad*2); - if(thisbox->items[z].vsize != SIZEEXPAND) - (*usedpady) += (thisbox->items[z].pad*2) + thisbox->items[z].height; - else - (*usedpady) += thisbox->items[z].pad*2; - } - } - } - - (*usedx) += uxmax; - (*usedy) += uymax; - (*usedpadx) += upxmax; - (*usedpady) += upymax; - - currentx += thisbox->pad; - currenty += thisbox->pad; - + thisbox->usedpadx += itempad; + } + } + + /* Add the maximums which were calculated in the previous loop */ + thisbox->minwidth += uxmax; + thisbox->minheight += uymax; + thisbox->usedpadx += upxmax; + thisbox->usedpady += upymax; + + /* Move the groupbox start past the group border */ if(thisbox->grouphwnd) { currentx += 3; currenty += thisbox->grouppady - 3; } - /* The second pass is for expansion and actual placement. */ + /* The second pass is for actual placement. */ if(pass > 1) { - /* Any SIZEEXPAND items should be set to uxmax/uymax */ - for(z=0;z<thisbox->count;z++) - { - if(thisbox->items[z].hsize == SIZEEXPAND && thisbox->type == DW_VERT) - thisbox->items[z].width = uxmax-(thisbox->items[z].pad*2); - if(thisbox->items[z].vsize == SIZEEXPAND && thisbox->type == DW_HORZ) - thisbox->items[z].height = uymax-(thisbox->items[z].pad*2); - /* Run this code segment again to finalize the sized after setting uxmax/uymax values. */ - if(thisbox->items[z].type == TYPEBOX) - { - Box *tmp = (Box *)GetWindowLongPtr(thisbox->items[z].hwnd, GWLP_USERDATA); - - if(tmp) - { - if(*depth > 0) - { - float calcval; - - if(thisbox->type == DW_VERT) - { - calcval = (float)(tmp->minwidth-((thisbox->items[z].pad*2)+(thisbox->pad*2))); - if(calcval == 0.0) - tmp->xratio = thisbox->xratio; - else - tmp->xratio = ((float)((thisbox->items[z].width * thisbox->xratio)-((thisbox->items[z].pad*2)+(thisbox->pad*2))))/calcval; - tmp->width = thisbox->items[z].width; - } - if(thisbox->type == DW_HORZ) - { - calcval = (float)(tmp->minheight-((thisbox->items[z].pad*2)+(thisbox->pad*2))); - if(calcval == 0.0) - tmp->yratio = thisbox->yratio; - else - tmp->yratio = ((float)((thisbox->items[z].height * thisbox->yratio)-((thisbox->items[z].pad*2)+(thisbox->pad*2))))/calcval; - tmp->height = thisbox->items[z].height; - } - } - - (*depth)++; - - _resize_box(tmp, depth, x, y, &nux, &nuy, 3, &nupx, &nupy); - - (*depth)--; - - } - } - } - for(z=0;z<(thisbox->count);z++) { int height = thisbox->items[z].height; int width = thisbox->items[z].width; - int pad = thisbox->items[z].pad; - HWND handle = thisbox->items[z].hwnd; - int vectorx, vectory; - - /* When upxmax != pad*2 then ratios are incorrect. */ - vectorx = (int)((width*thisbox->items[z].xratio)-width); - vectory = (int)((height*thisbox->items[z].yratio)-height); - - if(width > 0 && height > 0) - { - char tmpbuf[100]; - /* This is a hack to fix rounding of the sizing */ - if(*depth == 0) + int itempad = thisbox->items[z].pad * 2; + int thispad = thisbox->pad * 2; + + /* Calculate the new sizes */ + if(thisbox->items[z].hsize == SIZEEXPAND) + { + if(thisbox->type == DW_HORZ) + { + int expandablex = thisbox->minwidth - thisbox->usedpadx; + + if(expandablex) + width = (int)(((float)width / (float)expandablex) * (float)(x - thisbox->usedpadx)); + } + else + width = x - (itempad + thispad + thisbox->grouppadx); + } + if(thisbox->items[z].vsize == SIZEEXPAND) + { + if(thisbox->type == DW_VERT) { - vectorx++; - vectory++; + int expandabley = thisbox->minheight - thisbox->usedpady; + + if(expandabley) + height = (int)(((float)height / (float)expandabley) * (float)(y - thisbox->usedpady)); } - - /* If this item isn't going to expand... reset the vectors to 0 */ - if(thisbox->items[z].vsize != SIZEEXPAND) - vectory = 0; - if(thisbox->items[z].hsize != SIZEEXPAND) - vectorx = 0; - + else + height = y - (itempad + thispad + thisbox->grouppady); + } + + /* If the calculated size is valid... */ + if(width > 0 && height > 0) + { + int pad = thisbox->items[z].pad; + HWND handle = thisbox->items[z].hwnd; + TCHAR tmpbuf[100] = {0}; + GetClassName(handle, tmpbuf, 99); - if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1)==0) { /* Handle special case Combobox */ MoveWindow(handle, currentx + pad, currenty + pad, - width + vectorx, (height + vectory) + 400, FALSE); + width, height + 400, FALSE); } - else if(strnicmp(tmpbuf, UPDOWN_CLASS, strlen(UPDOWN_CLASS)+1)==0) +#ifdef TOOLBAR + /* Bitmap Buttons */ + else if(_tcsnicmp(tmpbuf, TOOLBARCLASSNAME, _tcslen(TOOLBARCLASSNAME)+1) == 0) + { + SendMessage(handle, TB_SETBUTTONSIZE, 0, MAKELPARAM(width, height)); + + MoveWindow(handle, currentx + pad, currenty + pad, width, height, FALSE); + } +#endif + else if(_tcsnicmp(tmpbuf, UPDOWN_CLASS, _tcslen(UPDOWN_CLASS)+1)==0) { /* Handle special case Spinbutton */ ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(handle, GWLP_USERDATA); - MoveWindow(handle, currentx + pad + ((width + vectorx) - 20), currenty + pad, - 20, height + vectory, FALSE); + MoveWindow(handle, currentx + pad + (width - 20), currenty + pad, + 20, height, FALSE); if(cinfo) { MoveWindow(cinfo->buddy, currentx + pad, currenty + pad, - (width + vectorx) - 20, height + vectory, FALSE); + width - 20, height, FALSE); } } - else if(strncmp(tmpbuf, ScrollClassName, strlen(ScrollClassName)+1)==0) + else if(_tcsncmp(tmpbuf, ScrollClassName, _tcslen(ScrollClassName)+1)==0) { /* Handle special case of scrollbox */ ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(handle, GWLP_USERDATA); - int cx = width + vectorx; - int cy = height + vectory; - int usedx = 0, usedy = 0, usedpadx = 0, usedpady = 0, depth = 0; + int cx, cy, depth = 0; Box *thisbox = (Box *)GetWindowLongPtr(cinfo->combo, GWLP_USERDATA); SCROLLINFO hsi, vsi; RECT rect; @@ -1486,7 +1557,7 @@ GetScrollInfo(handle, SB_VERT, &vsi); /* Position the scrollbox */ - MoveWindow(handle, currentx + pad, currenty + pad, cx, cy, FALSE); + MoveWindow(handle, currentx + pad, currenty + pad, width, height, FALSE); GetClientRect(handle, &rect); cx = rect.right; @@ -1494,32 +1565,32 @@ /* Get the required space for the box */ - _resize_box(thisbox, &depth, cx, cy, &usedx, &usedy, 1, &usedpadx, &usedpady); - - if(cx < usedx) + _resize_box(thisbox, &depth, cx, cy, 1); + + if(cx < thisbox->minwidth) { - cx = usedx; + cx = thisbox->minwidth; } - if(cy < usedy) + if(cy < thisbox->minheight) { - cy = usedy; + cy = thisbox->minheight; } /* Position the scrolled box */ vsi.fMask = hsi.fMask = SIF_POS | SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL; vsi.nMin = hsi.nMin = vsi.nMax = hsi.nMax = 0; - if(rect.bottom < usedy) + if(rect.bottom < thisbox->minheight) { - vsi.nMax = usedy; + vsi.nMax = thisbox->minheight - 1; vsi.nPage = rect.bottom; if(vsi.nPos > vsi.nMax) { vsi.nPos = vsi.nMax; } } - if(rect.right < usedx) + if(rect.right < thisbox->minwidth) { - hsi.nMax = usedx; + hsi.nMax = thisbox->minwidth - 1; hsi.nPage = rect.right; if(hsi.nPos > hsi.nMax) { @@ -1533,21 +1604,19 @@ /* Layout the content of the scrollbox */ _do_resize(thisbox, cx, cy); } - else if(strncmp(tmpbuf, SplitbarClassName, strlen(SplitbarClassName)+1)==0) + else if(_tcsncmp(tmpbuf, SplitbarClassName, _tcslen(SplitbarClassName)+1)==0) { /* Then try the bottom or right box */ float *percent = (float *)dw_window_get_data(handle, "_dw_percent"); int type = (int)dw_window_get_data(handle, "_dw_type"); - int cx = width + vectorx; - int cy = height + vectory; MoveWindow(handle, currentx + pad, currenty + pad, - cx, cy, FALSE); - - if(cx > 0 && cy > 0 && percent) - _handle_splitbar_resize(handle, *percent, type, cx, cy); + width, height, FALSE); + + if(percent && width > 0 && height > 0) + _handle_splitbar_resize(handle, *percent, type, width, height); } - else if(strnicmp(tmpbuf, STATICCLASSNAME, strlen(STATICCLASSNAME)+1)==0) + else if(_tcsnicmp(tmpbuf, STATICCLASSNAME, _tcslen(STATICCLASSNAME)+1)==0) { /* Handle special case Vertically Center static text */ ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(handle, GWLP_USERDATA); @@ -1555,45 +1624,56 @@ if(cinfo && cinfo->vcenter) { /* We are centered so calculate a new position */ - char tmpbuf[1024]; - int textheight, diff, total = height + vectory; - - GetWindowText(handle, tmpbuf, 1023); + TCHAR tmpbuf[1024] = {0}, *thisbuf = tmpbuf; + int textheight, diff, total = height; + + GetWindowText(handle, thisbuf, 1023); /* Figure out how big the text is */ - dw_font_text_extents_get(handle, 0, tmpbuf, 0, &textheight); + dw_font_text_extents_get(handle, 0, WideToUTF8(thisbuf), 0, &textheight); diff = (total - textheight) / 2; MoveWindow(handle, currentx + pad, currenty + pad + diff, - width + vectorx, height + vectory - diff, FALSE); + width, height - diff, FALSE); } else { MoveWindow(handle, currentx + pad, currenty + pad, - width + vectorx, height + vectory, FALSE); + width, height, FALSE); } } else { /* Everything else */ - MoveWindow(handle, currentx + pad, currenty + pad, - width + vectorx, height + vectory, FALSE); + if(*depth) + MoveWindow(handle, currentx + pad, currenty + pad, width, height, FALSE); + else /* FIXME: This is a hack to generate WM_PAINT messages for items on the top-level */ + SetWindowPos(handle, HWND_TOP, currentx + pad, currenty + pad, width, height, 0); + + /* After placing a box... place its components */ if(thisbox->items[z].type == TYPEBOX) { Box *boxinfo = (Box *)GetWindowLongPtr(handle, GWLP_USERDATA); - if(boxinfo && boxinfo->grouphwnd) + if(boxinfo) { - MoveWindow(boxinfo->grouphwnd, 0, 0, - width + vectorx, height + vectory, FALSE); + /* Move the group border into place */ + if(boxinfo->grouphwnd) + { + MoveWindow(boxinfo->grouphwnd, 0, 0, + width, height, FALSE); + } + /* Dive into the box */ + (*depth)++; + _resize_box(boxinfo, depth, width, height, pass); + (*depth)--; } - } } /* Notebook dialog requires additional processing */ - if(strncmp(tmpbuf, WC_TABCONTROL, strlen(WC_TABCONTROL))==0) + if(_tcsncmp(tmpbuf, WC_TABCONTROL, _tcslen(WC_TABCONTROL))==0) { RECT rect; NotebookPage **array = (NotebookPage **)dw_window_get_data(handle, "_dw_array"); @@ -1605,10 +1685,11 @@ TabCtrl_AdjustRect(handle,FALSE,&rect); MoveWindow(array[pageid]->hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom-rect.top, FALSE); + dw_window_redraw(array[pageid]->hwnd); } } /* So does the List View... handle delayed cursoring */ - if(strnicmp(tmpbuf, WC_LISTVIEW, strlen(WC_LISTVIEW)+1)==0 && width + vectorx > 10 && height + vectory > 10) + if(_tcsnicmp(tmpbuf, WC_LISTVIEW, _tcslen(WC_LISTVIEW)+1)==0 && width > 10 && height > 10) { int index = DW_POINTER_TO_INT(dw_window_get_data(handle, "_dw_cursor")); @@ -1616,14 +1697,14 @@ ListView_EnsureVisible(handle, index, TRUE); } + /* Advance the current position in the box */ if(thisbox->type == DW_HORZ) - currentx += width + vectorx + (pad * 2); + currentx += width + (pad * 2); if(thisbox->type == DW_VERT) - currenty += height + vectory + (pad * 2); - } - } - } - return 0; + currenty += height + (pad * 2); + } + } + } } void _do_resize(Box *thisbox, int x, int y) @@ -1632,19 +1713,13 @@ { if(thisbox) { - int usedx = 0, usedy = 0, depth = 0, usedpadx = 0, usedpady = 0; - - _resize_box(thisbox, &depth, x, y, &usedx, &usedy, 1, &usedpadx, &usedpady); - - if(usedx-usedpadx == 0 || usedy-usedpady == 0) - return; - - thisbox->xratio = ((float)(x-usedpadx))/((float)(usedx-usedpadx)); - thisbox->yratio = ((float)(y-usedpady))/((float)(usedy-usedpady)); - - usedpadx = usedpady = usedx = usedy = depth = 0; - - _resize_box(thisbox, &depth, x, y, &usedx, &usedy, 2, &usedpadx, &usedpady); + int depth = 0; + + /* Calculate space requirements */ + _resize_box(thisbox, &depth, x, y, 1); + + /* Finally place all the boxes and controls */ + _resize_box(thisbox, &depth, x, y, 2); } } } @@ -1672,7 +1747,7 @@ /*case SB_PAGEDOWN:*/ case SB_PAGERIGHT: pos = si.nPos + si.nPage; - if(pos > (si.nMax - si.nPage) + 1) + if(pos > (int)(si.nMax - si.nPage) + 1) pos = (si.nMax - si.nPage) + 1; return pos; /*case SB_LINEUP:*/ @@ -1684,7 +1759,7 @@ /*case SB_LINEDOWN:*/ case SB_LINERIGHT: pos = si.nPos + 1; - if(pos > (si.nMax - si.nPage) + 1) + if(pos > (int)(si.nMax - si.nPage) + 1) pos = (si.nMax - si.nPage) + 1; return pos; } @@ -1733,16 +1808,15 @@ int is_checked; sprintf( buffer, "_dw_ischecked%d", id ); is_checked = (int)dw_window_get_data(DW_HWND_OBJECT, buffer); - is_checked = (is_checked) ? 0 : 1; - dw_menu_item_set_check( window, id, is_checked ); + is_checked = (is_checked) ? DW_MIS_UNCHECKED : DW_MIS_CHECKED; + dw_menu_item_set_state( window, id, is_checked ); } } /* The main window procedure for Dynamic Windows, all the resizing code is done here. */ -BOOL CALLBACK _wndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) +LRESULT CALLBACK _wndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) { int result = -1, taskbar = FALSE; - static int command_active = 0; SignalHandler *tmp = Root; void (*windowfunc)(PVOID); ULONG origmsg = msg; @@ -1764,9 +1838,6 @@ if (result == -1) { - /* Avoid infinite recursion */ - command_active = 1; - /* Find any callbacks for this function */ while (tmp) { @@ -1905,13 +1976,19 @@ break; case WM_CHAR: { - int (*keypressfunc)(HWND, char, int, int, void *) = tmp->signalfunction; + int (*keypressfunc)(HWND, char, int, int, void *, char *) = tmp->signalfunction; if(hWnd == tmp->window || _toplevel_window(hWnd) == tmp->window) { int special = 0; - char ch = 0; - + char *utf8 = NULL, ch[2] = {0}; +#ifdef UNICODE + WCHAR uc[2] = { 0 }; + + uc[0] = (WCHAR)mp1; + utf8 = WideToUTF8(uc); +#endif + if(GetAsyncKeyState(VK_SHIFT) & 0x8000) special |= KC_SHIFT; if(GetAsyncKeyState(VK_CONTROL) & 0x8000) @@ -1920,9 +1997,9 @@ special |= KC_ALT; if(origmsg == WM_CHAR && mp1 < 128) - ch = (char)mp1; - - result = keypressfunc(tmp->window, ch, mp1, special, tmp->data); + ch[0] = (char)mp1; + + result = keypressfunc(tmp->window, ch[0], (int)mp1, special, tmp->data, utf8 ? utf8 : ch); tmp = NULL; } } @@ -1964,11 +2041,11 @@ { NMTREEVIEW FAR *tem=(NMTREEVIEW FAR *)mp2; NMLISTVIEW FAR *lem=(NMLISTVIEW FAR *)mp2; - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; GetClassName(tem->hdr.hwndFrom, tmpbuf, 99); - if(strnicmp(tmpbuf, WC_TREEVIEW, strlen(WC_TREEVIEW))==0) + if(_tcsnicmp(tmpbuf, WC_TREEVIEW, _tcslen(WC_TREEVIEW))==0) { if(tem->hdr.code == TVN_SELCHANGED && tmp->message == TVN_SELCHANGED) { @@ -2005,7 +2082,7 @@ if(tmp->window == tem->hdr.hwndFrom) { int (*containercontextfunc)(HWND, char *, int, int, void *, void *) = tmp->signalfunction; - HTREEITEM hti, last; + HTREEITEM hti; TVITEM tvi; TVHITTESTINFO thi; void **ptrs = NULL; @@ -2018,7 +2095,6 @@ MapWindowPoints(HWND_DESKTOP, tmp->window, &thi.pt, 1); - last = TreeView_GetSelection(tmp->window); hti = TreeView_HitTest(tmp->window, &thi); if(hti) @@ -2036,7 +2112,7 @@ } } } - else if(strnicmp(tmpbuf, WC_LISTVIEW, strlen(WC_LISTVIEW)+1)==0) + else if(_tcsnicmp(tmpbuf, WC_LISTVIEW, _tcslen(WC_LISTVIEW)+1)==0) { if((lem->hdr.code == LVN_ITEMCHANGED && (lem->uChanged & LVIF_STATE)) && tmp->message == TVN_SELCHANGED) { @@ -2090,6 +2166,16 @@ tmp = NULL; } } + else if(tmp->message == WM_VSCROLL) + { + NMUPDOWN FAR *tem=(NMUPDOWN FAR *)mp2; + if(tmp->window == tem->hdr.hwndFrom && tem->hdr.code == UDN_DELTAPOS) + { + int (*valuechangefunc)(HWND, int, void *) = tmp->signalfunction; + result = valuechangefunc(tmp->window, tem->iPos + tem->iDelta, tmp->data); + tmp = NULL; + } + } } break; case WM_COMMAND: @@ -2111,6 +2197,21 @@ tmp = NULL; } } +#ifdef TOOLBAR + else if (message == BN_CLICKED && tmp->message == WM_COMMAND && tmp->window == (HWND)mp2) + { + TCHAR tmpbuf[100] = {0}; + + GetClassName((HWND)mp2, tmpbuf, 99); + + /* Make sure this isn't a button, because it will have already been handled */ + if (_tcsnicmp(tmpbuf, BUTTONCLASSNAME, _tcslen(BUTTONCLASSNAME)+1) != 0) + { + result = clickfunc(tmp->window, tmp->data); + tmp = NULL; + } + } +#endif else if (tmp->id && passthru == tmp->id) { HMENU hwndmenu = GetMenu(hWnd), menuowner = _menu_owner((HMENU)tmp->window); @@ -2136,7 +2237,7 @@ case WM_HSCROLL: case WM_VSCROLL: { - char tmpbuf[100] = ""; + TCHAR tmpbuf[100] = {0}; HWND handle = (HWND)mp2; int (*valuechangefunc)(HWND, int, void *) = tmp->signalfunction; @@ -2145,7 +2246,7 @@ GetClassName(hWnd, tmpbuf, 99); } - if (strnicmp(tmpbuf, TRACKBAR_CLASS, strlen(TRACKBAR_CLASS)+1)==0) + if (_tcsnicmp(tmpbuf, TRACKBAR_CLASS, _tcslen(TRACKBAR_CLASS)+1)==0) { if (handle == tmp->window) @@ -2161,7 +2262,7 @@ tmp = NULL; } } - else if(strnicmp(tmpbuf, SCROLLBARCLASSNAME, strlen(SCROLLBARCLASSNAME)+1)==0) + else if(_tcsnicmp(tmpbuf, SCROLLBARCLASSNAME, _tcslen(SCROLLBARCLASSNAME)+1)==0) { if(handle == tmp->window) { @@ -2184,12 +2285,47 @@ if(tmp) tmp = tmp->next; } - command_active = 0; } /* Now that any handlers are done... do normal processing */ switch( msg ) { +#ifdef AEROGLASS + case WM_DWMCOMPOSITIONCHANGED: + { + LONG_PTR styleex = GetWindowLongPtr(hWnd, GWL_EXSTYLE); + + if(_DwmIsCompositionEnabled) + _DwmIsCompositionEnabled(&_dw_composition); + + /* If we are no longer compositing... disable layered windows */ + if(!_dw_composition && (styleex & WS_EX_LAYERED)) + { + MARGINS mar = {0}; + + SetWindowLongPtr(hWnd, GWL_EXSTYLE, styleex & ~WS_EX_LAYERED); + if(_DwmExtendFrameIntoClientArea) + _DwmExtendFrameIntoClientArea(hWnd, &mar); + } + } + break; +#endif +#ifdef AEROGLASS1 + case WM_ERASEBKGND: + if(_dw_composition && (GetWindowLongPtr(hWnd, GWL_EXSTYLE) & WS_EX_LAYERED)) + { + static HBRUSH hbrush = 0; + RECT rect; + + if(!hbrush) + hbrush = CreateSolidBrush(_dw_transparencykey); + + GetClientRect(hWnd, &rect); + FillRect((HDC)mp1, &rect, hbrush); + return TRUE; + } + break; +#endif case WM_PAINT: { PAINTSTRUCT ps; @@ -2260,7 +2396,6 @@ case WM_VSCROLL: { HWND handle = (HWND)mp2; - char tmpbuf[100]; int bar = (origmsg == WM_HSCROLL) ? SB_HORZ : SB_VERT; if(dw_window_get_data(handle, "_dw_scrollbar")) @@ -2272,8 +2407,10 @@ } else { + TCHAR tmpbuf[100] = {0}; + GetClassName( hWnd, tmpbuf, 99 ); - if ( strnicmp(tmpbuf, FRAMECLASSNAME, strlen(FRAMECLASSNAME)+1 ) == 0 ) + if ( _tcsnicmp(tmpbuf, FRAMECLASSNAME, _tcslen(FRAMECLASSNAME)+1 ) == 0 ) { _HandleScroller(hWnd, bar, (int)HIWORD(mp1), (int)LOWORD(mp1)); } @@ -2318,74 +2455,16 @@ case WM_CTLCOLORMSGBOX: case WM_CTLCOLORSCROLLBAR: case WM_CTLCOLORDLG: - { - ColorInfo *thiscinfo = (ColorInfo *)GetWindowLongPtr((HWND)mp2, GWLP_USERDATA); - if(thiscinfo && thiscinfo->fore != -1 && thiscinfo->back != -1) - { - /* Handle foreground */ - if(thiscinfo->fore > -1 && thiscinfo->fore < 18) - { - if(thiscinfo->fore != DW_CLR_DEFAULT) - { - SetTextColor((HDC)mp1, RGB(_red[thiscinfo->fore], - _green[thiscinfo->fore], - _blue[thiscinfo->fore])); - } - } - else if((thiscinfo->fore & DW_RGB_COLOR) == DW_RGB_COLOR) - { - SetTextColor((HDC)mp1, RGB(DW_RED_VALUE(thiscinfo->fore), - DW_GREEN_VALUE(thiscinfo->fore), - DW_BLUE_VALUE(thiscinfo->fore))); - } - /* Handle background */ - if(thiscinfo->back > -1 && thiscinfo->back < 18) - { - if(thiscinfo->back == DW_CLR_DEFAULT) - { - HBRUSH hbr = GetSysColorBrush(COLOR_3DFACE); - - SelectObject((HDC)mp1, hbr); - return (LONG)hbr; - } - else - { - SetBkColor((HDC)mp1, RGB(_red[thiscinfo->back], - _green[thiscinfo->back], - _blue[thiscinfo->back])); - if(thiscinfo->hbrush) - DeleteObject(thiscinfo->hbrush); - thiscinfo->hbrush = CreateSolidBrush(RGB(_red[thiscinfo->back], - _green[thiscinfo->back], - _blue[thiscinfo->back])); - SelectObject((HDC)mp1, thiscinfo->hbrush); - } - return (LONG)thiscinfo->hbrush; - } - else if((thiscinfo->back & DW_RGB_COLOR) == DW_RGB_COLOR) - { - SetBkColor((HDC)mp1, RGB(DW_RED_VALUE(thiscinfo->back), - DW_GREEN_VALUE(thiscinfo->back), - DW_BLUE_VALUE(thiscinfo->back))); - if(thiscinfo->hbrush) - DeleteObject(thiscinfo->hbrush); - thiscinfo->hbrush = CreateSolidBrush(RGB(DW_RED_VALUE(thiscinfo->back), - DW_GREEN_VALUE(thiscinfo->back), - DW_BLUE_VALUE(thiscinfo->back))); - SelectObject((HDC)mp1, thiscinfo->hbrush); - return (LONG)thiscinfo->hbrush; - } - } - - } - break; + return _colorwndproc(hWnd, msg, mp1, mp2); } if(result != -1) + { + /* Make sure any queued redraws are handled */ + _dw_redraw(0, FALSE); + /* Then finally return */ return result; - else - { - return DefWindowProc(hWnd, msg, mp1, mp2); - } + } + return DefWindowProc(hWnd, msg, mp1, mp2); } VOID CALLBACK _TimerProc(HWND hwnd, UINT msg, UINT_PTR idEvent, DWORD dwTime) @@ -2393,7 +2472,7 @@ _wndproc(hwnd, msg, (WPARAM)idEvent, 0); } -BOOL CALLBACK _framewndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) +LRESULT CALLBACK _framewndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) { switch( msg ) { @@ -2408,16 +2487,22 @@ case WM_MOUSEMOVE: _wndproc(hWnd, msg, mp1, mp2); break; -#if 0 - case WM_ERASEBKGND: - { - ColorInfo *thiscinfo = (ColorInfo *)GetWindowLongPtr(hWnd, GWLP_USERDATA); - - if(thiscinfo && thiscinfo->fore != -1 && thiscinfo->back != -1) - return FALSE; +#ifdef AEROGLASS + case WM_ERASEBKGND: + if(_dw_composition && (GetWindowLongPtr(_toplevel_window(hWnd), GWL_EXSTYLE) & WS_EX_LAYERED)) + { + static HBRUSH hbrush = 0; + RECT rect; + + if(!hbrush) + hbrush = CreateSolidBrush(_dw_transparencykey); + + GetClientRect(hWnd, &rect); + FillRect((HDC)mp1, &rect, hbrush); + return TRUE; } break; -#endif +#endif case WM_PAINT: { ColorInfo *thiscinfo = (ColorInfo *)GetWindowLongPtr(hWnd, GWLP_USERDATA); @@ -2491,9 +2576,9 @@ return DefWindowProc(hWnd, msg, mp1, mp2); } -BOOL CALLBACK _rendwndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) -{ - BOOL rcode = TRUE; +LRESULT CALLBACK _rendwndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) +{ + LRESULT rcode = TRUE; switch( msg ) { @@ -2529,7 +2614,7 @@ return rcode; } -BOOL CALLBACK _spinnerwndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) +LRESULT CALLBACK _spinnerwndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) { ColorInfo *cinfo; @@ -2547,7 +2632,7 @@ case WM_RBUTTONDOWN: case WM_KEYDOWN: { - BOOL ret; + LRESULT ret; if(!cinfo || !cinfo->pOldProc) ret = DefWindowProc(hWnd, msg, mp1, mp2); @@ -2569,7 +2654,7 @@ case WM_RBUTTONUP: case WM_KEYUP: { - BOOL ret; + LRESULT ret; if(!cinfo || !cinfo->pOldProc) ret = DefWindowProc(hWnd, msg, mp1, mp2); @@ -2591,7 +2676,7 @@ { if(mp1 == 100) { - BOOL ret; + LRESULT ret; if(cinfo && cinfo->buddy) SendMessage(cinfo->buddy, WM_USER+10, 0, 0); @@ -2614,12 +2699,12 @@ { if(cinfo->buddy) { - char tempbuf[100] = ""; + TCHAR tempbuf[100] = { 0 }; long position; GetWindowText(cinfo->buddy, tempbuf, 99); - position = atol(tempbuf); + position = _tstol(tempbuf); SendMessage(hWnd, UDM_SETPOS32, 0, (LPARAM)position); } @@ -2635,14 +2720,14 @@ void _click_default(HWND handle) { - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; GetClassName(handle, tmpbuf, 99); /* These are the window classes which can * obtain input focus. */ - if (strnicmp(tmpbuf, BUTTONCLASSNAME, strlen(BUTTONCLASSNAME))==0) + if (_tcsnicmp(tmpbuf, BUTTONCLASSNAME, _tcslen(BUTTONCLASSNAME)+1)==0) { /* Generate click on default item */ SignalHandler *tmp = Root; @@ -2668,17 +2753,18 @@ SetFocus(handle); } -BOOL CALLBACK _colorwndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) +/* Subclass function that will handle setting colors on controls */ +LRESULT CALLBACK _colorwndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) { ColorInfo *cinfo; - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; WNDPROC pOldProc = 0; - int ret = -1; + LRESULT ret = -1; cinfo = (ColorInfo *)GetWindowLongPtr(hWnd, GWLP_USERDATA); GetClassName(hWnd, tmpbuf, 99); - if(strcmp(tmpbuf, FRAMECLASSNAME) == 0) + if(_tcsncmp(tmpbuf, FRAMECLASSNAME, _tcslen(FRAMECLASSNAME)+1) == 0) cinfo = &(((Box *)cinfo)->cinfo); if ( msg == WM_MOUSEMOVE || msg == WM_USER+2 ) @@ -2804,7 +2890,7 @@ val = (long)SendMessage(cinfo->buddy, UDM_GETPOS32, 0, 0); - sprintf(tmpbuf, "%ld", val); + _sntprintf(tmpbuf, 99, TEXT("%ld"), val); SetWindowText(hWnd, tmpbuf); } } @@ -2820,64 +2906,74 @@ ColorInfo *thiscinfo = (ColorInfo *)GetWindowLongPtr((HWND)mp2, GWLP_USERDATA); if(thiscinfo && thiscinfo->fore != -1 && thiscinfo->back != -1) { + int thisback = thiscinfo->back; + /* Handle foreground */ - if(thiscinfo->fore > -1 && thiscinfo->fore < 18) + if(thiscinfo->fore != DW_CLR_DEFAULT) { - if(thiscinfo->fore != DW_CLR_DEFAULT) - { - SetTextColor((HDC)mp1, RGB(_red[thiscinfo->fore], - _green[thiscinfo->fore], - _blue[thiscinfo->fore])); - } - } - else if((thiscinfo->fore & DW_RGB_COLOR) == DW_RGB_COLOR) - { - SetTextColor((HDC)mp1, RGB(DW_RED_VALUE(thiscinfo->fore), - DW_GREEN_VALUE(thiscinfo->fore), - DW_BLUE_VALUE(thiscinfo->fore))); + int fore = _internal_color(thiscinfo->fore); + + SetTextColor((HDC)mp1, RGB(DW_RED_VALUE(fore), + DW_GREEN_VALUE(fore), + DW_BLUE_VALUE(fore))); } /* Handle background */ - if(thiscinfo->back > -1 && thiscinfo->back < 18) + if(thiscinfo->back == DW_RGB_TRANSPARENT) + { + ColorInfo *parentcinfo = (ColorInfo *)GetWindowLongPtr(hWnd, GWLP_USERDATA); + + if(parentcinfo && parentcinfo->back != -1) + thisback = parentcinfo->back; + } + if(thisback == DW_CLR_DEFAULT) { - if(thiscinfo->back == DW_CLR_DEFAULT) - { - HBRUSH hbr = GetSysColorBrush(COLOR_3DFACE); - - SetBkColor((HDC)mp1, GetSysColor(COLOR_3DFACE)); - - - SelectObject((HDC)mp1, hbr); - return (LONG)hbr; - } - else - { - SetBkColor((HDC)mp1, RGB(_red[thiscinfo->back], - _green[thiscinfo->back], - _blue[thiscinfo->back])); - if(thiscinfo->hbrush) - DeleteObject(thiscinfo->hbrush); - thiscinfo->hbrush = CreateSolidBrush(RGB(_red[thiscinfo->back], - _green[thiscinfo->back], - _blue[thiscinfo->back])); - SelectObject((HDC)mp1, thiscinfo->hbrush); - } - return (LONG)thiscinfo->hbrush; + HBRUSH hbr = GetSysColorBrush(COLOR_3DFACE); + + SetBkColor((HDC)mp1, GetSysColor(COLOR_3DFACE)); + + SelectObject((HDC)mp1, hbr); + return (LONG)hbr; } - else if((thiscinfo->back & DW_RGB_COLOR) == DW_RGB_COLOR) + else if(thisback != -1 && thisback != DW_RGB_TRANSPARENT) { - SetBkColor((HDC)mp1, RGB(DW_RED_VALUE(thiscinfo->back), - DW_GREEN_VALUE(thiscinfo->back), - DW_BLUE_VALUE(thiscinfo->back))); + int back = _internal_color(thisback); + + SetBkColor((HDC)mp1, RGB(DW_RED_VALUE(back), + DW_GREEN_VALUE(back), + DW_BLUE_VALUE(back))); if(thiscinfo->hbrush) DeleteObject(thiscinfo->hbrush); - thiscinfo->hbrush = CreateSolidBrush(RGB(DW_RED_VALUE(thiscinfo->back), - DW_GREEN_VALUE(thiscinfo->back), - DW_BLUE_VALUE(thiscinfo->back))); + thiscinfo->hbrush = CreateSolidBrush(RGB(DW_RED_VALUE(back), + DW_GREEN_VALUE(back), + DW_BLUE_VALUE(back))); SelectObject((HDC)mp1, thiscinfo->hbrush); return (LONG)thiscinfo->hbrush; } } - + #ifdef AEROGLASS + switch(msg) + { + case WM_CTLCOLORSTATIC: + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + { + + if((_dw_composition && GetWindowLongPtr(_toplevel_window(hWnd), GWL_EXSTYLE) & WS_EX_LAYERED) && + (!thiscinfo || (thiscinfo && (thiscinfo->back == -1 || thiscinfo->back == DW_RGB_TRANSPARENT)))) + { + if(!(msg == WM_CTLCOLORSTATIC && SendMessage((HWND)mp2, STM_GETIMAGE, IMAGE_BITMAP, 0))) + { + SetBkColor((HDC)mp1, _dw_transparencykey); + if(thiscinfo->hbrush) + DeleteObject(thiscinfo->hbrush); + thiscinfo->hbrush = CreateSolidBrush(_dw_transparencykey); + SelectObject((HDC)mp1, thiscinfo->hbrush); + return (LONG)thiscinfo->hbrush; + } + } + } + } +#endif } break; } @@ -2893,7 +2989,7 @@ } /* Window procedure for container/listview */ -BOOL CALLBACK _containerwndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) +LRESULT CALLBACK _containerwndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) { ContainerInfo *continfo = (ContainerInfo *)GetWindowLongPtr(hWnd, GWLP_USERDATA); @@ -2907,7 +3003,7 @@ case WM_PAINT: if(continfo->cinfo.pOldProc && (continfo->even != DW_RGB_TRANSPARENT || continfo->odd != DW_RGB_TRANSPARENT)) { - RECT rectUpd, rectDestin, rect; + RECT rectUpd, rectDestin, rectThis, *rect = &rectThis; int iItems, iTop, i; COLORREF c; @@ -2925,7 +3021,7 @@ for(i=iTop; i<=(iTop+iItems+1); i++) { /* if row rectangle intersects update rectangle then it requires re-drawing */ - if(ListView_GetItemRect(hWnd, i, &rect, LVIR_BOUNDS) && IntersectRect(&rectDestin, &rectUpd, &rect)) + if(ListView_GetItemRect(hWnd, i, rect, LVIR_BOUNDS) && IntersectRect(&rectDestin, &rectUpd, rect)) { /* change text background colour accordingly */ c = (i % 2) ? continfo->odd : continfo->even; @@ -3047,10 +3143,10 @@ return CallWindowProc(continfo->cinfo.pOldProc, hWnd, msg, mp1, mp2); } -BOOL CALLBACK _treewndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) +LRESULT CALLBACK _treewndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) { ContainerInfo *cinfo; - int ret = -1; + LRESULT ret = -1; cinfo = (ContainerInfo *)GetWindowLongPtr(hWnd, GWLP_USERDATA); @@ -3110,23 +3206,20 @@ void _handle_splitbar_resize(HWND hwnd, float percent, int type, int x, int y) { - HWND handle1, handle2; - Box *tmp; + HWND handle1 = (HWND)dw_window_get_data(hwnd, "_dw_topleft"); + HWND handle2 = (HWND)dw_window_get_data(hwnd, "_dw_bottomright"); + + ShowWindow(handle1, SW_HIDE); + ShowWindow(handle2, SW_HIDE); if(type == DW_HORZ) { int newx = x; float ratio = (float)percent/(float)100.0; - - handle1 = (HWND)dw_window_get_data(hwnd, "_dw_topleft"); - handle2 = (HWND)dw_window_get_data(hwnd, "_dw_bottomright"); - tmp = (Box *)GetWindowLongPtr(handle1, GWLP_USERDATA); + Box *tmp = (Box *)GetWindowLongPtr(handle1, GWLP_USERDATA); newx = (int)((float)newx * ratio) - (SPLITBAR_WIDTH/2); - ShowWindow(handle1, SW_HIDE); - ShowWindow(handle2, SW_HIDE); - MoveWindow(handle1, 0, 0, newx, y, FALSE); _do_resize(tmp, newx - 1, y - 1); @@ -3143,24 +3236,18 @@ { int newy = y; float ratio = (float)(100.0-percent)/(float)100.0; - - handle1 = (HWND)dw_window_get_data(hwnd, "_dw_bottomright"); - handle2 = (HWND)dw_window_get_data(hwnd, "_dw_topleft"); - tmp = (Box *)GetWindowLongPtr(handle1, GWLP_USERDATA); + Box *tmp = (Box *)GetWindowLongPtr(handle2, GWLP_USERDATA); newy = (int)((float)newy * ratio) - (SPLITBAR_WIDTH/2); - ShowWindow(handle1, SW_HIDE); - ShowWindow(handle2, SW_HIDE); - - MoveWindow(handle1, 0, y - newy, x, newy, FALSE); + MoveWindow(handle2, 0, y - newy, x, newy, FALSE); _do_resize(tmp, x - 1, newy - 1); - tmp = (Box *)GetWindowLongPtr(handle2, GWLP_USERDATA); + tmp = (Box *)GetWindowLongPtr(handle1, GWLP_USERDATA); newy = y - newy - SPLITBAR_WIDTH; - MoveWindow(handle2, 0, 0, x, newy, FALSE); + MoveWindow(handle1, 0, 0, x, newy, FALSE); _do_resize(tmp, x - 1, newy - 1); dw_window_set_data(hwnd, "_dw_start", (void *)newy); @@ -3171,7 +3258,7 @@ } /* This handles any activity on the scrollbox */ -BOOL CALLBACK _scrollwndproc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2) +LRESULT CALLBACK _scrollwndproc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2) { switch (msg) { @@ -3211,7 +3298,7 @@ /*case SB_PAGEUP:*/ case SB_PAGERIGHT: si->nPos = si->nPos + si->nPage; - if(si->nPos > (si->nMax - si->nPage) + 1) + if(si->nPos > (int)(si->nMax - si->nPage) + 1) si->nPos = (si->nMax - si->nPage) + 1; break; /*case SB_LINEDOWN:*/ @@ -3223,7 +3310,7 @@ /*case SB_LINEUP:*/ case SB_LINERIGHT: si->nPos = si->nPos + 1; - if(si->nPos > (si->nMax - si->nPage) + 1) + if(si->nPos > (int)(si->nMax - si->nPage) + 1) si->nPos = (si->nMax - si->nPage) + 1; break; } @@ -3239,7 +3326,7 @@ } /* This handles any activity on the splitbars (sizers) */ -BOOL CALLBACK _splitwndproc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2) +LRESULT CALLBACK _splitwndproc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2) { switch (msg) { @@ -3318,13 +3405,13 @@ { start = point.x - rect.left; if(width - SPLITBAR_WIDTH > 1 && start < width - SPLITBAR_WIDTH) - *percent = ((float)start / (float)(width - SPLITBAR_WIDTH)) * 100.0; + *percent = ((float)start / (float)(width - SPLITBAR_WIDTH)) * (float)100.0; } else { start = point.y - rect.top; if(height - SPLITBAR_WIDTH > 1 && start < height - SPLITBAR_WIDTH) - *percent = ((float)start / (float)(height - SPLITBAR_WIDTH)) * 100.0; + *percent = ((float)start / (float)(height - SPLITBAR_WIDTH)) * (float)100.0; } _handle_splitbar_resize(hwnd, *percent, type, width, height); } @@ -3338,7 +3425,7 @@ } /* This handles drawing the status text areas */ -BOOL CALLBACK _statuswndproc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2) +LRESULT CALLBACK _statuswndproc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2) { switch (msg) { @@ -3359,7 +3446,7 @@ PAINTSTRUCT ps; RECT rc; unsigned long cx, cy; - char tempbuf[1024] = ""; + TCHAR tempbuf[1025] = { 0 }; ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(hwnd, GWLP_USERDATA); HFONT hfont = _acquire_font(hwnd, cinfo ? cinfo->fontname : NULL); HFONT oldfont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0); @@ -3385,18 +3472,159 @@ return DefWindowProc(hwnd, msg, mp1, mp2); } +#ifdef AEROGLASS +/* Window procedure to handle drawing themed text when in composited mode */ +LRESULT CALLBACK _staticwndproc(HWND hwnd, ULONG msg, WPARAM mp1, LPARAM mp2) +{ + ColorInfo *parentcinfo, *cinfo = (ColorInfo *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + WNDPROC pOldProc; + + if (!cinfo) + return DefWindowProc(hwnd, msg, mp1, mp2); + + /* Need the parent to do the check completely */ + parentcinfo = (ColorInfo *)GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA); + + /* If we don't require themed drawing */ + if(((cinfo->back != -1 && cinfo->back != DW_RGB_TRANSPARENT) || (parentcinfo && parentcinfo->back != -1)) + || !_dw_composition || !(GetWindowLongPtr(_toplevel_window(hwnd), GWL_EXSTYLE) & WS_EX_LAYERED)) + return _colorwndproc(hwnd, msg, mp1, mp2); + + pOldProc = cinfo->pOldProc; + + switch(msg) + { + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + + if(hdc) + { + /* Figure out how to draw */ + HDC hdcPaint = NULL; + RECT rcClient; + LONG_PTR dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE); + LONG_PTR dwStyleEx = GetWindowLongPtr(hwnd, GWL_EXSTYLE); + HTHEME hTheme = _OpenThemeData(NULL, L"ControlPanelStyle"); + + GetClientRect(hwnd, &rcClient); + + if(hTheme) + { + /* Create an in memory image to draw to */ + HPAINTBUFFER hBufferedPaint = _BeginBufferedPaint(hdc, &rcClient, BPBF_TOPDOWNDIB, NULL, &hdcPaint); + + if(hdcPaint) + { + LONG_PTR dwStaticStyle = dwStyle & 0x1F; + HFONT hFontOld = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0); + int iLen = GetWindowTextLength(hwnd), fore = _internal_color(cinfo->fore); + DTTOPTS DttOpts = { sizeof(DTTOPTS) }; + static HBRUSH hbrush = 0; + + /* Make sure we have a transparency brush */ + if(!hbrush) + hbrush = CreateSolidBrush(_dw_transparencykey); + + /* Fill the background with the transparency color */ + FillRect(hdcPaint, &rcClient, hbrush); + _BufferedPaintSetAlpha(hBufferedPaint, &ps.rcPaint, 0x00); + + /* Setup how we will draw the text */ + DttOpts.dwFlags = DTT_COMPOSITED | DTT_GLOWSIZE | DTT_TEXTCOLOR; + DttOpts.crText = cinfo->fore == -1 ? RGB(255, 255, 255) : RGB(DW_RED_VALUE(fore), DW_GREEN_VALUE(fore), DW_BLUE_VALUE(fore)); + DttOpts.iGlowSize = 12; + + SetBkMode(hdcPaint, TRANSPARENT); + + if(hFontOld) + hFontOld = (HFONT)SelectObject(hdcPaint, hFontOld); + + /* Make sure there is text to draw */ + if(iLen) + { + LPWSTR szText = (LPWSTR)_alloca(sizeof(WCHAR)*(iLen+5)); + + if(szText) + { + iLen = GetWindowTextW(hwnd, szText, iLen+5); + if(iLen) + { + DWORD dwFlags = DT_WORDBREAK; + + switch (dwStaticStyle) + { + case SS_CENTER: + dwFlags |= DT_CENTER; + break; + case SS_RIGHT: + dwFlags |= DT_RIGHT; + break; + case SS_LEFTNOWORDWRAP: + dwFlags &= ~DT_WORDBREAK; + break; + } + + if(dwStyle & SS_CENTERIMAGE) + { + dwFlags |= DT_VCENTER; + dwFlags &= ~DT_WORDBREAK; + } + + + if(dwStyle & SS_ENDELLIPSIS) + dwFlags |= DT_END_ELLIPSIS|DT_MODIFYSTRING; + else if(dwStyle & SS_PATHELLIPSIS) + dwFlags |= DT_PATH_ELLIPSIS|DT_MODIFYSTRING; + else if(dwStyle & SS_WORDELLIPSIS) + dwFlags |= DT_WORD_ELLIPSIS|DT_MODIFYSTRING; + + if (dwStyleEx&WS_EX_RIGHT) + dwFlags |= DT_RIGHT; + + if(dwStyle & SS_NOPREFIX) + dwFlags |= DT_NOPREFIX; + + /* Draw the text! */ + _DrawThemeTextEx(hTheme, hdcPaint, 0, 0, + szText, -1, dwFlags, &rcClient, &DttOpts); + } + } + } + + /* Cleanup */ + if (hFontOld) + SelectObject(hdcPaint, hFontOld); + _EndBufferedPaint(hBufferedPaint, TRUE); + } + _CloseThemeData(hTheme); + } + } + + EndPaint(hwnd, &ps); + return TRUE; + } + break; + } + + if ( !pOldProc ) + return DefWindowProc(hwnd, msg, mp1, mp2); + return CallWindowProc(pOldProc, hwnd, msg, mp1, mp2); +} +#endif + /* Function: _BtProc * Abstract: Subclass procedure for buttons */ -BOOL CALLBACK _BtProc(HWND hwnd, ULONG msg, WPARAM mp1, LPARAM mp2) -{ - BubbleButton *bubble; +LRESULT CALLBACK _BtProc(HWND hwnd, ULONG msg, WPARAM mp1, LPARAM mp2) +{ + ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(hwnd, GWLP_USERDATA); WNDPROC pOldProc; - - bubble = (BubbleButton *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - - if ( !bubble ) + int retval = -1; + + if ( !cinfo ) return DefWindowProc(hwnd, msg, mp1, mp2); /* We must save a pointer to the old @@ -3404,7 +3632,7 @@ * handler attached here destroys this * window it will then be invalid. */ - pOldProc = bubble->pOldProc; + pOldProc = cinfo->pOldProc; switch(msg) { @@ -3415,8 +3643,7 @@ case WM_CTLCOLORMSGBOX: case WM_CTLCOLORSCROLLBAR: case WM_CTLCOLORDLG: - _wndproc(hwnd, msg, mp1, mp2); - break; + return _colorwndproc(hwnd, msg, mp1, mp2); case WM_SETFOCUS: _wndproc(hwnd, msg, mp1, mp2); break; @@ -3434,12 +3661,14 @@ /* Make sure it's the right window, and the right ID */ if(tmp->window == hwnd) { - if(bubble->checkbox) + int checkbox = DW_POINTER_TO_INT(dw_window_get_data(hwnd, "_dw_checkbox")); + + if(checkbox) in_checkbox_handler = 1; - clickfunc(tmp->window, tmp->data); - - if(bubble->checkbox) + retval = clickfunc(tmp->window, tmp->data); + + if(checkbox) in_checkbox_handler = 0; tmp = NULL; } @@ -3468,7 +3697,7 @@ /* Make sure it's the right window, and the right ID */ if(tmp->window == hwnd) { - clickfunc(tmp->window, tmp->data); + retval = clickfunc(tmp->window, tmp->data); tmp = NULL; } } @@ -3494,6 +3723,9 @@ break; } + /* Make sure windows are up-to-date */ + if(retval != -1) + _dw_redraw(0, FALSE); if ( !pOldProc ) return DefWindowProc(hwnd, msg, mp1, mp2); return CallWindowProc(pOldProc, hwnd, msg, mp1, mp2); @@ -3528,29 +3760,25 @@ void _create_tooltip(HWND handle, char *text) { - /* Create a tooltip. */ - HWND hwndTT = CreateWindowEx(WS_EX_TOPMOST, - TOOLTIPS_CLASS, NULL, - WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - handle, NULL, DWInstance,NULL); TOOLINFO ti = { 0 }; - - SetWindowPos(hwndTT, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - - /* Set up "tool" information. - * In this case, the "tool" is the entire parent window. - */ + ti.cbSize = sizeof(TOOLINFO); - ti.uFlags = TTF_SUBCLASS; ti.hwnd = handle; ti.hinst = DWInstance; - ti.lpszText = text; - GetClientRect(handle, &ti.rect); - - /* Associate the tooltip with the "tool" window. */ - SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti); + + SendMessage(hwndTooltip, TTM_DELTOOL, 0, (LPARAM) (LPTOOLINFO) &ti); + if(text) + { + /* Set up "tool" information. + * In this case, the "tool" is the entire parent window. + */ + ti.uFlags = TTF_SUBCLASS; + ti.lpszText = UTF8toWide(text); + ti.rect.right = ti.rect.bottom = 2000; + + /* Associate the tooltip with the "tool" window. */ + SendMessage(hwndTooltip, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti); + } } #ifndef GDIPLUS @@ -3582,17 +3810,17 @@ } if ( stricmp( file + len - 4, ".ico" ) == 0 ) { - *icon = LoadImage(NULL, file, IMAGE_ICON, 0, 0, LR_LOADFROMFILE); + *icon = LoadImage(NULL, UTF8toWide(file), IMAGE_ICON, 0, 0, LR_LOADFROMFILE); windowtype = BS_ICON; } else if ( stricmp( file + len - 4, ".bmp" ) == 0 ) { - *hbitmap = (HBITMAP)LoadImage(NULL, file, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); + *hbitmap = (HBITMAP)LoadImage(NULL, UTF8toWide(file), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); windowtype = BS_BITMAP; } else if ( stricmp( file + len - 4, ".png" ) == 0 ) { - *hbitmap = (HBITMAP)LoadImage(NULL, file, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); + *hbitmap = (HBITMAP)LoadImage(NULL, UTF8toWide(file), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); windowtype = BS_BITMAP; } free(file); @@ -3603,7 +3831,7 @@ strcat(file, ".ico"); if (access(file, 04) == 0) { - *icon = LoadImage(NULL, file, IMAGE_ICON, 0, 0, LR_LOADFROMFILE); + *icon = LoadImage(NULL, UTF8toWide(file), IMAGE_ICON, 0, 0, LR_LOADFROMFILE); windowtype = BS_ICON; } else @@ -3612,7 +3840,7 @@ strcat(file, ".bmp"); if (access(file, 04) == 0) { - *hbitmap = (HBITMAP)LoadImage(NULL, file, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); + *hbitmap = (HBITMAP)LoadImage(NULL, UTF8toWide(file), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); windowtype = BS_BITMAP; } } @@ -3627,6 +3855,16 @@ { COLORREF foreground = RGB(128,128,128); COLORREF background = DW_RGB_TRANSPARENT; +#ifdef GDIPLUS + ARGB gpfore = MAKEARGB(255, 128, 128, 128); + GpBrush *brush; + GpPen *pen; + + GdipCreatePen1(gpfore, 1.0, UnitPixel, &pen); + TlsSetValue(_gpPen, (LPVOID)pen); + GdipCreateSolidFill(gpfore, &brush); + TlsSetValue(_gpBrush, (LPVOID)brush); +#endif TlsSetValue(_foreground, (LPVOID)foreground); TlsSetValue(_background, (LPVOID)background); TlsSetValue(_hPen, CreatePen(PS_SOLID, 1, foreground)); @@ -3649,12 +3887,31 @@ struct GdiplusStartupInput si; #endif + /* Setup the private data directory */ + if(argc > 0 && argv[0]) + { + char *pos = strrchr(argv[0], '\\'); + + /* Just to be safe try the unix style */ + if(!pos) + pos = strrchr(argv[0], '/'); + + if(pos) + strncpy(_dw_exec_dir, argv[0], (size_t)(pos - argv[0])); + } + /* If that failed... just get the current directory */ + if(!_dw_exec_dir[0]) + GetCurrentDirectoryA(MAX_PATH, _dw_exec_dir); + /* Initialize our thread local storage */ _foreground = TlsAlloc(); _background = TlsAlloc(); _hPen = TlsAlloc(); _hBrush = TlsAlloc(); - _init_thread(); +#ifdef GDIPLUS + _gpPen = TlsAlloc(); + _gpBrush = TlsAlloc(); +#endif icc.dwSize = sizeof(INITCOMMONCONTROLSEX); icc.dwICC = ICC_WIN95_CLASSES|ICC_DATE_CLASSES; @@ -3712,6 +3969,19 @@ RegisterClass(&wc); + /* Register a status bar control */ + memset(&wc, 0, sizeof(WNDCLASS)); + wc.style = CS_DBLCLKS; + wc.lpfnWndProc = (WNDPROC)_statuswndproc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 32; + wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_3DFACE); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.lpszMenuName = NULL; + wc.lpszClassName = StatusbarClassName; + + RegisterClass(&wc); + #if (defined(BUILD_DLL) || defined(BUILD_HTML)) && !defined(__MINGW32__) /* Register HTML renderer class */ memset(&wc, 0, sizeof(WNDCLASS)); @@ -3748,7 +4018,7 @@ * packed into their correct parent. */ - DW_HWND_OBJECT = CreateWindow(ObjectClassName, "", 0, 0, 0, + DW_HWND_OBJECT = CreateWindow(ObjectClassName, TEXT("HWND_OBJECT"), 0, 0, 0, 0, 0, HWND_DESKTOP, NULL, DWInstance, NULL); if(!DW_HWND_OBJECT) @@ -3757,6 +4027,12 @@ exit(1); } + /* Create a tooltip. */ + hwndTooltip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, DW_HWND_OBJECT, NULL, DWInstance,NULL); + + SetWindowPos(hwndTooltip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + /* Create empty box data */ SetWindowLongPtr(DW_HWND_OBJECT, GWLP_USERDATA, (LONG_PTR)calloc(sizeof(Box), 1)); @@ -3781,13 +4057,6 @@ { strncpy( _dw_alternate_temp_dir, alttmpdir, MAX_PATH ); } - /* - * Get screen size. Used to make calls to dw_screen_width() - * and dw_screen-height() quicker, but to alos limit the - * default size of windows. - */ - screenx = GetSystemMetrics(SM_CXSCREEN); - screeny = GetSystemMetrics(SM_CYSCREEN); #ifdef GDIPLUS /* Setup GDI+ */ @@ -3797,9 +4066,43 @@ si.SuppressExternalCodecs = FALSE; GdiplusStartup(&gdiplusToken, &si, NULL); #endif + + /* GDI+ Needs to be initialized before calling _init_thread(); */ + _init_thread(); + + if((huxtheme = LoadLibrary(TEXT("uxtheme")))) + _SetWindowTheme = (HRESULT (WINAPI *)(HWND, LPCWSTR, LPCWSTR ))GetProcAddress(huxtheme, "SetWindowTheme"); +#ifdef AEROGLASS + /* Attempt to load the Desktop Window Manager and Theme library */ + if(huxtheme && (hdwm = LoadLibrary(TEXT("dwmapi")))) + { + _DwmExtendFrameIntoClientArea = (HRESULT (WINAPI *)(HWND, const MARGINS *))GetProcAddress(hdwm, "DwmExtendFrameIntoClientArea"); + if((_DwmIsCompositionEnabled = (HRESULT (WINAPI *)(BOOL *))GetProcAddress(hdwm, "DwmIsCompositionEnabled"))) + _DwmIsCompositionEnabled(&_dw_composition); + _OpenThemeData = (HTHEME (WINAPI *)(HWND, LPCWSTR))GetProcAddress(huxtheme, "OpenThemeData"); + _BeginBufferedPaint = (HPAINTBUFFER (WINAPI *)(HDC, const RECT *, BP_BUFFERFORMAT, BP_PAINTPARAMS *, HDC *))GetProcAddress(huxtheme, "BeginBufferedPaint"); + _BufferedPaintSetAlpha = (HRESULT (WINAPI *)(HPAINTBUFFER, const RECT *, BYTE))GetProcAddress(huxtheme, "BufferedPaintSetAlpha"); + _DrawThemeTextEx = (HRESULT (WINAPI *)(HTHEME, HDC, int, int, LPCWSTR, int, DWORD, LPRECT, const DTTOPTS *))GetProcAddress(huxtheme, "DrawThemeTextEx"); + _EndBufferedPaint = (HRESULT (WINAPI *)(HPAINTBUFFER, BOOL))GetProcAddress(huxtheme, "EndBufferedPaint"); + _CloseThemeData = (HRESULT (WINAPI *)(HTHEME))GetProcAddress(huxtheme, "CloseThemeData"); + } + /* In case of error close the library if needed */ + else if(hdwm) + { + FreeLibrary(hdwm); + hdwm = 0; + } +#endif +#ifdef RICHEDIT + /* Attempt to load rich edit library */ + if(!(hrichedit = LoadLibrary("riched20"))) + hrichedit = LoadLibrary("riched32"); +#endif return 0; } +static int _dw_main_running = FALSE; + /* * Runs a message loop for Dynamic Windows. */ @@ -3808,8 +4111,14 @@ MSG msg; _dwtid = dw_thread_id(); - - while(GetMessage(&msg, NULL, 0, 0)) + /* Make sure any queued redraws are handled */ + _dw_redraw(0, FALSE); + + /* Set the running flag to TRUE */ + _dw_main_running = TRUE; + + /* Run the loop until the flag is unset... or error */ + while(_dw_main_running && GetMessage(&msg, NULL, 0, 0)) { if(msg.hwnd == NULL && msg.message == WM_TIMER) _wndproc(msg.hwnd, msg.message, msg.wParam, msg.lParam); @@ -3822,6 +4131,14 @@ } /* + * Causes running dw_main() to return. + */ +void API dw_main_quit(void) +{ + _dw_main_running = FALSE; +} + +/* * Runs a message loop for Dynamic Windows, for a period of milliseconds. * Parameters: * milliseconds: Number of milliseconds to run the loop for. @@ -3952,13 +4269,13 @@ void API dw_debug(char *format, ...) { va_list args; - char outbuf[1025] = {0}; + char outbuf[1025] = {0}, *thisbuf = outbuf; va_start(args, format); vsnprintf(outbuf, 1024, format, args); va_end(args); - OutputDebugString(outbuf); + OutputDebugString(UTF8toWide(thisbuf)); } /* @@ -3971,14 +4288,14 @@ int API dw_messagebox(char *title, int flags, char *format, ...) { va_list args; - char outbuf[1024]; + char outbuf[1025] = { 0 }, *thisbuf = outbuf; int rc; va_start(args, format); vsnprintf(outbuf, 1024, format, args); va_end(args); - rc = MessageBox(HWND_DESKTOP, outbuf, title, flags); + rc = MessageBox(HWND_DESKTOP, UTF8toWide(thisbuf), UTF8toWide(title), flags); if(rc == IDOK) return DW_MB_RETURN_OK; else if(rc == IDYES) @@ -4027,7 +4344,16 @@ */ int API dw_window_show(HWND handle) { - int rc = ShowWindow(handle, SW_SHOW); + int rc; + RECT rect; + + GetClientRect(handle, &rect); + + /* If the client area is 0x0 then call the autosize routine */ + if((rect.bottom - rect.top) == 0 || (rect.right - rect.left) == 0) + dw_window_set_size(handle, 0, 0); + + rc = ShowWindow(handle, SW_SHOW); SetFocus(handle); _initial_focus(handle); return rc; @@ -4050,49 +4376,33 @@ */ int API dw_window_destroy(HWND handle) { - HWND parent = GetParent(handle); - Box *thisbox = (Box *)GetWindowLongPtr(parent, GWLP_USERDATA); - HMENU menu = GetMenu(handle); - + HWND parent; + HMENU menu; + + /* Handle special case for menu handle */ + if(handle < (HWND)65536) + { + char buffer[31] = {0}; + ULONG id = (ULONG)handle; + + _snprintf(buffer, 30, "_dw_id%ld", id); + menu = (HMENU)dw_window_get_data(DW_HWND_OBJECT, buffer); + + if(menu && IsMenu(menu)) + return dw_menu_delete_item((HMENUI)menu, id); + return DW_ERROR_UNKNOWN; + } + + parent = GetParent(handle); + menu = GetMenu(handle); + if(menu) _free_menu_data(menu); /* If it is a desktop window let WM_DESTROY handle it */ if(parent != HWND_DESKTOP) { - /* If the parent box has items... - * try to remove it from the layout - */ - if(thisbox && thisbox->count) - { - int z, index = -1; - Item *tmpitem, *thisitem = thisbox->items; - - for(z=0;z<thisbox->count;z++) - { - if(thisitem[z].hwnd == handle) - index = z; - } - - if(index == -1) - return 0; - - tmpitem = malloc(sizeof(Item)*(thisbox->count-1)); - - /* Copy all but the current entry to the new list */ - for(z=0;z<index;z++) - { - tmpitem[z] = thisitem[z]; - } - for(z=index+1;z<thisbox->count;z++) - { - tmpitem[z-1] = thisitem[z]; - } - - thisbox->items = tmpitem; - free(thisitem); - thisbox->count--; - } + dw_box_unpack(handle); _free_window_memory(handle, 0); EnumChildWindows(handle, _free_window_memory, 0); } @@ -4120,21 +4430,6 @@ } } -int instring(char *text, char *buffer) -{ - int z, len = strlen(text), buflen = strlen(buffer); - - if(buflen > len) - { - for(z=0;z<=(buflen-len);z++) - { - if(memcmp(text, &buffer[z], len) == 0) - return z; - } - } - return 0; -} - /* * Changes a window's parent to newparent. * Parameters: @@ -4148,20 +4443,19 @@ LOGFONT _get_logfont(HDC hdc, char *fontname) { - int Italic, Bold; - char *myFontName; - int z, size = 9; + char *Italic, *Bold, *myFontName = strchr(fontname, '.'); + int size = atoi(fontname); LOGFONT lf = {0}; - for(z=0;z<strlen(fontname);z++) - { - if(fontname[z]=='.') - break; - } - size = atoi(fontname); - lf.lfHeight = -MulDiv(size, GetDeviceCaps(hdc, LOGPIXELSY), 72); - Italic = instring(" Italic", &fontname[z+1]); - Bold = instring(" Bold", &fontname[z+1]); + /* If we found a '.' use the location after the . */ + if(myFontName) + myFontName = _strdup(++myFontName); + else /* Otherwise use the whole fontname and default size of 9 */ + myFontName = _strdup(fontname); + + lf.lfHeight = -MulDiv(size ? size : 9, GetDeviceCaps(hdc, LOGPIXELSY), 72); + Italic = strstr(myFontName, " Italic"); + Bold = strstr(myFontName, " Bold"); lf.lfWidth = 0; lf.lfEscapement = 0; lf.lfOrientation = 0; @@ -4174,15 +4468,11 @@ lf.lfClipPrecision = 0; lf.lfQuality = DEFAULT_QUALITY; lf.lfPitchAndFamily = DEFAULT_PITCH | FW_DONTCARE; - /* - * remove any font modifiers - */ - myFontName = strdup(&fontname[z+1]); if(Italic) - myFontName[Italic] = 0; + *Italic = 0; if(Bold) - myFontName[Bold] = 0; - strncpy(lf.lfFaceName, myFontName, sizeof(lf.lfFaceName)-1); + *Bold = 0; + _tcsncpy(lf.lfFaceName, UTF8toWide(myFontName), (sizeof(lf.lfFaceName)/sizeof(TCHAR))-1); free(myFontName); return lf; } @@ -4242,6 +4532,324 @@ } } +/* Internal function to return a pointer to an item struct + * with information about the packing information regarding object. + */ +Item *_box_item(HWND handle) +{ + HWND parent = GetParent(handle); + Box *thisbox = (Box *)GetWindowLongPtr(parent, GWLP_USERDATA); + + /* If it is a desktop window let WM_DESTROY handle it */ + if(parent != HWND_DESKTOP) + { + if(thisbox && thisbox->count) + { + int z; + Item *thisitem = thisbox->items; + + for(z=0;z<thisbox->count;z++) + { + if(thisitem[z].hwnd == handle) + return &thisitem[z]; + } + } + } + return NULL; +} + +/* Internal function to calculate the widget's required size.. + * These are the general rules for widget sizes: + * + * Render/Unspecified: 1x1 + * Scrolled(Container,Tree,MLE): Guessed size clamped to min and max in dw.h + * Entryfield/Combobox/Spinbutton: 150x(maxfontheight) + * Spinbutton: 50x(maxfontheight) + * Text/Status: (textwidth)x(textheight) + * Ranged: 100x14 or 14x100 for vertical. + * Buttons/Bitmaps: Size of text or image and border. + */ +void _control_size(HWND handle, int *width, int *height) +{ + int thiswidth = 1, thisheight = 1, extrawidth = 0, extraheight = 0; + char *buf = dw_window_get_text(handle); + TCHAR tmpbuf[100] = {0}; + static char testtext[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + HBITMAP hbm = 0; + HICON hic = 0; + ICONINFO ii = {0}; + + GetClassName(handle, tmpbuf, 99); + + /* If we have a string... + * calculate the size with the current font. + */ + if(buf) + { + if(*buf) + dw_font_text_extents_get(handle, NULL, buf, &thiswidth, &thisheight); + dw_free(buf); + } + + /* Attempt to get icon from classes that can have them */ + if(_tcsnicmp(tmpbuf, STATICCLASSNAME, _tcslen(STATICCLASSNAME)+1) == 0) + hic = (HICON)SendMessage(handle, STM_GETIMAGE, IMAGE_ICON, 0); + else if(_tcsnicmp(tmpbuf, BUTTONCLASSNAME, _tcslen(BUTTONCLASSNAME)+1) == 0) + hic = (HICON)SendMessage(handle, BM_GETIMAGE, IMAGE_ICON, 0); + + /* If we got an icon, pull out the internal bitmap */ + if(hic) + { + if(GetIconInfo(hic, &ii)) + hbm = ii.hbmMask ? ii.hbmMask : ii.hbmColor; + } + + /* If we weren't able to get the bitmap from the icon... */ + if(!hbm) + { + /* Attempt to get bitmap from classes that can have them */ + if(_tcsnicmp(tmpbuf, STATICCLASSNAME, _tcslen(STATICCLASSNAME)+1) == 0) + hbm = (HBITMAP)SendMessage(handle, STM_GETIMAGE, IMAGE_BITMAP, 0); + else if(_tcsnicmp(tmpbuf, BUTTONCLASSNAME, _tcslen(BUTTONCLASSNAME)+1) == 0) + hbm = (HBITMAP)SendMessage(handle, BM_GETIMAGE, IMAGE_BITMAP, 0); + } + + /* If we got an image... set the sizes appropriately */ + if(hbm) + { + BITMAP bmi = { 0 }; + + GetObject(hbm, sizeof(BITMAP), &bmi); + thiswidth = bmi.bmWidth; + thisheight = bmi.bmHeight; + } + + /* Combobox */ + if(_tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1) == 0) + { + dw_font_text_extents_get(handle, NULL, testtext, NULL, &thisheight); + thiswidth = 150; + extraheight = 4; + if(thisheight < 18) + thisheight = 18; + } + /* Ranged: Percent, Slider, Scrollbar */ + else if(_tcsnicmp(tmpbuf, PROGRESS_CLASS, _tcslen(PROGRESS_CLASS)+1) == 0 || + _tcsnicmp(tmpbuf, TRACKBAR_CLASS, _tcslen(TRACKBAR_CLASS)+1) == 0 || + _tcsnicmp(tmpbuf, SCROLLBARCLASSNAME, _tcslen(SCROLLBARCLASSNAME)+1) == 0) + { + if(_tcsnicmp(tmpbuf, SCROLLBARCLASSNAME, _tcslen(SCROLLBARCLASSNAME)+1) == 0 && + GetWindowLong(handle, GWL_STYLE) & SBS_VERT) + { + /* Vertical */ + thiswidth = GetSystemMetrics(SM_CXVSCROLL); + thisheight = 100; + } + else + { + /* Horizontal */ + thiswidth = 100; + thisheight = GetSystemMetrics(SM_CYHSCROLL); + } + } + /* Spinbuttons */ + else if(_tcsnicmp(tmpbuf, UPDOWN_CLASS, _tcslen(UPDOWN_CLASS)+1) == 0) + { + dw_font_text_extents_get(handle, NULL, testtext, NULL, &thisheight); + thiswidth = 50; + extraheight = 6; + } +#ifdef TOOLBAR + /* Bitmap Buttons */ + else if(_tcsnicmp(tmpbuf, TOOLBARCLASSNAME, _tcslen(TOOLBARCLASSNAME)+1) == 0) + { + HIMAGELIST imlist = (HIMAGELIST)SendMessage(handle, TB_GETIMAGELIST, 0, 0); + int minsize = 24; + + if(imlist) + ImageList_GetIconSize(imlist, &thiswidth, &thisheight); + + /* If we are flat the size can be smaller */ + if(GetWindowLong(handle, GWL_STYLE) & TBSTYLE_FLAT) + minsize = 20; + else + { + thiswidth += 4; + thisheight += 4; + } + + if(thiswidth < minsize) + thiswidth = minsize; + if(thisheight < minsize) + thisheight = minsize; + } +#endif + /* Listbox */ + else if(_tcsnicmp(tmpbuf, LISTBOXCLASSNAME, _tcslen(LISTBOXCLASSNAME)+1) == 0) + { + char buf[1025] = {0}; + int x, count = dw_listbox_count(handle); + int basicwidth = thiswidth = GetSystemMetrics(SM_CXVSCROLL) + 8; + + thisheight = 8; + + for(x=0;x<count;x++) + { + int height, width = 0; + + dw_listbox_get_text(handle, x, buf, 1024); + + if(strlen(buf)) + dw_font_text_extents_get(handle, NULL, buf, &width, &height); + else + dw_font_text_extents_get(handle, NULL, testtext, NULL, &height); + + width += basicwidth; + + if(width > thiswidth) + thiswidth = width > _DW_SCROLLED_MAX_WIDTH ? _DW_SCROLLED_MAX_WIDTH : width; + thisheight += height; + } + + if(thiswidth < _DW_SCROLLED_MIN_WIDTH) + thiswidth = _DW_SCROLLED_MIN_WIDTH; + if(thisheight < _DW_SCROLLED_MIN_HEIGHT) + thisheight = _DW_SCROLLED_MIN_HEIGHT; + if(thisheight > _DW_SCROLLED_MAX_HEIGHT) + thisheight = _DW_SCROLLED_MAX_HEIGHT; + } + /* Entryfields and MLE */ + else if(_tcsnicmp(tmpbuf, EDITCLASSNAME, _tcslen(EDITCLASSNAME)+1) == 0 || + _tcsnicmp(tmpbuf, RICHEDIT_CLASS, _tcslen(RICHEDIT_CLASS)+1) == 0) + { + LONG style = GetWindowLong(handle, GWL_STYLE); + if((style & ES_MULTILINE)) + { + unsigned long bytes; + int height, width; + char *buf, *ptr; + int basicwidth; + + if(style & ES_AUTOHSCROLL) + thisheight = GetSystemMetrics(SM_CYHSCROLL) + 8; + else + thisheight = 8; + basicwidth = thiswidth = GetSystemMetrics(SM_CXVSCROLL) + 8; + + dw_mle_get_size(handle, &bytes, NULL); + + ptr = buf = _alloca(bytes + 2); + dw_mle_export(handle, buf, 0, (int)bytes); + buf[bytes] = 0; + strcat(buf, "\n"); + + /* MLE */ + while((ptr = strstr(buf, "\n"))) + { + ptr[0] = 0; + width = 0; + if(strlen(buf)) + dw_font_text_extents_get(handle, NULL, buf, &width, &height); + else + dw_font_text_extents_get(handle, NULL, testtext, NULL, &height); + + width += basicwidth; + + if(!(style & ES_AUTOHSCROLL) && width > _DW_SCROLLED_MAX_WIDTH) + { + thiswidth = _DW_SCROLLED_MAX_WIDTH; + thisheight += height * (width / _DW_SCROLLED_MAX_WIDTH); + } + else + { + if(width > thiswidth) + thiswidth = width > _DW_SCROLLED_MAX_WIDTH ? _DW_SCROLLED_MAX_WIDTH : width; + } + thisheight += height; + buf = &ptr[1]; + } + + if(thiswidth < _DW_SCROLLED_MIN_WIDTH) + thiswidth = _DW_SCROLLED_MIN_WIDTH; + if(thisheight < _DW_SCROLLED_MIN_HEIGHT) + thisheight = _DW_SCROLLED_MIN_HEIGHT; + if(thisheight > _DW_SCROLLED_MAX_HEIGHT) + thisheight = _DW_SCROLLED_MAX_HEIGHT; + } + else + { + /* Entryfield */ + dw_font_text_extents_get(handle, NULL, testtext, NULL, &thisheight); + thiswidth = 150; + extraheight = 6; + } + } + /* Container */ + else if(_tcsnicmp(tmpbuf, WC_LISTVIEW, _tcslen(WC_LISTVIEW)+1)== 0) + { + DWORD result = ListView_ApproximateViewRect(handle, _DW_SCROLLED_MAX_WIDTH, _DW_SCROLLED_MAX_HEIGHT, -1); + + thiswidth = LOWORD(result); + thisheight = HIWORD(result); + + if(thiswidth > _DW_SCROLLED_MAX_WIDTH) + thiswidth = _DW_SCROLLED_MAX_WIDTH; + if(thiswidth < _DW_SCROLLED_MIN_WIDTH) + thiswidth = _DW_SCROLLED_MIN_WIDTH; + if(thisheight < _DW_SCROLLED_MIN_HEIGHT) + thisheight = _DW_SCROLLED_MIN_HEIGHT; + if(thisheight > _DW_SCROLLED_MAX_HEIGHT) + thisheight = _DW_SCROLLED_MAX_HEIGHT; + } + /* Tree */ + else if(_tcsnicmp(tmpbuf, WC_TREEVIEW, _tcslen(WC_TREEVIEW)+1)== 0) + { + thiswidth = (int)((_DW_SCROLLED_MAX_WIDTH + _DW_SCROLLED_MIN_WIDTH)/2); + thisheight = (int)((_DW_SCROLLED_MAX_HEIGHT + _DW_SCROLLED_MIN_HEIGHT)/2); + } + /* Buttons */ + else if(_tcsnicmp(tmpbuf, BUTTONCLASSNAME, _tcslen(BUTTONCLASSNAME)+1) == 0) + { + ULONG style = GetWindowLong(handle, GWL_STYLE); + + /* Bitmap buttons */ + if(hbm) + { + extrawidth = 5; + extraheight = 5; + } + /* Checkbox or radio button */ + else if(style & BS_AUTOCHECKBOX || style & BS_AUTORADIOBUTTON) + { + extrawidth = 24; + extraheight = 4; + } + /* Text buttons */ + else + { + extrawidth = 8; + extraheight = 8; + } + } + else if(_tcsnicmp(tmpbuf, StatusbarClassName, _tcslen(StatusbarClassName)+1) == 0) + { + extrawidth = 4; + extraheight = 2; + } + + /* Set the requested sizes */ + if(width) + *width = thiswidth + extrawidth; + if(height) + *height = thisheight + extraheight; + + /* Free temporary bitmaps */ + if(ii.hbmColor) + DeleteObject(ii.hbmColor); + if(ii.hbmMask); + DeleteObject(ii.hbmMask); +} + /* * Sets the font used by a specified window (widget) handle. * Parameters: @@ -4252,12 +4860,12 @@ { HFONT hfont, oldfont; ColorInfo *cinfo; - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; cinfo = (ColorInfo *)GetWindowLongPtr(handle, GWLP_USERDATA); GetClassName(handle, tmpbuf, 99); - if ( strnicmp( tmpbuf, FRAMECLASSNAME, strlen(FRAMECLASSNAME)+1) == 0 ) + if ( _tcsnicmp( tmpbuf, FRAMECLASSNAME, _tcslen(FRAMECLASSNAME)+1) == 0 ) { /* groupbox */ Box *thisbox = (Box *)GetWindowLongPtr( handle, GWLP_USERDATA ); @@ -4271,7 +4879,7 @@ oldfont = (HFONT)SendMessage(handle, WM_GETFONT, 0, 0); hfont = _acquire_font(handle, fontname); - if (fontname) + if(hfont && fontname) { if(cinfo) { @@ -4291,10 +4899,25 @@ SetWindowLongPtr(handle, GWLP_USERDATA, (LONG_PTR)cinfo); } } - SendMessage(handle, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE); - if(oldfont) - DeleteObject(oldfont); - return 0; + /* If we changed the font... */ + if(hfont) + { + Item *item = _box_item(handle); + + SendMessage(handle, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE); + if(oldfont) + DeleteObject(oldfont); + + /* Check to see if any of the sizes need to be recalculated */ + if(item && (item->origwidth == -1 || item->origheight == -1)) + { + _control_size(handle, item->origwidth == -1 ? &item->width : NULL, item->origheight == -1 ? &item->height : NULL); + /* Queue a redraw on the top-level window */ + _dw_redraw(_toplevel_window(handle), TRUE); + } + return DW_ERROR_NONE; + } + return DW_ERROR_UNKNOWN; } /* Allows the user to choose a font using the system's font chooser dialog. @@ -4332,7 +4955,7 @@ italic = " Italic"; height = MulDiv(abs(lf.lfHeight), 72, GetDeviceCaps (hdc, LOGPIXELSY)); ReleaseDC(NULL, hdc); - _snprintf( str, 100, "%d.%s%s%s", height, lf.lfFaceName, bold, italic ); + _snprintf( str, 100, "%d.%s%s%s", height, WideToUTF8(lf.lfFaceName), bold, italic ); } } return str; @@ -4352,10 +4975,10 @@ char *italic = ""; LOGFONT lf = { 0 }; Box *thisbox; - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; GetClassName(handle, tmpbuf, 99); - if ( strnicmp( tmpbuf, FRAMECLASSNAME, strlen(FRAMECLASSNAME)+1) == 0 ) + if ( _tcsnicmp( tmpbuf, FRAMECLASSNAME, _tcslen(FRAMECLASSNAME)+1) == 0 ) { /* groupbox */ thisbox = (Box *)GetWindowLongPtr( handle, GWLP_USERDATA ); @@ -4398,13 +5021,13 @@ { ColorInfo *cinfo; Box *thisbox; - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; cinfo = (ColorInfo *)GetWindowLongPtr(handle, GWLP_USERDATA); GetClassName(handle, tmpbuf, 99); - if(strnicmp(tmpbuf, WC_LISTVIEW, strlen(WC_LISTVIEW))==0) + if(_tcsnicmp(tmpbuf, WC_LISTVIEW, _tcslen(WC_LISTVIEW))==0) { cinfo->fore = fore = _internal_color(fore); cinfo->back = back = _internal_color(back); @@ -4421,7 +5044,7 @@ InvalidateRgn(handle, NULL, TRUE); return TRUE; } - else if ( strnicmp( tmpbuf, FRAMECLASSNAME, strlen(FRAMECLASSNAME)) == 0 ) + else if ( _tcsnicmp( tmpbuf, FRAMECLASSNAME, _tcslen(FRAMECLASSNAME)) == 0 ) { /* groupbox */ thisbox = (Box *)GetWindowLongPtr( handle, GWLP_USERDATA ); @@ -4511,44 +5134,47 @@ HWND hwndframe; Box *newbox = calloc(sizeof(Box), 1); ULONG flStyleEx = 0; - - newbox->pad = 0; +#ifdef AEROGLASS + MARGINS mar = {-1}; + + if(_dw_composition && (flStyle & DW_FCF_COMPOSITED)) + flStyleEx = WS_EX_LAYERED; +#endif + newbox->type = DW_VERT; - newbox->count = 0; + newbox->vsize = newbox->hsize = SIZEEXPAND; newbox->cinfo.fore = newbox->cinfo.back = -1; - /* Hmm, the "correct" way doesn't seem to be - * working, but the old hackish SetParent() - * at the bottom seems to work, so I'll leave - * it like this for now. - */ -#if 0 - if(hwndOwner) - flStyleEx |= WS_EX_MDICHILD; -#endif - if(!(flStyle & WS_CAPTION)) flStyle |= WS_POPUPWINDOW; - if(flStyle & DW_FCF_TASKLIST) - { - ULONG newflags = (flStyle | WS_CLIPCHILDREN) & ~DW_FCF_TASKLIST; - - hwndframe = CreateWindowEx(flStyleEx, ClassName, title, newflags, CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner, NULL, DWInstance, NULL); + if(flStyle & DW_FCF_TASKLIST || + flStyle & WS_VSCROLL /* This is deprecated and should go away in version 3? */) + { + hwndframe = CreateWindowEx(flStyleEx, ClassName, UTF8toWide(title), (flStyle | WS_CLIPCHILDREN) & 0xffdf0000, CW_USEDEFAULT, CW_USEDEFAULT, + 0, 0, hwndOwner, NULL, DWInstance, NULL); } else { flStyleEx |= WS_EX_TOOLWINDOW; - hwndframe = CreateWindowEx(flStyleEx, ClassName, title, flStyle | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner, NULL, DWInstance, NULL); + hwndframe = CreateWindowEx(flStyleEx, ClassName, UTF8toWide(title), (flStyle | WS_CLIPCHILDREN) & 0xffff0000, CW_USEDEFAULT, CW_USEDEFAULT, + 0, 0, hwndOwner, NULL, DWInstance, NULL); } SetWindowLongPtr(hwndframe, GWLP_USERDATA, (LONG_PTR)newbox); if(hwndOwner) SetParent(hwndframe, hwndOwner); +#ifdef AEROGLASS + /* Attempt to enable Aero glass background on the entire window */ + if(_DwmExtendFrameIntoClientArea && _dw_composition && (flStyle & DW_FCF_COMPOSITED)) + { + SetLayeredWindowAttributes(hwndframe, _dw_transparencykey, 0, LWA_COLORKEY); + _DwmExtendFrameIntoClientArea(hwndframe, &mar); + } +#endif + return hwndframe; } @@ -4570,7 +5196,7 @@ newbox->cinfo.fore = newbox->cinfo.back = -1; hwndframe = CreateWindow(FRAMECLASSNAME, - "", + NULL, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN, 0,0,0,0, DW_HWND_OBJECT, @@ -4601,7 +5227,7 @@ cinfo->fore = cinfo->back = -1; hwndframe = CreateWindow(ScrollClassName, - "", + NULL, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL, 0,0,0,0, DW_HWND_OBJECT, @@ -4687,7 +5313,7 @@ newbox->cinfo.fore = newbox->cinfo.back = -1; hwndframe = CreateWindow(FRAMECLASSNAME, - "", + NULL, WS_VISIBLE | WS_CHILD, 0,0,0,0, DW_HWND_OBJECT, @@ -4696,7 +5322,7 @@ NULL); newbox->grouphwnd = CreateWindow(BUTTONCLASSNAME, - title, + UTF8toWide(title), WS_CHILD | BS_GROUPBOX | WS_VISIBLE | WS_CLIPCHILDREN, 0,0,0,0, @@ -4723,8 +5349,8 @@ ccs.hWindowMenu = NULL; ccs.idFirstChild = 0; - hwndframe = CreateWindow("MDICLIENT", - "", + hwndframe = CreateWindow(TEXT("MDICLIENT"), + NULL, WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS, 0,0,0,0, DW_HWND_OBJECT, @@ -4743,7 +5369,7 @@ { #if (defined(BUILD_DLL) || defined(BUILD_HTML)) && !defined(__MINGW32__) return CreateWindow(BrowserClassName, - "", + NULL, WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS, 0,0,0,0, DW_HWND_OBJECT, @@ -4819,7 +5445,7 @@ HWND API dw_bitmap_new(ULONG id) { return CreateWindow(STATICCLASSNAME, - "", + NULL, SS_BITMAP | SS_CENTERIMAGE | WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN, 0,0,0,0, @@ -4845,7 +5471,7 @@ flags = TCS_BOTTOM; tmp = CreateWindow(WC_TABCONTROL, - "", + NULL, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | flags, 0,0,0,0, DW_HWND_OBJECT, @@ -5022,8 +5648,8 @@ mii.hSubMenu = (HMENU)submenu; else mii.hSubMenu = 0; - mii.dwTypeData = menutitle; - mii.cch = strlen(menutitle); + mii.dwTypeData = UTF8toWide(menutitle); + mii.cch = (UINT)_tcslen(mii.dwTypeData); InsertMenuItem(mymenu, 65535, TRUE, &mii); @@ -5183,26 +5809,31 @@ } /* - * INCOMPLETE * Deletes the menu item specified * Parameters: * menu: The handle to the menu in which the item was appended. * id: Menuitem id. - */ -void API dw_menu_delete_item(HMENUI menux, unsigned long id) + * Returns: + * DW_ERROR_NONE (0) on success or DW_ERROR_UNKNOWN on failure. + */ +int API dw_menu_delete_item(HMENUI menux, unsigned long id) { HMENU mymenu = (HMENU)menux; if ( IsWindow(menux) && !IsMenu(mymenu) ) mymenu = (HMENU)dw_window_get_data(menux, "_dw_menu"); - if ( DeleteMenu(mymenu, id, MF_BYCOMMAND) == 0 ) - { - char lasterror[257]; - FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), lasterror, 256, NULL); - fprintf(stderr, "Error deleting menu: %s", lasterror); - } - DrawMenuBar(menux); + if ( mymenu == 0 || DeleteMenu(mymenu, id, MF_BYCOMMAND) == 0 ) + return DW_ERROR_UNKNOWN; + + /* If the ID was autogenerated it is safe to remove it */ + if(id >= 30000) + dw_signal_disconnect_by_window((HWND)id); + + /* Make sure the menu is redrawn if needed */ + if( (HMENU)menux != mymenu ) + DrawMenuBar(menux); + return DW_ERROR_NONE; } /* @@ -5238,7 +5869,7 @@ HWND API dw_container_new(ULONG id, int multi) { HWND tmp = CreateWindow(WC_LISTVIEW, - "", + NULL, WS_VISIBLE | WS_CHILD | (multi ? 0 : LVS_SINGLESEL) | LVS_REPORT | LVS_SHOWSELALWAYS | @@ -5257,7 +5888,7 @@ return NULL; } - cinfo->cinfo.pOldProc = (WNDPROC)SubclassWindow(tmp, _containerwndproc); + cinfo->cinfo.pOldProc = SubclassWindow(tmp, _containerwndproc); cinfo->cinfo.fore = cinfo->cinfo.back = -1; cinfo->odd = cinfo->even = DW_RGB_TRANSPARENT; @@ -5281,7 +5912,7 @@ HWND API dw_tree_new(ULONG id) { HWND tmp = CreateWindow(WC_TREEVIEW, - "", + NULL, WS_VISIBLE | WS_CHILD | TVS_HASLINES | TVS_SHOWSELALWAYS | TVS_HASBUTTONS | TVS_LINESATROOT | @@ -5300,7 +5931,7 @@ return NULL; } - cinfo->cinfo.pOldProc = (WNDPROC)SubclassWindow(tmp, _treewndproc); + cinfo->cinfo.pOldProc = SubclassWindow(tmp, _treewndproc); cinfo->cinfo.fore = cinfo->cinfo.back = -1; cinfo->odd = cinfo->even = DW_RGB_TRANSPARENT; @@ -5347,16 +5978,24 @@ HWND API dw_text_new(char *text, ULONG id) { HWND tmp = CreateWindow(STATICCLASSNAME, - text, - SS_NOPREFIX | - BS_TEXT | WS_VISIBLE | + UTF8toWide(text), + SS_NOPREFIX | SS_NOTIFY | WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN, 0,0,0,0, DW_HWND_OBJECT, (HMENU)id, DWInstance, NULL); +#ifdef AEROGLASS + ColorInfo *cinfo = calloc(1, sizeof(ColorInfo)); + + cinfo->back = cinfo->fore = -1; + + cinfo->pOldProc = SubclassWindow(tmp, _staticwndproc); + SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)cinfo); +#endif dw_window_set_font(tmp, DefaultFont); + dw_window_set_color(tmp, DW_CLR_DEFAULT, DW_RGB_TRANSPARENT); return tmp; } @@ -5368,17 +6007,15 @@ */ HWND API dw_status_text_new(char *text, ULONG id) { - HWND tmp = CreateWindow(ObjectClassName, - text, - BS_TEXT | WS_VISIBLE | - WS_CHILD | WS_CLIPCHILDREN, + HWND tmp = CreateWindow(StatusbarClassName, + UTF8toWide(text), + WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN, 0,0,0,0, DW_HWND_OBJECT, (HMENU)id, DWInstance, NULL); dw_window_set_font(tmp, DefaultFont); - SubclassWindow(tmp, _statuswndproc); return tmp; } @@ -5391,8 +6028,8 @@ { HWND tmp = CreateWindowEx(WS_EX_CLIENTEDGE, - EDITCLASSNAME, - "", + hrichedit ? RICHEDIT_CLASS : EDITCLASSNAME, + NULL, WS_VISIBLE | WS_BORDER | WS_VSCROLL | ES_MULTILINE | ES_WANTRETURN | WS_CHILD | @@ -5410,7 +6047,7 @@ return NULL; } - cinfo->cinfo.pOldProc = (WNDPROC)SubclassWindow(tmp, _treewndproc); + cinfo->cinfo.pOldProc = SubclassWindow(tmp, _treewndproc); cinfo->cinfo.fore = cinfo->cinfo.back = -1; cinfo->odd = cinfo->even = DW_RGB_TRANSPARENT; @@ -5429,7 +6066,7 @@ { HWND tmp = CreateWindowEx(WS_EX_CLIENTEDGE, EDITCLASSNAME, - text, + UTF8toWide(text), ES_WANTRETURN | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL | WS_VISIBLE | WS_CLIPCHILDREN, @@ -5458,7 +6095,7 @@ { HWND tmp = CreateWindowEx(WS_EX_CLIENTEDGE, EDITCLASSNAME, - text, + UTF8toWide(text), ES_WANTRETURN | WS_CHILD | ES_PASSWORD | WS_BORDER | WS_VISIBLE | ES_AUTOHSCROLL | WS_CLIPCHILDREN, @@ -5484,7 +6121,7 @@ if(cinfo) { cinfo->buddy = handle; - cinfo->pOldProc = (WNDPROC)SubclassWindow(handle, _colorwndproc); + cinfo->pOldProc = SubclassWindow(handle, _colorwndproc); SetWindowLongPtr(handle, GWLP_USERDATA, (LONG_PTR)cinfo); } return FALSE; @@ -5499,7 +6136,7 @@ HWND API dw_combobox_new(char *text, ULONG id) { HWND tmp = CreateWindow(COMBOBOXCLASSNAME, - text, + UTF8toWide(text), WS_CHILD | CBS_DROPDOWN | WS_VSCROLL | WS_CLIPCHILDREN | CBS_AUTOHSCROLL | WS_VISIBLE, 0,0,0,0, @@ -5524,10 +6161,11 @@ cinfo2->back = cinfo->back = -1; cinfo2->combo = cinfo->combo = tmp; EnumChildWindows(tmp, _subclass_child, (LPARAM)cinfo2); - + cinfo->buddy = cinfo2->buddy; + SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)cinfo); dw_window_set_font(tmp, DefaultFont); - SetWindowText(tmp, text); + SetWindowText(tmp, UTF8toWide(text)); return tmp; } @@ -5539,10 +6177,10 @@ */ HWND API dw_button_new(char *text, ULONG id) { - BubbleButton *bubble = calloc(1, sizeof(BubbleButton)); + ColorInfo *cinfo = calloc(1, sizeof(ColorInfo)); HWND tmp = CreateWindow(BUTTONCLASSNAME, - text, + UTF8toWide(text), WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE | WS_CLIPCHILDREN, 0,0,0,0, @@ -5550,14 +6188,100 @@ (HMENU)id, DWInstance, NULL); - bubble->cinfo.fore = bubble->cinfo.back = -1; - bubble->pOldProc = (WNDPROC)SubclassWindow(tmp, _BtProc); - - SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)bubble); + cinfo->fore = cinfo->back = -1; + cinfo->pOldProc = SubclassWindow(tmp, _BtProc); + + SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)cinfo); dw_window_set_font(tmp, DefaultFont); return tmp; } +#ifdef TOOLBAR +/* Internal function to create a grayscale bitmap from a color one */ +void _to_grayscale(HBITMAP hbm, int width, int height) +{ + HDC hdc = CreateCompatibleDC(NULL); + if (hdc) + { + HBITMAP hbmPrev = SelectBitmap(hdc, hbm); + int x, y; + + for(y=0;y<height;y++) + { + for(x=0;x<width;x++) + { + COLORREF c = GetPixel(hdc, x, y); + /* Use half-values then add 127 to make it look washed out */ + int luma = (int)(GetRValue(c)*0.15 + GetGValue(c)*0.3+ GetBValue(c)*0.06) + 127; + + SetPixel(hdc, x, y, RGB(luma,luma,luma)); + } + } + SelectBitmap(hdc, hbmPrev); + DeleteDC(hdc); + } +} + +/* Internal function to create a toolbar based button */ +HWND _create_toolbar(char *text, ULONG id, HICON icon, HBITMAP hbitmap) +{ + HWND tmp; + HIMAGELIST imlist, dimlist; + BITMAP bmi = { 0 }; + TBBUTTON tbButtons[] = { + { MAKELONG(0, 0), id, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0} + }; + + /* Get the bitmap from either the icon or bitmap itself */ + if(hbitmap) + { + GetObject(hbitmap, sizeof(BITMAP), &bmi); + imlist = ImageList_Create(bmi.bmWidth, bmi.bmHeight, ILC_COLOR32, 1, 0); + ImageList_Add(imlist, hbitmap, NULL); + dimlist = ImageList_Create(bmi.bmWidth, bmi.bmHeight, ILC_COLOR32, 1, 0); + _to_grayscale(hbitmap, bmi.bmWidth, bmi.bmHeight); + ImageList_Add(dimlist, hbitmap, NULL); + DeleteObject(hbitmap); + } + else if(icon) + { + ICONINFO iconinfo; + + GetIconInfo(icon, &iconinfo); + GetObject(iconinfo.hbmColor, sizeof(BITMAP), &bmi); + imlist = ImageList_Create(bmi.bmWidth, bmi.bmHeight, ILC_COLOR32 | ILC_MASK, 1, 0); + ImageList_AddIcon(imlist, icon); + dimlist = ImageList_Create(bmi.bmWidth, bmi.bmHeight, ILC_COLOR32 | ILC_MASK, 1, 0); + _to_grayscale(iconinfo.hbmColor, bmi.bmWidth, bmi.bmHeight); + ImageList_Add(dimlist, iconinfo.hbmColor, iconinfo.hbmMask); + DeleteObject(iconinfo.hbmColor); + DeleteObject(iconinfo.hbmMask); + DestroyIcon(icon); + } + else + return 0; + + /* Create the toolbar */ + tmp = CreateWindowEx(0L, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | TBSTYLE_AUTOSIZE | CCS_NORESIZE | + CCS_NOPARENTALIGN | CCS_NODIVIDER, 0, 0, 100, 30, DW_HWND_OBJECT, (HMENU)id, DWInstance, NULL); + + /* Disable visual styles by default */ + if(_SetWindowTheme) + _SetWindowTheme(tmp, L"", L""); + + /* Insert the single bitmap and button into the toolbar */ + SendMessage(tmp, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); + SendMessage(tmp, TB_SETBUTTONSIZE, 0, MAKELPARAM(bmi.bmWidth, bmi.bmHeight)); + SendMessage(tmp, TB_SETPADDING, 0, 0); + SendMessage(tmp, TB_SETIMAGELIST, 0, (LPARAM)imlist); + SendMessage(tmp, TB_SETDISABLEDIMAGELIST, 0, (LPARAM)dimlist); + SendMessage(tmp, TB_ADDBUTTONS, 1, (LONG) &tbButtons); + + _create_tooltip(tmp, text); + return tmp; +} +#endif + /* * Create a new bitmap button window (widget) to be packed. * Parameters: @@ -5567,12 +6291,20 @@ HWND API dw_bitmapbutton_new(char *text, ULONG id) { HWND tmp; - BubbleButton *bubble = calloc(1, sizeof(BubbleButton)); - HBITMAP hbitmap = LoadBitmap(DWInstance, MAKEINTRESOURCE(id)); - HICON icon = LoadImage(DWInstance, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, LR_SHARED); + ColorInfo *cinfo = calloc(1, sizeof(ColorInfo)); + HICON icon = LoadImage(DWInstance, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, 0); + HBITMAP hbitmap = icon ? 0 : LoadBitmap(DWInstance, MAKEINTRESOURCE(id)); +#ifdef TOOLBAR + if(tmp = _create_toolbar(text, id, icon, hbitmap)) + { + cinfo->fore = cinfo->back = -1; + SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)cinfo); + return tmp; + } +#endif tmp = CreateWindow(BUTTONCLASSNAME, - "", + NULL, WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE | WS_CLIPCHILDREN | (icon ? BS_ICON : BS_BITMAP), @@ -5582,10 +6314,10 @@ DWInstance, NULL); - bubble->cinfo.fore = bubble->cinfo.back = -1; - bubble->pOldProc = (WNDPROC)SubclassWindow(tmp, _BtProc); - - SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)bubble); + cinfo->fore = cinfo->back = -1; + cinfo->pOldProc = SubclassWindow(tmp, _BtProc); + + SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)cinfo); _create_tooltip(tmp, text); @@ -5612,12 +6344,12 @@ HWND API dw_bitmapbutton_new_from_file(char *text, unsigned long id, char *filename) { HWND tmp; - BubbleButton *bubble; + ColorInfo *cinfo = calloc(1, sizeof(ColorInfo)); HBITMAP hbitmap = 0; HANDLE hicon = 0; int windowtype = 0; - if (!(bubble = calloc(1, sizeof(BubbleButton)))) + if (!cinfo) return 0; #ifdef GDIPLUS @@ -5632,8 +6364,16 @@ windowtype = _dw_get_image_handle(filename, &hicon, &hbitmap); #endif +#ifdef TOOLBAR + if(tmp = _create_toolbar(text, id, hicon, hbitmap)) + { + cinfo->fore = cinfo->back = -1; + SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)cinfo); + return tmp; + } +#endif tmp = CreateWindow( BUTTONCLASSNAME, - "", + NULL, windowtype | WS_CHILD | BS_PUSHBUTTON | WS_CLIPCHILDREN | WS_VISIBLE, 0,0,0,0, DW_HWND_OBJECT, @@ -5641,10 +6381,10 @@ DWInstance, NULL); - bubble->cinfo.fore = bubble->cinfo.back = -1; - bubble->pOldProc = (WNDPROC)SubclassWindow(tmp, _BtProc); - - SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)bubble); + cinfo->fore = cinfo->back = -1; + cinfo->pOldProc = SubclassWindow(tmp, _BtProc); + + SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)cinfo); _create_tooltip(tmp, text); @@ -5671,15 +6411,16 @@ HWND API dw_bitmapbutton_new_from_data(char *text, unsigned long id, char *data, int len) { HWND tmp; - BubbleButton *bubble; + ColorInfo *cinfo = calloc(1, sizeof(ColorInfo)); HBITMAP hbitmap = 0; HANDLE hicon = 0; char *file; FILE *fp; int windowtype = BS_BITMAP; - if ( !(bubble = calloc(1, sizeof(BubbleButton))) ) + if (!cinfo) return 0; + file = _tempnam( _dw_alternate_temp_dir, "dw" ); if ( file != NULL ) { @@ -5695,26 +6436,34 @@ hbitmap = _dw_load_bitmap(file, NULL); #else if ( len > 1 && data[0] == 'B' && data[1] == 'M' ) /* first 2 chars of data is BM, then its a BMP */ - hbitmap = (HBITMAP)LoadImage( NULL, file, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); + hbitmap = (HBITMAP)LoadImage( NULL, UTF8toWide(file), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); else /* otherwise its assumed to be an ico */ { - hicon = LoadImage( NULL, file, IMAGE_ICON, 0, 0, LR_LOADFROMFILE ); + hicon = LoadImage( NULL, UTF8toWide(file), IMAGE_ICON, 0, 0, LR_LOADFROMFILE ); windowtype = BS_ICON; } #endif } else { - unlink( file ); + _unlink( file ); free( file ); return 0; } - unlink( file ); + _unlink( file ); free( file ); } +#ifdef TOOLBAR + if(tmp = _create_toolbar(text, id, hicon, hbitmap)) + { + cinfo->fore = cinfo->back = -1; + SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)cinfo); + return tmp; + } +#endif tmp = CreateWindow( BUTTONCLASSNAME, - "", + NULL, WS_CHILD | BS_PUSHBUTTON | windowtype | WS_CLIPCHILDREN | WS_VISIBLE, @@ -5724,10 +6473,10 @@ DWInstance, NULL ); - bubble->cinfo.fore = bubble->cinfo.back = -1; - bubble->pOldProc = (WNDPROC)SubclassWindow( tmp, _BtProc ); - - SetWindowLongPtr( tmp, GWLP_USERDATA, (LONG_PTR)bubble ); + cinfo->fore = cinfo->back = -1; + cinfo->pOldProc = SubclassWindow( tmp, _BtProc ); + + SetWindowLongPtr( tmp, GWLP_USERDATA, (LONG_PTR)cinfo ); _create_tooltip(tmp, text); @@ -5752,7 +6501,7 @@ { HWND buddy = CreateWindowEx(WS_EX_CLIENTEDGE, EDITCLASSNAME, - text, + UTF8toWide(text), WS_CHILD | WS_BORDER | WS_VISIBLE | ES_NUMBER | WS_CLIPCHILDREN, 0,0,0,0, @@ -5806,7 +6555,7 @@ HWND API dw_radiobutton_new(char *text, ULONG id) { HWND tmp = CreateWindow(BUTTONCLASSNAME, - text, + UTF8toWide(text), WS_CHILD | BS_AUTORADIOBUTTON | WS_CLIPCHILDREN | WS_VISIBLE, 0,0,0,0, @@ -5814,11 +6563,12 @@ (HMENU)id, DWInstance, NULL); - BubbleButton *bubble = calloc(1, sizeof(BubbleButton)); - bubble->cinfo.fore = bubble->cinfo.back = -1; - bubble->pOldProc = (WNDPROC)SubclassWindow(tmp, _BtProc); - SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)bubble); + ColorInfo *cinfo = calloc(1, sizeof(ColorInfo)); + cinfo->fore = cinfo->back = -1; + cinfo->pOldProc = SubclassWindow(tmp, _BtProc); + SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)cinfo); dw_window_set_font(tmp, DefaultFont); + dw_window_set_color(tmp, DW_CLR_DEFAULT, DW_RGB_TRANSPARENT); return tmp; } @@ -5833,7 +6583,7 @@ HWND API dw_slider_new(int vertical, int increments, ULONG id) { HWND tmp = CreateWindow(TRACKBAR_CLASS, - "", + NULL, WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | (vertical ? TBS_VERT : TBS_HORZ), 0,0,0,0, @@ -5861,7 +6611,7 @@ HWND API dw_scrollbar_new(int vertical, ULONG id) { HWND tmp = CreateWindow(SCROLLBARCLASSNAME, - "", + NULL, WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | (vertical ? SBS_VERT : SBS_HORZ), 0,0,0,0, @@ -5887,7 +6637,7 @@ HWND API dw_percent_new(ULONG id) { return CreateWindow(PROGRESS_CLASS, - "", + NULL, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN, 0,0,0,0, DW_HWND_OBJECT, @@ -5904,9 +6654,9 @@ */ HWND API dw_checkbox_new(char *text, ULONG id) { - BubbleButton *bubble = calloc(1, sizeof(BubbleButton)); + ColorInfo *cinfo = calloc(1, sizeof(ColorInfo)); HWND tmp = CreateWindow(BUTTONCLASSNAME, - text, + UTF8toWide(text), WS_CHILD | BS_AUTOCHECKBOX | BS_TEXT | WS_CLIPCHILDREN | WS_VISIBLE, 0,0,0,0, @@ -5914,11 +6664,11 @@ (HMENU)id, DWInstance, NULL); - bubble->checkbox = 1; - bubble->cinfo.fore = bubble->cinfo.back = -1; - bubble->pOldProc = (WNDPROC)SubclassWindow(tmp, _BtProc); - SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)bubble); + cinfo->pOldProc = SubclassWindow(tmp, _BtProc); + SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)cinfo); + dw_window_set_data(tmp, "_dw_checkbox", DW_INT_TO_POINTER(1)); dw_window_set_font(tmp, DefaultFont); + dw_window_set_color(tmp, DW_CLR_DEFAULT, DW_RGB_TRANSPARENT); return tmp; } @@ -5932,7 +6682,7 @@ { HWND tmp = CreateWindowEx(WS_EX_CLIENTEDGE, LISTBOXCLASSNAME, - "", + NULL, WS_VISIBLE | LBS_NOINTEGRALHEIGHT | WS_CHILD | LBS_HASSTRINGS | LBS_NOTIFY | WS_BORDER | WS_CLIPCHILDREN | @@ -5952,7 +6702,7 @@ cinfo->cinfo.fore = cinfo->cinfo.back = -1; cinfo->odd = cinfo->even = DW_RGB_TRANSPARENT; - cinfo->cinfo.pOldProc = (WNDPROC)SubclassWindow(tmp, _containerwndproc); + cinfo->cinfo.pOldProc = SubclassWindow(tmp, _containerwndproc); SetWindowLongPtr(tmp, GWLP_USERDATA, (LONG_PTR)cinfo); dw_window_set_font(tmp, DefaultFont); @@ -6031,6 +6781,19 @@ DeleteObject(oldbitmap); else if(icon && oldicon) DeleteObject(oldicon); + + /* If we changed the bitmap... */ + { + Item *item = _box_item(handle); + + /* Check to see if any of the sizes need to be recalculated */ + if(item && (item->origwidth == -1 || item->origheight == -1)) + { + _control_size(handle, item->origwidth == -1 ? &item->width : NULL, item->origheight == -1 ? &item->height : NULL); + /* Queue a redraw on the top-level window */ + _dw_redraw(_toplevel_window(handle), TRUE); + } + } } /* @@ -6053,12 +6816,7 @@ char *file; FILE *fp; - if ( id ) - { - hbitmap = LoadBitmap( DWInstance, MAKEINTRESOURCE(id) ); - icon = LoadImage( DWInstance, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, LR_SHARED ); - } - else if (data) + if (data) { file = _tempnam( _dw_alternate_temp_dir, "dw" ); if ( file != NULL ) @@ -6072,23 +6830,28 @@ hbitmap = _dw_load_bitmap(file, NULL); #else if ( len > 1 && data[0] == 'B' && data[1] == 'M' ) /* first 2 chars of data is BM, then its a BMP */ - hbitmap = (HBITMAP)LoadImage( NULL, file, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); + hbitmap = (HBITMAP)LoadImage( NULL, UTF8toWide(file), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); else /* otherwise its assumed to be an ico */ - icon = LoadImage( NULL, file, IMAGE_ICON, 0, 0, LR_LOADFROMFILE ); + icon = LoadImage( NULL, UTF8toWide(file), IMAGE_ICON, 0, 0, LR_LOADFROMFILE ); #endif } else { - unlink( file ); + _unlink( file ); free( file ); return; } - unlink( file ); + _unlink( file ); free( file ); } if (icon == 0 && hbitmap == 0) return; } + else if ( id ) + { + hbitmap = LoadBitmap( DWInstance, MAKEINTRESOURCE(id) ); + icon = LoadImage( DWInstance, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, LR_SHARED ); + } if ( icon ) { @@ -6125,28 +6888,55 @@ void API dw_window_set_text(HWND handle, char *text) { Box *thisbox; - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}, *wtext = UTF8toWide(text); GetClassName(handle, tmpbuf, 99); - SetWindowText(handle, text); + SetWindowText(handle, wtext); /* Combobox */ - if ( strnicmp( tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1) == 0 ) + if ( _tcsnicmp( tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1) == 0 ) SendMessage(handle, CB_SETEDITSEL, 0, MAKELPARAM(-1, 0)); - else if ( strnicmp( tmpbuf, UPDOWN_CLASS, strlen(UPDOWN_CLASS)+1) == 0 ) + else if ( _tcsnicmp( tmpbuf, UPDOWN_CLASS, _tcslen(UPDOWN_CLASS)+1) == 0 ) { ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(handle, GWLP_USERDATA); if( cinfo && cinfo->buddy ) - SetWindowText( cinfo->buddy, text ); - } - else if ( strnicmp( tmpbuf, FRAMECLASSNAME, strlen(FRAMECLASSNAME)+1) == 0 ) + SetWindowText( cinfo->buddy, wtext ); + } + else if ( _tcsnicmp( tmpbuf, FRAMECLASSNAME, _tcslen(FRAMECLASSNAME)+1) == 0 ) { /* groupbox */ thisbox = (Box *)GetWindowLongPtr( handle, GWLP_USERDATA ); if ( thisbox && thisbox->grouphwnd != (HWND)NULL ) - SetWindowText( thisbox->grouphwnd, text ); - } + SetWindowText( thisbox->grouphwnd, wtext ); + } + /* If we changed the text... */ + { + Item *item = _box_item(handle); + + /* Check to see if any of the sizes need to be recalculated */ + if(item && (item->origwidth == -1 || item->origheight == -1)) + { + _control_size(handle, item->origwidth == -1 ? &item->width : NULL, item->origheight == -1 ? &item->height : NULL); + /* Queue a redraw on the top-level window */ + _dw_redraw(_toplevel_window(handle), TRUE); + } + } +} + +/* + * Sets the text used for a given window's floating bubble help. + * Parameters: + * handle: Handle to the window (widget). + * bubbletext: The text in the floating bubble tooltip. + */ +void API dw_window_set_tooltip(HWND handle, char *bubbletext) +{ + ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(handle, GWLP_USERDATA); + + if(cinfo && cinfo->buddy) + _create_tooltip(cinfo->buddy, bubbletext); + _create_tooltip(handle, bubbletext); } /* @@ -6158,12 +6948,13 @@ */ char * API dw_window_get_text(HWND handle) { - char tmpbuf[100], *tempbuf; + char *retbuf = NULL; + TCHAR *tempbuf, tmpbuf[100] = { 0 }; int len; GetClassName(handle, tmpbuf, 99); - if ( strnicmp( tmpbuf, UPDOWN_CLASS, strlen(UPDOWN_CLASS)+1) == 0 ) + if ( _tcsnicmp( tmpbuf, UPDOWN_CLASS, _tcslen(UPDOWN_CLASS)+1) == 0 ) { ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(handle, GWLP_USERDATA); @@ -6173,12 +6964,19 @@ return NULL; } - len = GetWindowTextLength(handle); - tempbuf = calloc(1, len + 2); - - GetWindowText(handle, tempbuf, len + 1); - - return tempbuf; + /* Figure out the wide length, allocate a temp buffer + * and fill it with the current text. + */ + len = GetWindowTextLength(handle) + 1; + if((tempbuf = _alloca(len * sizeof(TCHAR)))) + GetWindowText(handle, tempbuf, len); + + /* Figure out the UTF8 length, allocate a return buffer + * and fill it with the UTF8 text and return it. + */ + if(tempbuf && (retbuf = WideToUTF8(tempbuf))) + retbuf = _strdup(retbuf); + return retbuf; } /* @@ -6256,7 +7054,7 @@ void _dw_box_pack(HWND box, HWND item, int index, int width, int height, int hsize, int vsize, int pad, char *funcname) { Box *thisbox = NULL; - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; /* * If you try and pack an item into itself VERY bad things can happen; like at least an @@ -6269,9 +7067,9 @@ } GetClassName(box, tmpbuf, 99); - + /* If we are in a scrolled box... extract the interal box */ - if(strnicmp(tmpbuf, ScrollClassName, strlen(ScrollClassName)+1)==0) + if(_tcsnicmp(tmpbuf, ScrollClassName, _tcslen(ScrollClassName)+1)==0) { ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(box, GWLP_USERDATA); if(cinfo) @@ -6280,7 +7078,7 @@ thisbox = (Box *)GetWindowLongPtr(box, GWLP_USERDATA); } } - else //if(strnicmp(tmpbuf, FRAMECLASSNAME, strlen(FRAMECLASSNAME)+1)==0) + else //if(_tcsnicmp(tmpbuf, FRAMECLASSNAME, _tcslen(FRAMECLASSNAME)+1)==0) thisbox = (Box *)GetWindowLongPtr(box, GWLP_USERDATA); if(thisbox) { @@ -6288,12 +7086,14 @@ Item *tmpitem, *thisitem = thisbox->items; /* Do some sanity bounds checking */ + if(!thisitem) + thisbox->count = 0; if(index < 0) index = 0; if(index > thisbox->count) index = thisbox->count; - tmpitem = malloc(sizeof(Item)*(thisbox->count+1)); + tmpitem = calloc(sizeof(Item), (thisbox->count+1)); for(z=0;z<thisbox->count;z++) { @@ -6310,49 +7110,49 @@ if(hsize && !width) width = 1; - if(strnicmp(tmpbuf, FRAMECLASSNAME, strlen(FRAMECLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, FRAMECLASSNAME, _tcslen(FRAMECLASSNAME)+1)==0) tmpitem[index].type = TYPEBOX; - else if(strnicmp(tmpbuf, "SysMonthCal32", 13)==0) - { - RECT rc; - MonthCal_GetMinReqRect(item, &rc); - width = 1 + rc.right - rc.left; - height = 1 + rc.bottom - rc.top; - tmpitem[index].type = TYPEITEM; - } else { - if ( width == 0 && hsize == FALSE ) - dw_messagebox(funcname, DW_MB_OK|DW_MB_ERROR, "Width and expand Horizonal both unset for box: %x item: %x",box,item); - if ( height == 0 && vsize == FALSE ) - dw_messagebox(funcname, DW_MB_OK|DW_MB_ERROR, "Height and expand Vertical both unset for box: %x item: %x",box,item); - - tmpitem[index].type = TYPEITEM; + if(_tcsnicmp(tmpbuf, TEXT("SysMonthCal32"), 13)==0) + { + RECT rc; + MonthCal_GetMinReqRect(item, &rc); + width = 1 + rc.right - rc.left; + height = 1 + rc.bottom - rc.top; + tmpitem[index].type = TYPEITEM; + } + else + { + if ( width == 0 && hsize == FALSE ) + dw_messagebox(funcname, DW_MB_OK|DW_MB_ERROR, "Width and expand Horizonal both unset for box: %x item: %x",box,item); + if ( height == 0 && vsize == FALSE ) + dw_messagebox(funcname, DW_MB_OK|DW_MB_ERROR, "Height and expand Vertical both unset for box: %x item: %x",box,item); + + tmpitem[index].type = TYPEITEM; + } } tmpitem[index].hwnd = item; tmpitem[index].origwidth = tmpitem[index].width = width; tmpitem[index].origheight = tmpitem[index].height = height; tmpitem[index].pad = pad; - if(hsize) - tmpitem[index].hsize = SIZEEXPAND; - else - tmpitem[index].hsize = SIZESTATIC; - - if(vsize) - tmpitem[index].vsize = SIZEEXPAND; - else - tmpitem[index].vsize = SIZESTATIC; + tmpitem[index].hsize = hsize ? SIZEEXPAND : SIZESTATIC; + tmpitem[index].vsize = vsize ? SIZEEXPAND : SIZESTATIC; + + /* If either of the parameters are -1 ... calculate the size */ + if(width == -1 || height == -1) + _control_size(item, width == -1 ? &tmpitem[index].width : NULL, height == -1 ? &tmpitem[index].height : NULL); thisbox->items = tmpitem; - if(thisbox->count) + if(thisitem) free(thisitem); thisbox->count++; SetParent(item, box); - if(strncmp(tmpbuf, UPDOWN_CLASS, strlen(UPDOWN_CLASS)+1)==0) + if(_tcsnicmp(tmpbuf, UPDOWN_CLASS, _tcslen(UPDOWN_CLASS)+1)==0) { ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(item, GWLP_USERDATA); @@ -6363,14 +7163,147 @@ SendMessage(item, UDM_SETBUDDY, (WPARAM)cinfo->buddy, 0); } } - } +#ifdef TOOLBAR + else if(_tcsnicmp(tmpbuf, TOOLBARCLASSNAME, _tcslen(TOOLBARCLASSNAME)+1) == 0) + { +#ifdef AEROGLASS + if(!(_dw_composition && (GetWindowLongPtr(_toplevel_window(box), GWL_EXSTYLE) & WS_EX_LAYERED))) +#endif + { + /* Enable double buffering if our window isn't composited */ + SendMessage(item, TB_SETEXTENDEDSTYLE, 0, (LPARAM)TBSTYLE_EX_DOUBLEBUFFER); + } + } +#endif + /* Queue a redraw on the top-level window */ + _dw_redraw(_toplevel_window(box), TRUE); + } +} + +/* + * Remove windows (widgets) from the box they are packed into. + * Parameters: + * handle: Window handle of the packed item to be removed. + * Returns: + * DW_ERROR_NONE on success and DW_ERROR_GENERAL on failure. + */ +int API dw_box_unpack(HWND handle) +{ + HWND parent = GetParent(handle); + + if(handle && parent != HWND_DESKTOP) + { + Box *thisbox = (Box *)GetWindowLongPtr(parent, GWLP_USERDATA); + + /* If the parent box has items... + * try to remove it from the layout + */ + if(thisbox && thisbox->count) + { + int z, index = -1; + Item *tmpitem = NULL, *thisitem = thisbox->items; + + if(!thisitem) + thisbox->count = 0; + + for(z=0;z<thisbox->count;z++) + { + if(thisitem[z].hwnd == handle) + index = z; + } + + if(index == -1) + return DW_ERROR_GENERAL; + + if(thisbox->count > 1) + { + tmpitem = calloc(sizeof(Item), (thisbox->count-1)); + + /* Copy all but the current entry to the new list */ + for(z=0;z<index;z++) + { + tmpitem[z] = thisitem[z]; + } + for(z=index+1;z<thisbox->count;z++) + { + tmpitem[z-1] = thisitem[z]; + } + } + + thisbox->items = tmpitem; + if(thisitem) + free(thisitem); + if(tmpitem) + thisbox->count--; + else + thisbox->count = 0; + + SetParent(handle, DW_HWND_OBJECT); + /* Queue a redraw on the top-level window */ + _dw_redraw(_toplevel_window(parent), TRUE); + return DW_ERROR_NONE; + } + } + return DW_ERROR_GENERAL; +} + +/* + * Remove windows (widgets) from a box at an arbitrary location. + * Parameters: + * box: Window handle of the box to be removed from. + * index: 0 based index of packed items. + * Returns: + * Handle to the removed item on success, 0 on failure or padding. + */ +HWND API dw_box_unpack_at_index(HWND box, int index) +{ + Box *thisbox = (Box *)GetWindowLongPtr(box, GWLP_USERDATA); + + /* Try to remove it from the layout */ + if(thisbox && index > -1 && index < thisbox->count) + { + int z; + Item *tmpitem = NULL, *thisitem = thisbox->items; + HWND handle = thisitem[index].hwnd; + + if(thisbox->count > 1) + { + tmpitem = calloc(sizeof(Item), (thisbox->count-1)); + + /* Copy all but the current entry to the new list */ + for(z=0;z<index;z++) + { + tmpitem[z] = thisitem[z]; + } + for(z=index+1;z<thisbox->count;z++) + { + tmpitem[z-1] = thisitem[z]; + } + } + + thisbox->items = tmpitem; + if(thisitem) + free(thisitem); + if(tmpitem) + thisbox->count--; + else + thisbox->count = 0; + + /* If it isn't padding, reset the parent */ + if(handle) + SetParent(handle, DW_HWND_OBJECT); + /* Queue a redraw on the top-level window */ + _dw_redraw(_toplevel_window(box), TRUE); + return handle; + } + return 0; } /* * Pack windows (widgets) into a box at an arbitrary location. * Parameters: * box: Window handle of the box to be packed into. - * item: Window handle of the item to be back. + * item: Window handle of the item to pack. * index: 0 based index of packed items. * width: Width in pixels of the item or -1 to be self determined. * height: Height in pixels of the item or -1 to be self determined. @@ -6387,7 +7320,7 @@ * Pack windows (widgets) into a box from the start (or top). * Parameters: * box: Window handle of the box to be packed into. - * item: Window handle of the item to be back. + * item: Window handle of the item to pack. * width: Width in pixels of the item or -1 to be self determined. * height: Height in pixels of the item or -1 to be self determined. * hsize: TRUE if the window (widget) should expand horizontally to fill space given. @@ -6406,7 +7339,7 @@ * Pack windows (widgets) into a box from the end (or bottom). * Parameters: * box: Window handle of the box to be packed into. - * item: Window handle of the item to be back. + * item: Window handle of the item to pack. * width: Width in pixels of the item or -1 to be self determined. * height: Height in pixels of the item or -1 to be self determined. * hsize: TRUE if the window (widget) should expand horizontally to fill space given. @@ -6419,6 +7352,36 @@ } /* + * The following is an attempt to dynamically size a window based on the size of its + * children before realization. Only applicable when width or height is less than one. + */ +void _get_window_for_size(HWND handle, unsigned long *width, unsigned long *height) +{ + Box *thisbox = (Box *)GetWindowLongPtr(handle, GWLP_USERDATA); + + if(thisbox) + { + int depth = 0; + DWORD dwStyle = GetWindowLong(handle, GWL_STYLE); + DWORD dwExStyle = GetWindowLong(handle, GWL_EXSTYLE); + HMENU menu = GetMenu(handle) ; + RECT rc = { 0 } ; + + /* Calculate space requirements */ + _resize_box(thisbox, &depth, *width, *height, 1); + + rc.right = thisbox->minwidth; + rc.bottom = thisbox->minheight; + + /* Take into account the window border and menu here */ + AdjustWindowRectEx(&rc, dwStyle, menu ? TRUE : FALSE, dwExStyle); + + if ( *width < 1 ) *width = rc.right - rc.left; + if ( *height < 1 ) *height = rc.bottom - rc.top; + } +} + +/* * Sets the size of a given window (widget). * Parameters: * handle: Window (widget) handle. @@ -6427,22 +7390,56 @@ */ void API dw_window_set_size(HWND handle, ULONG width, ULONG height) { - int usedx = 0, usedy = 0, depth = 0, usedpadx = 0, usedpady = 0; - Box *thisbox; - /* - * The following is an attempt to dynamically size a window based on the size of its - * children before realization. Only applicable when width or height is zero. - * It doesn't work vey well :-( - */ - thisbox = (Box *)GetWindowLongPtr(handle, GWLP_USERDATA); - if ( thisbox ) - { - _resize_box(thisbox, &depth, 0, 0, &usedx, &usedy, 1, &usedpadx, &usedpady); - _resize_box(thisbox, &depth, usedx, usedy, &usedx, &usedy, 2, &usedpadx, &usedpady); - } - if ( width == 0 ) width = usedx; - if ( height == 0 ) height = usedy; - SetWindowPos(handle, (HWND)NULL, 0, 0, width, height, SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOMOVE); + /* Attempt to auto-size */ + if ( width < 1 || height < 1 ) + _get_window_for_size(handle, &width, &height); + + /* Finally set the size */ + SetWindowPos(handle, (HWND)NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE); +} + +/* + * Gets the size the system thinks the widget should be. + * Parameters: + * handle: Window handle of the item to be back. + * width: Width in pixels of the item or NULL if not needed. + * height: Height in pixels of the item or NULL if not needed. + */ +void API dw_window_get_preferred_size(HWND handle, int *width, int *height) +{ + TCHAR tmpbuf[100] = {0}; + + GetClassName(handle, tmpbuf, 99); + + if(_tcsnicmp(tmpbuf, ClassName, _tcslen(ClassName)+1) == 0) + { + unsigned long thiswidth = 0, thisheight = 0; + + /* Get the size with the border */ + _get_window_for_size(handle, &thiswidth, &thisheight); + + /* Return what was requested */ + if(width) *width = (int)thiswidth; + if(height) *height = (int)thisheight; + } + else if(_tcsnicmp(tmpbuf, FRAMECLASSNAME, _tcslen(FRAMECLASSNAME)+1) == 0) + { + Box *thisbox = (Box *)GetWindowLongPtr(handle, GWLP_USERDATA); + + if(thisbox) + { + int depth = 0; + + /* Calculate space requirements */ + _resize_box(thisbox, &depth, 0, 0, 1); + + /* Return what was requested */ + if(width) *width = thisbox->minwidth; + if(height) *height = thisbox->minheight; + } + } + else + _control_size(handle, width, height); } /* @@ -6450,7 +7447,7 @@ */ int API dw_screen_width(void) { - return screenx; + return GetSystemMetrics(SM_CXSCREEN); } /* @@ -6458,7 +7455,7 @@ */ int API dw_screen_height(void) { - return screeny; + return GetSystemMetrics(SM_CYSCREEN); } /* This should return the current color depth */ @@ -6474,6 +7471,75 @@ return bpp; } +/* + * Sets the gravity of a given window (widget). + * Gravity controls which corner of the screen and window the position is relative to. + * Parameters: + * handle: Window (widget) handle. + * horz: DW_GRAV_LEFT (default), DW_GRAV_RIGHT or DW_GRAV_CENTER. + * vert: DW_GRAV_TOP (default), DW_GRAV_BOTTOM or DW_GRAV_CENTER. + */ +void API dw_window_set_gravity(HWND handle, int horz, int vert) +{ + dw_window_set_data(handle, "_dw_grav_horz", DW_INT_TO_POINTER(horz)); + dw_window_set_data(handle, "_dw_grav_vert", DW_INT_TO_POINTER(vert)); +} + +/* Convert the coordinates based on gravity */ +void _handle_gravity(HWND handle, long *x, long *y, unsigned long width, unsigned long height) +{ + int horz = DW_POINTER_TO_INT(dw_window_get_data(handle, "_dw_grav_horz")); + int vert = DW_POINTER_TO_INT(dw_window_get_data(handle, "_dw_grav_vert")); + + /* Do any gravity calculations */ + if(horz || vert) + { + long newx = *x, newy = *y; + + /* Handle horizontal center gravity */ + if((horz & 0xf) == DW_GRAV_CENTER) + newx += ((dw_screen_width() / 2) - (width / 2)); + /* Handle right gravity */ + else if((horz & 0xf) == DW_GRAV_RIGHT) + newx = dw_screen_width() - width - *x; + /* Handle vertical center gravity */ + if((vert & 0xf) == DW_GRAV_CENTER) + newy += ((dw_screen_height() / 2) - (height / 2)); + else if((vert & 0xf) == DW_GRAV_BOTTOM) + newy = dw_screen_height() - height - *y; + + /* Save the new values */ + *x = newx; + *y = newy; + + /* Adjust the values to avoid Taskbar if requested */ + if((horz | vert) & DW_GRAV_OBSTACLES) + { + POINT pt = { 0, 0 }; + HMONITOR mon = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY); + MONITORINFO mi; + + mi.cbSize = sizeof(MONITORINFO); + + GetMonitorInfo(mon, &mi); + + if(horz & DW_GRAV_OBSTACLES) + { + if((horz & 0xf) == DW_GRAV_LEFT) + *x += (mi.rcWork.left - mi.rcMonitor.left); + else if((horz & 0xf) == DW_GRAV_RIGHT) + *x -= (mi.rcMonitor.right - mi.rcWork.right); + } + if(vert & DW_GRAV_OBSTACLES) + { + if((vert & 0xf) == DW_GRAV_TOP) + *y += (mi.rcWork.top - mi.rcMonitor.top); + else if((vert & 0xf) == DW_GRAV_BOTTOM) + *y -= (mi.rcMonitor.bottom - mi.rcWork.bottom); + } + } + } +} /* * Sets the position of a given window (widget). @@ -6484,6 +7550,17 @@ */ void API dw_window_set_pos(HWND handle, long x, long y) { + unsigned long width, height; + RECT rect; + + GetClientRect(handle, &rect); + + /* Can't position an unsized window, so attempt to auto-size */ + if((rect.bottom - rect.top) == 0 || (rect.right - rect.left) == 0) + dw_window_set_size(handle, 0, 0); + + dw_window_get_pos_size(handle, NULL, NULL, &width, &height); + _handle_gravity(handle, &x, &y, width, height); SetWindowPos(handle, (HWND)NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); } @@ -6498,26 +7575,13 @@ */ void API dw_window_set_pos_size(HWND handle, long x, long y, ULONG width, ULONG height) { - int usedx = 0, usedy = 0, depth = 0, usedpadx = 0, usedpady = 0; - Box *thisbox; - /* - * The following is an attempt to dynamically size a window based on the size of its - * children before realization. Only applicable when width or height is zero. - * It doesn't work vey well :-( - */ - thisbox = (Box *)GetWindowLongPtr(handle, GWLP_USERDATA); - if ( thisbox ) - { - _resize_box(thisbox, &depth, 0, 0, &usedx, &usedy, 1, &usedpadx, &usedpady); - _resize_box(thisbox, &depth, usedx, usedy, &usedx, &usedy, 2, &usedpadx, &usedpady); - } - if ( width == 0 ) width = usedx; - if ( height == 0 ) height = usedy; - SetWindowPos(handle, (HWND)NULL, x, y, width, height, SWP_NOZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE); -#if 0 - /* force a configure event */ - SendMessage( handle, WM_SIZE, 0, MAKELPARAM(width, height) ); -#endif + /* Attempt to auto-size */ + if ( width < 1 || height < 1 ) + _get_window_for_size(handle, &width, &height); + + _handle_gravity(handle, &x, &y, width, height); + /* Finally set the size */ + SetWindowPos(handle, (HWND)NULL, x, y, width, height, SWP_NOZORDER | SWP_NOACTIVATE); } /* @@ -6571,7 +7635,11 @@ { ULONG tmp, currentstyle; ColorInfo *cinfo; - + TCHAR tmpbuf[100] = {0}; + + if(!handle) + return; + if(handle < (HWND)65536) { char buffer[31] = {0}; @@ -6586,31 +7654,83 @@ return; } + GetClassName(handle, tmpbuf, 99); + currentstyle = GetWindowLong(handle, GWL_STYLE); cinfo = (ColorInfo *)GetWindowLongPtr(handle, GWLP_USERDATA); +#ifdef TOOLBAR + /* Bitmap Buttons */ + if(_tcsnicmp(tmpbuf, TOOLBARCLASSNAME, _tcslen(TOOLBARCLASSNAME)+1) == 0) + { + ULONG thisstyle = (TBSTYLE_FLAT | TBSTYLE_TRANSPARENT); + + if(mask & DW_BS_NOBORDER) + { + SetWindowLong(handle, GWL_STYLE, (style & DW_BS_NOBORDER) ? (currentstyle | thisstyle) : (currentstyle & ~thisstyle)); + + /* Enable or disable visual themese */ + if(_SetWindowTheme) + _SetWindowTheme(handle, (style & DW_BS_NOBORDER) ? NULL : L"", (style & DW_BS_NOBORDER) ? NULL : L""); + + return; + } + } +#endif + tmp = currentstyle | mask; tmp ^= mask; tmp |= style; - /* We are using SS_NOPREFIX as a VCENTER flag */ - if(tmp & SS_NOPREFIX) - { - - if(cinfo) - cinfo->vcenter = 1; - else - { - cinfo = calloc(1, sizeof(ColorInfo)); - cinfo->fore = cinfo->back = -1; - cinfo->vcenter = 1; - - cinfo->pOldProc = SubclassWindow(handle, _colorwndproc); - SetWindowLongPtr(handle, GWLP_USERDATA, (LONG_PTR)cinfo); - } - } - else if(cinfo) - cinfo->vcenter = 0; + if(_tcsnicmp(tmpbuf, ClassName, _tcslen(ClassName)+1)==0) + { + tmp = tmp & 0xffff0000; +#ifdef AEROGLASS + if(mask & DW_FCF_COMPOSITED && _DwmExtendFrameIntoClientArea && _dw_composition) + { + LONG_PTR styleex = GetWindowLongPtr(handle, GWL_EXSTYLE); + + if(style & DW_FCF_COMPOSITED) + { + MARGINS mar = {-1}; + + /* Attempt to enable Aero glass background on the entire window */ + SetWindowLongPtr(handle, GWL_EXSTYLE, styleex | WS_EX_LAYERED); + SetLayeredWindowAttributes(handle, _dw_transparencykey, 0, LWA_COLORKEY); + _DwmExtendFrameIntoClientArea(handle, &mar); + } + else + { + MARGINS mar = {0}; + + /* Remove Aero Glass */ + SetWindowLongPtr(handle, GWL_EXSTYLE, styleex & ~WS_EX_LAYERED); + _DwmExtendFrameIntoClientArea(handle, &mar); + } + } +#endif + } + else + { + /* We are using SS_NOPREFIX as a VCENTER flag */ + if(tmp & SS_NOPREFIX) + { + + if(cinfo) + cinfo->vcenter = 1; + else + { + cinfo = calloc(1, sizeof(ColorInfo)); + cinfo->fore = cinfo->back = -1; + cinfo->vcenter = 1; + + cinfo->pOldProc = SubclassWindow(handle, _colorwndproc); + SetWindowLongPtr(handle, GWLP_USERDATA, (LONG_PTR)cinfo); + } + } + else if(cinfo) + cinfo->vcenter = 0; + } SetWindowLong(handle, GWL_STYLE, tmp); } @@ -6663,7 +7783,7 @@ array[z]->realid = refid; array[z]->item.mask = TCIF_TEXT; array[z]->item.iImage = -1; - array[z]->item.pszText = ""; + array[z]->item.pszText = TEXT(""); TabCtrl_InsertItem(handle, z, &(array[z]->item)); return refid; } @@ -6693,7 +7813,7 @@ if(pageid > -1 && array[pageid]) { array[pageid]->item.mask = TCIF_TEXT; - array[pageid]->item.pszText = text; + array[pageid]->item.pszText = UTF8toWide(text); TabCtrl_SetItem(handle, pageid, &(array[pageid]->item)); _resize_notebook_page(handle, pageid); } @@ -6732,7 +7852,6 @@ HWND tmpbox = dw_box_new(DW_VERT, 0); dw_box_pack_start(tmpbox, page, 0, 0, TRUE, TRUE, 0); - SubclassWindow(tmpbox, _wndproc); if(array[pageid]->hwnd) dw_window_destroy(array[pageid]->hwnd); array[pageid]->hwnd = tmpbox; @@ -6851,18 +7970,18 @@ */ void API dw_listbox_append(HWND handle, char *text) { - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; GetClassName(handle, tmpbuf, 99); - if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1)==0) SendMessage(handle, CB_ADDSTRING, - 0, (LPARAM)text); + 0, (LPARAM)UTF8toWide(text)); else SendMessage(handle, LB_ADDSTRING, - 0, (LPARAM)text); + 0, (LPARAM)UTF8toWide(text)); } /* @@ -6874,19 +7993,19 @@ */ void API dw_listbox_list_append(HWND handle, char **text, int count) { - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; int listbox_type; int i; GetClassName(handle, tmpbuf, 99); - if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1)==0) listbox_type = CB_ADDSTRING; else listbox_type = LB_ADDSTRING; for(i=0;i<count;i++) - SendMessage(handle,(WPARAM)listbox_type,0,(LPARAM)text[i]); + SendMessage(handle,(WPARAM)listbox_type,0,(LPARAM)UTF8toWide(text[i])); } /* @@ -6898,18 +8017,18 @@ */ void API dw_listbox_insert(HWND handle, char *text, int pos) { - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; GetClassName(handle, tmpbuf, 99); - if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1)==0) SendMessage(handle, CB_INSERTSTRING, - pos, (LPARAM)text); + pos, (LPARAM)UTF8toWide(text)); else SendMessage(handle, LB_INSERTSTRING, - pos, (LPARAM)text); + pos, (LPARAM)UTF8toWide(text)); } /* @@ -6919,11 +8038,11 @@ */ void API dw_listbox_clear(HWND handle) { - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; GetClassName(handle, tmpbuf, 99); - if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1)==0) { char *buf = dw_window_get_text(handle); @@ -6950,11 +8069,11 @@ */ void API dw_listbox_set_text(HWND handle, unsigned int index, char *buffer) { - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; GetClassName(handle, tmpbuf, 99); - if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1)==0) { SendMessage(handle, CB_DELETESTRING, (WPARAM)index, 0); SendMessage(handle, CB_INSERTSTRING, (WPARAM)index, (LPARAM)buffer); @@ -6979,31 +8098,35 @@ */ void API dw_listbox_get_text(HWND handle, unsigned int index, char *buffer, unsigned int length) { - char tmpbuf[100]; - int len; + TCHAR tmpbuf[100] = {0}, *wbuffer; + unsigned int len; + + buffer[0] = 0; if(!buffer || !length) return; - buffer[0] = 0; - GetClassName(handle, tmpbuf, 99); - if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1)==0) { len = (int)SendMessage(handle, CB_GETLBTEXTLEN, (WPARAM)index, 0); - if(len < length && len != CB_ERR) - SendMessage(handle, - CB_GETLBTEXT, (WPARAM)index, (LPARAM)buffer); + if(len != CB_ERR && (wbuffer = _alloca((len+1)*sizeof(TCHAR)))) + { + SendMessage(handle, CB_GETLBTEXT, (WPARAM)index, (LPARAM)wbuffer); + strncpy(buffer, WideToUTF8(wbuffer), length); + } } else { len = (int)SendMessage(handle, LB_GETTEXTLEN, (WPARAM)index, 0); - if(len < length && len != LB_ERR) - SendMessage(handle, - LB_GETTEXT, (WPARAM)index, (LPARAM)buffer); + if(len != LB_ERR && (wbuffer = _alloca((len+1)*sizeof(TCHAR)))) + { + SendMessage(handle, LB_GETTEXT, (WPARAM)index, (LPARAM)wbuffer); + strncpy(buffer, WideToUTF8(wbuffer), length); + } } } @@ -7014,11 +8137,11 @@ */ int API dw_listbox_selected(HWND handle) { - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; GetClassName(handle, tmpbuf, 99); - if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1)==0) return (unsigned int)SendMessage(handle, CB_GETCURSEL, 0, 0); @@ -7037,12 +8160,12 @@ int API dw_listbox_selected_multi(HWND handle, int where) { int *array, count, z; - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; GetClassName(handle, tmpbuf, 99); /* This doesn't work on comboboxes */ - if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1)==0) return -1; count = (int)SendMessage(handle, LB_GETSELCOUNT, 0, 0); @@ -7080,11 +8203,11 @@ */ void API dw_listbox_select(HWND handle, int index, int state) { - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; GetClassName(handle, tmpbuf, 99); - if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1)==0) SendMessage(handle, CB_SETCURSEL, (WPARAM)index, 0); else { @@ -7102,11 +8225,11 @@ */ void API dw_listbox_delete(HWND handle, int index) { - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; GetClassName(handle, tmpbuf, 99); - if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1)==0) SendMessage(handle, CB_DELETESTRING, (WPARAM)index, 0); else SendMessage(handle, LB_DELETESTRING, (WPARAM)index, 0); @@ -7119,11 +8242,11 @@ */ int API dw_listbox_count(HWND handle) { - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; GetClassName(handle, tmpbuf, 99); - if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1)==0) return (int)SendMessage(handle, CB_GETCOUNT,0L, 0L); @@ -7139,12 +8262,12 @@ */ void API dw_listbox_set_top(HWND handle, int top) { - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; GetClassName(handle, tmpbuf, 99); /* This doesn't work on comboboxes */ - if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME)+1)==0) + if(_tcsnicmp(tmpbuf, COMBOBOXCLASSNAME, _tcslen(COMBOBOXCLASSNAME)+1)==0) return; SendMessage(handle, LB_SETTOPINDEX, (WPARAM)top, 0); @@ -7160,19 +8283,19 @@ unsigned int API dw_mle_import(HWND handle, char *buffer, int startpoint) { int textlen, len = GetWindowTextLength(handle); - char *tmpbuf; + TCHAR *tmpbuf, *srcbuf = UTF8toWide(buffer); if(startpoint < 0) startpoint = 0; - if(!buffer || (textlen = strlen(buffer)) < 1) + if(!buffer || (textlen = (int)_tcslen(srcbuf)) < 1) return startpoint; - tmpbuf = calloc(1, len + textlen + startpoint + 2); + tmpbuf = calloc(sizeof(TCHAR), len + textlen + startpoint + 2); if(len) { - char *dest, *start; + TCHAR *dest, *start; int copylen = len - startpoint; GetWindowText(handle, tmpbuf, len+1); @@ -7181,9 +8304,9 @@ start = &tmpbuf[startpoint]; if(copylen > 0) - memcpy(dest, start, copylen); - } - memcpy(&tmpbuf[startpoint], buffer, textlen); + memcpy(dest, start, copylen*sizeof(TCHAR)); + } + memcpy(&tmpbuf[startpoint], srcbuf, textlen*sizeof(TCHAR)); SetWindowText(handle, tmpbuf); @@ -7202,7 +8325,7 @@ void API dw_mle_export(HWND handle, char *buffer, int startpoint, int length) { int max, len = GetWindowTextLength(handle); - char *tmpbuf = calloc(1, len+2); + TCHAR *tmpbuf = calloc(sizeof(TCHAR), len+2); if(len) GetWindowText(handle, tmpbuf, len+1); @@ -7213,7 +8336,7 @@ { max = MIN(length, len - startpoint); - memcpy(buffer, &tmpbuf[startpoint], max); + memcpy(buffer, WideToUTF8(&tmpbuf[startpoint]), max); buffer[max] = '\0'; } @@ -7245,13 +8368,13 @@ void API dw_mle_delete(HWND handle, int startpoint, int length) { int len = GetWindowTextLength(handle); - char *tmpbuf = calloc(1, len+2); + TCHAR *tmpbuf = calloc(sizeof(TCHAR), len+2); GetWindowText(handle, tmpbuf, len+1); if(startpoint + length < len) { - strcpy(&tmpbuf[startpoint], &tmpbuf[startpoint+length]); + _tcscpy(&tmpbuf[startpoint], &tmpbuf[startpoint+length]); SetWindowText(handle, tmpbuf); } @@ -7266,7 +8389,7 @@ */ void API dw_mle_clear(HWND handle) { - SetWindowText(handle, ""); + SetWindowText(handle, TEXT("")); } /* @@ -7300,13 +8423,21 @@ */ void API dw_mle_set_word_wrap(HWND handle, int state) { - /* If ES_AUTOHSCROLL is not set and there is not + /* If ES_AUTOHSCROLL is not set and there is no * horizontal scrollbar it word wraps. */ if(state) dw_window_set_style(handle, 0, ES_AUTOHSCROLL); else dw_window_set_style(handle, ES_AUTOHSCROLL, ES_AUTOHSCROLL); + /* If it is a rich edit control use the rich edit message */ + if(hrichedit) + { + if(state) + SendMessage(handle, EM_SETOPTIONS, (WPARAM)ECOOP_AND, (LPARAM)~ECO_AUTOHSCROLL); + else + SendMessage(handle, EM_SETOPTIONS, (WPARAM)ECOOP_OR, (LPARAM)ECO_AUTOHSCROLL); + } } /* @@ -7332,18 +8463,19 @@ int API dw_mle_search(HWND handle, char *text, int point, unsigned long flags) { int len = GetWindowTextLength(handle); - char *tmpbuf = calloc(1, len+2); + TCHAR *tmpbuf = calloc(sizeof(TCHAR), len+2); + TCHAR *searchtext = UTF8toWide(text); int z, textlen, retval = 0; GetWindowText(handle, tmpbuf, len+1); - textlen = strlen(text); + textlen = (int)strlen(text); if(flags & DW_MLE_CASESENSITIVE) { for(z=point;z<(len-textlen) && !retval;z++) { - if(strncmp(&tmpbuf[z], text, textlen) == 0) + if(_tcsncmp(&tmpbuf[z], searchtext, textlen) == 0) retval = z + textlen; } } @@ -7351,7 +8483,7 @@ { for(z=point;z<(len-textlen) && !retval;z++) { - if(strnicmp(&tmpbuf[z], text, textlen) == 0) + if(_tcsnicmp(&tmpbuf[z], searchtext, textlen) == 0) retval = z + textlen; } } @@ -7506,10 +8638,10 @@ */ void API dw_spinbutton_set_pos(HWND handle, long position) { - char tmpbuf[101] = {0}; + TCHAR tmpbuf[101] = {0}; ColorInfo *cinfo = (ColorInfo *)GetWindowLongPtr(handle, GWLP_USERDATA); - _snprintf(tmpbuf, 100, "%ld", position); + _sntprintf(tmpbuf, 100, TEXT("%ld"), position); if(cinfo && cinfo->buddy) SetWindowText(cinfo->buddy, tmpbuf); @@ -7565,15 +8697,13 @@ /* This function unchecks all radiobuttons on a box */ BOOL CALLBACK _uncheck_radios(HWND handle, LPARAM lParam) { - char tmpbuf[100]; + TCHAR tmpbuf[100] = {0}; GetClassName(handle, tmpbuf, 99); - if(strnicmp(tmpbuf, BUTTONCLASSNAME, strlen(BUTTONCLASSNAME)+1)==0) - { - BubbleButton *bubble= (BubbleButton *)GetWindowLongPtr(handle, GWLP_USERDATA); - - if(bubble && !bubble->checkbox) + if(_tcsnicmp(tmpbuf, BUTTONCLASSNAME, _tcslen(BUTTONCLASSNAME)+1)==0) + { + if(!dw_window_get_data(handle, "_dw_checkbox")) SendMessage(handle, BM_SETCHECK, 0, 0); } return TRUE; @@ -7586,9 +8716,7 @@ */ void API dw_checkbox_set(HWND handle, int value) { - BubbleButton *bubble= (BubbleButton *)GetWindowLongPtr(handle, GWLP_USERDATA); - - if(bubble && !bubble->checkbox) + if(!dw_window_get_data(handle, "_dw_checkbox")) { HWND parent = GetParent(handle); @@ -7619,9 +8747,9 @@ ptrs[1] = itemdata; tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; - tvi.pszText = title; + tvi.pszText = UTF8toWide(title); tvi.lParam = (LONG)ptrs; - tvi.cchTextMax = strlen(title); + tvi.cchTextMax = (int)_tcslen(tvi.pszText); tvi.iSelectedImage = tvi.iImage = _lookup_icon(handle, (HICON)icon, 1); tvins.item = tvi; @@ -7653,9 +8781,9 @@ ptrs[1] = itemdata; tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; - tvi.pszText = title; + tvi.pszText = UTF8toWide(title); tvi.lParam = (LONG)ptrs; - tvi.cchTextMax = strlen(title); + tvi.cchTextMax = (int)_tcslen(tvi.pszText); tvi.iSelectedImage = tvi.iImage = _lookup_icon(handle, (HICON)icon, 1); tvins.item = tvi; @@ -7690,8 +8818,8 @@ ptrs[0] = title; tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE; - tvi.pszText = title; - tvi.cchTextMax = strlen(title); + tvi.pszText = UTF8toWide(title); + tvi.cchTextMax = (int)_tcslen(tvi.pszText); tvi.iSelectedImage = tvi.iImage = _lookup_icon(handle, (HICON)icon, 1); tvi.hItem = (HTREEITEM)item; @@ -7757,7 +8885,7 @@ tvi.hItem = item; if(TreeView_GetItem(handle, &tvi)) - return tvi.pszText; + return _strdup(WideToUTF8(tvi.pszText)); return NULL; } @@ -7780,9 +8908,7 @@ */ void API dw_tree_item_select(HWND handle, HTREEITEM item) { - dw_window_set_data(handle, "_dw_select_item", (void *)1); TreeView_SelectItem(handle, item); - dw_window_set_data(handle, "_dw_select_item", (void *)0); } /* Delete all tree subitems */ @@ -7904,8 +9030,8 @@ if(titles[z]) { lvc.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM | LVCF_FMT; - lvc.pszText = titles[z]; - lvc.cchTextMax = strlen(titles[z]); + lvc.pszText = UTF8toWide(titles[z]); + lvc.cchTextMax = (int)_tcslen(lvc.pszText); if(flags[z] & DW_CFA_RIGHT) lvc.fmt = LVCFMT_RIGHT; else if(flags[z] & DW_CFA_CENTER) @@ -7922,6 +9048,19 @@ } /* + * Configures the main filesystem column title for localization. + * Parameters: + * handle: Handle to the container to be configured. + * title: The title to be displayed in the main column. + */ +void API dw_filesystem_set_column_title(HWND handle, char *title) +{ + char *newtitle = _strdup(title ? title : ""); + + dw_window_set_data(handle, "_dw_coltitle", newtitle); +} + +/* * Sets up the filesystem columns, note: filesystem always has an icon/filename field. * Parameters: * handle: Handle to the container to be configured. @@ -7931,10 +9070,11 @@ */ int API dw_filesystem_setup(HWND handle, unsigned long *flags, char **titles, int count) { + char *coltitle = (char *)dw_window_get_data(handle, "_dw_coltitle"); LV_COLUMN lvc; lvc.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; - lvc.pszText = "Filename"; + lvc.pszText = coltitle ? UTF8toWide(coltitle) : TEXT("Filename"); lvc.cchTextMax = 8; lvc.fmt = 0; if(!count) @@ -7944,6 +9084,11 @@ lvc.iSubItem = count; SendMessage(handle, LVM_INSERTCOLUMN, (WPARAM)0, (LPARAM)&lvc); dw_container_setup(handle, flags, titles, count, -1); + if(coltitle) + { + dw_window_set_data(handle, "_dw_coltitle", NULL); + free(coltitle); + } return DW_ERROR_NONE; } @@ -7991,7 +9136,7 @@ return 0; } } - icon = LoadImage(NULL, file, IMAGE_ICON, 0, 0, LR_LOADFROMFILE); + icon = LoadImage(NULL, UTF8toWide(file), IMAGE_ICON, 0, 0, LR_LOADFROMFILE); free(file); return (HICN)icon; #endif @@ -8023,16 +9168,16 @@ #ifdef GDIPLUS icon = _dw_load_icon(file); #else - icon = LoadImage( NULL, file, IMAGE_ICON, 0, 0, LR_LOADFROMFILE ); + icon = LoadImage( NULL, UTF8toWide(file), IMAGE_ICON, 0, 0, LR_LOADFROMFILE ); #endif } else { - unlink( file ); + _unlink( file ); free( file ); return 0; } - unlink( file ); + _unlink( file ); free( file ); } return (HICN)icon; @@ -8063,7 +9208,7 @@ lvi.iSubItem = 0; /* Insert at the end */ lvi.iItem = 1000000; - lvi.pszText = ""; + lvi.pszText = TEXT(""); lvi.cchTextMax = 1; lvi.iImage = -1; @@ -8082,7 +9227,12 @@ { int z; static HWND lasthwnd = NULL; - + HIMAGELIST himl; + + /* We can't add an invalid handle */ + if(!hicon) + return -1; + if(!hSmall || !hLarge) { hSmall = ImageList_Create(16, 16, ILC_COLOR16 | ILC_MASK, ICON_INDEX_LIMIT, 0); @@ -8097,12 +9247,12 @@ ImageList_AddIcon(hLarge, hicon); if(type) { - TreeView_SetImageList(handle, hSmall, TVSIL_NORMAL); + himl = TreeView_SetImageList(handle, hSmall, TVSIL_NORMAL); } else { - ListView_SetImageList(handle, hSmall, LVSIL_SMALL); - ListView_SetImageList(handle, hLarge, LVSIL_NORMAL); + himl = ListView_SetImageList(handle, hSmall, LVSIL_SMALL); + himl = ListView_SetImageList(handle, hLarge, LVSIL_NORMAL); } lasthwnd = handle; return z; @@ -8114,14 +9264,14 @@ { if(type) { - TreeView_SetImageList(handle, hSmall, TVSIL_NORMAL); + himl = TreeView_SetImageList(handle, hSmall, TVSIL_NORMAL); } else { - ListView_SetImageList(handle, hSmall, LVSIL_SMALL); - ListView_SetImageList(handle, hLarge, LVSIL_NORMAL); + himl = ListView_SetImageList(handle, hSmall, LVSIL_SMALL); + himl = ListView_SetImageList(handle, hLarge, LVSIL_NORMAL); } - lasthwnd = handle; + lasthwnd = handle; } return z; } @@ -8151,8 +9301,8 @@ lvi.iItem = row + item; lvi.iSubItem = 0; lvi.mask = LVIF_DI_SETITEM | LVIF_IMAGE | LVIF_TEXT; - lvi.pszText = filename; - lvi.cchTextMax = strlen(filename); + lvi.pszText = UTF8toWide(filename); + lvi.cchTextMax = (int)_tcslen(lvi.pszText); lvi.iImage = _lookup_icon(handle, (HICON)icon, 0); ListView_SetItem(handle, &lvi); @@ -8186,7 +9336,7 @@ ContainerInfo *cinfo = (ContainerInfo *)GetWindowLongPtr(handle, GWLP_USERDATA); ULONG *flags; LV_ITEM lvi; - char textbuffer[101] = {0}, *destptr = textbuffer; + TCHAR textbuffer[101] = {0}; int item = 0; if(pointer) @@ -8194,7 +9344,7 @@ item = (int)dw_window_get_data(handle, "_dw_insertitem"); } - if(!cinfo || !cinfo->flags || !data) + if(!cinfo || !cinfo->flags) return; flags = cinfo->flags; @@ -8202,38 +9352,42 @@ lvi.mask = LVIF_DI_SETITEM | LVIF_TEXT; lvi.iItem = row + item; lvi.iSubItem = column; + lvi.pszText = textbuffer; + lvi.cchTextMax = 0; if(flags[column] & DW_CFA_BITMAPORICON) { - HICON hicon = *((HICON *)data); - lvi.mask = LVIF_DI_SETITEM | LVIF_IMAGE; lvi.pszText = NULL; - lvi.cchTextMax = 0; - - lvi.iImage = _lookup_icon(handle, hicon, 0); - } - else if(flags[column] & DW_CFA_STRING) + + if(data) + { + HICON hicon = *((HICON *)data); + + lvi.iImage = _lookup_icon(handle, hicon, 0); + } + else + lvi.iImage = -1; + } + else if(flags[column] & DW_CFA_STRING && data) { char *tmp = *((char **)data); if(!tmp) tmp = ""; - lvi.pszText = tmp; - lvi.cchTextMax = strlen(tmp); - destptr = tmp; - } - else if(flags[column] & DW_CFA_ULONG) + lvi.pszText = UTF8toWide(tmp); + lvi.cchTextMax = (int)_tcslen(lvi.pszText); + } + else if(flags[column] & DW_CFA_ULONG && data) { ULONG tmp = *((ULONG *)data); - _snprintf(textbuffer, 100, "%lu", tmp); - - lvi.pszText = textbuffer; - lvi.cchTextMax = strlen(textbuffer); - } - else if(flags[column] & DW_CFA_DATE) + _sntprintf(textbuffer, 100, TEXT("%lu"), tmp); + + lvi.cchTextMax = (int)_tcslen(textbuffer); + } + else if(flags[column] & DW_CFA_DATE && data) { struct tm curtm; CDATE cdate = *((CDATE *)data); @@ -8248,17 +9402,12 @@ curtm.tm_mday = (cdate.day >= 0 && cdate.day < 32) ? cdate.day : 1; curtm.tm_mon = (cdate.month > 0 && cdate.month < 13) ? cdate.month - 1 : 0; curtm.tm_year = cdate.year - 1900; - strftime(textbuffer, 100, "%x", &curtm); - } - else - { - textbuffer[0] = 0; - } - - lvi.pszText = textbuffer; - lvi.cchTextMax = strlen(textbuffer); - } - else if(flags[column] & DW_CFA_TIME) + _tcsftime(textbuffer, 100, TEXT("%x"), &curtm); + } + + lvi.cchTextMax = (int)_tcslen(textbuffer); + } + else if(flags[column] & DW_CFA_TIME && data) { struct tm curtm; CTIME ctime = *((CTIME *)data); @@ -8267,10 +9416,9 @@ curtm.tm_min = (ctime.minutes >= 0 && ctime.minutes < 60) ? ctime.minutes : 0; curtm.tm_sec = (ctime.seconds >= 0 && ctime.seconds < 60) ? ctime.seconds : 0; - strftime(textbuffer, 100, "%X", &curtm); - - lvi.pszText = textbuffer; - lvi.cchTextMax = strlen(textbuffer); + _tcsftime(textbuffer, 100, TEXT("%X"), &curtm); + + lvi.cchTextMax = (int)_tcslen(textbuffer); } ListView_SetItem(handle, &lvi); @@ -8658,9 +9806,10 @@ } else if(cinfo && cinfo->columns > 1) { - int z, index; ULONG *flags = cinfo->flags, *columns = calloc(sizeof(ULONG), cinfo->columns); - char *text = malloc(1024); + TCHAR *text = calloc(sizeof(TCHAR), 1024); + unsigned int z; + int index; /* Initialize with sizes of column labels */ for(z=0;z<cinfo->columns;z++) @@ -8690,33 +9839,26 @@ { for(z=0;z<cinfo->columns;z++) { - LV_ITEM lvi; - - memset(&lvi, 0, sizeof(LV_ITEM)); - - lvi.iItem = index; - lvi.iSubItem = z; - lvi.mask = LVIF_TEXT; - lvi.cchTextMax = 1023; - lvi.pszText = text; - - if(ListView_GetItem(handle, &lvi)) - { - int width = ListView_GetStringWidth(handle, lvi.pszText); - if(width > columns[z]) - { - if(z == 0) - columns[z] = width + 20; - else - columns[z] = width; - } - } + unsigned int width; + + ListView_GetItemText(handle, index, z, text, 1023); + width = ListView_GetStringWidth(handle, text); + + /* Figure extra space for the icon for the first column */ + if(z == 0) + width += 20; + + if(width > columns[z]) + columns[z] = width; } index = ListView_GetNextItem(handle, index, LVNI_ALL); } - /* Set the new sizes */ + /* Set the new sizes... Microsoft says we need to add + * padding to the calculated sized but does not give + * a value. Trial and error shows that 16 works for us. + */ for(z=0;z<cinfo->columns;z++) ListView_SetColumnWidth(handle, z, columns[z] + 16); @@ -8743,7 +9885,7 @@ tnid.uCallbackMessage = WM_USER+2; tnid.hIcon = (HICON)icon; if(bubbletext) - strncpy(tnid.szTip, bubbletext, sizeof(tnid.szTip)); + _tcsncpy(tnid.szTip, UTF8toWide(bubbletext), sizeof(tnid.szTip)); else tnid.szTip[0] = 0; @@ -8778,9 +9920,9 @@ { Box *newbox = calloc(sizeof(Box), 1); HWND tmp = CreateWindow(ObjectClassName, - "", + NULL, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN, - 0,0,screenx,screeny, + 0,0,0,0, DW_HWND_OBJECT, (HMENU)id, DWInstance, @@ -8806,9 +9948,22 @@ HPEN hPen = TlsGetValue(_hPen); HBRUSH hBrush = TlsGetValue(_hBrush); COLORREF foreground; +#ifdef GDIPLUS + GpBrush *brush = TlsGetValue(_gpBrush); + GpPen *pen = TlsGetValue(_gpPen); + ARGB gpfore; +#endif value = _internal_color(value); foreground = RGB(DW_RED_VALUE(value), DW_GREEN_VALUE(value), DW_BLUE_VALUE(value)); +#ifdef GDIPLUS + gpfore = MAKEARGB(255, DW_RED_VALUE(value), DW_GREEN_VALUE(value), DW_BLUE_VALUE(value)); + + GdipDeletePen(pen); + GdipCreatePen1(gpfore, 1.0, UnitPixel, &pen); + TlsSetValue(_gpPen, (LPVOID)pen); + GdipSetSolidFillColor(brush, gpfore); +#endif DeleteObject(hPen); DeleteObject(hBrush); @@ -8873,6 +10028,12 @@ */ void API dw_draw_point(HWND handle, HPIXMAP pixmap, int x, int y) { +#ifdef GDIPLUS + /* There doesn't seem to be an equivalent to SetPixel in GDI+ ... + * so instead we call dw_draw_rect() with 1 for width and height. + */ + dw_draw_rect(handle, pixmap, DW_DRAW_FILL | DW_DRAW_NOAA, x, y, 1, 1); +#else HDC hdcPaint; if(handle) @@ -8885,6 +10046,7 @@ SetPixel(hdcPaint, x, y, (COLORREF)TlsGetValue(_foreground)); if(!pixmap) ReleaseDC(handle, hdcPaint); +#endif } /* Draw a line on a window (preferably a render window). @@ -8898,6 +10060,21 @@ */ void API dw_draw_line(HWND handle, HPIXMAP pixmap, int x1, int y1, int x2, int y2) { +#ifdef GDIPLUS + GpGraphics *graphics = NULL; + GpPen *pen = TlsGetValue(_gpPen); + + if(handle) + GdipCreateFromHWND(handle, &graphics); + else if(pixmap) + GdipCreateFromHDC(pixmap->hdc, &graphics); + else + return; + + GdipSetSmoothingMode(graphics, SmoothingModeAntiAlias); + GdipDrawLineI(graphics, pen, x1, y1, x2, y2); + GdipDeleteGraphics(graphics); +#else HDC hdcPaint; HPEN oldPen; @@ -8918,6 +10095,40 @@ SetPixel(hdcPaint, x2, y2, (COLORREF)TlsGetValue(_foreground)); if(!pixmap) ReleaseDC(handle, hdcPaint); +#endif +} + +/* Internal function to generate POINT arrays used by Windows APIs */ +POINT *_makePoints(int *npoints, int *x, int *y) +{ + POINT *points; + int i; + + /* + * Allocate enough space for the number of points supplied plus 1. + * Under windows, unless the first and last points are the same + * the polygon won't be closed + */ + points = (POINT *)malloc( ((*npoints)+1) * sizeof(POINT) ); + + if(points) + { + for ( i = 0 ; i < *npoints ; i++ ) + { + points[i].x = x[i]; + points[i].y = y[i]; + } + if ( !( points[0].x == points[(*npoints)-1].x + && points[0].y == points[(*npoints)-1].y ) ) + { + /* set the last point to be the same as the first point... */ + points[*npoints].x = points[0].x; + points[*npoints].y = points[0].y; + /* ... and increment the number of points */ + (*npoints)++; + } + } + return points; } /* Draw a closed polygon on a window (preferably a render window). @@ -8931,58 +10142,75 @@ */ void API dw_draw_polygon(HWND handle, HPIXMAP pixmap, int flags, int npoints, int *x, int *y) { - HDC hdcPaint; - HBRUSH oldBrush; - HPEN oldPen; POINT *points = NULL; - int i; - - if ( handle ) - hdcPaint = GetDC( handle ); - else if ( pixmap ) - hdcPaint = pixmap->hdc; - else + + /* Sanity check */ + if(npoints < 1) return; - if ( npoints ) - { - /* - * Allocate enough space for the number of points supplied plus 1. - * Under windows, unless the first and last points are the same - * the polygon won't be closed - */ - points = (POINT *)malloc( (npoints+1) * sizeof(POINT) ); - /* - * should check for NULL pointer return! - */ - for ( i = 0 ; i < npoints ; i++ ) - { - points[i].x = x[i]; - points[i].y = y[i]; - } - if ( !( points[0].x == points[npoints-1].x - && points[0].y == points[npoints-1].y ) ) - { - /* set the last point to be the same as the first point... */ - points[npoints].x = points[0].x; - points[npoints].y = points[0].y; - /* ... and increment the number of points */ - npoints++; - } - } - else - return; - - oldBrush = SelectObject( hdcPaint, TlsGetValue(_hBrush) ); - oldPen = SelectObject( hdcPaint, TlsGetValue(_hPen) ); - if ( flags & DW_DRAW_FILL ) - Polygon( hdcPaint, points, npoints ); - else - Polyline( hdcPaint, points, npoints ); - SelectObject( hdcPaint, oldBrush ); - SelectObject( hdcPaint, oldPen ); - if ( !pixmap ) - ReleaseDC( handle, hdcPaint ); - free(points); + +#ifdef GDIPLUS + { + GpGraphics *graphics = NULL; + + if(handle) + GdipCreateFromHWND(handle, &graphics); + else if(pixmap) + GdipCreateFromHDC(pixmap->hdc, &graphics); + else + return; + + /* Enable antialiasing if the DW_DRAW_NOAA flag isn't set */ + if(!(flags & DW_DRAW_NOAA)) + GdipSetSmoothingMode(graphics, SmoothingModeAntiAlias); + + if((points = _makePoints(&npoints, x, y))) + { + if(flags & DW_DRAW_FILL) + { + GpBrush *brush = TlsGetValue(_gpBrush); + + GdipFillPolygon2I(graphics, brush, points, npoints); + } + else + { + GpPen *pen = TlsGetValue(_gpPen); + + GdipDrawPolygonI(graphics, pen, points, npoints); + } + } + GdipDeleteGraphics(graphics); + } +#else + { + HDC hdcPaint; + + if ( handle ) + hdcPaint = GetDC( handle ); + else if ( pixmap ) + hdcPaint = pixmap->hdc; + else + return; + + if((points = _makePoints(&npoints, x, y))) + { + HBRUSH oldBrush = SelectObject( hdcPaint, TlsGetValue(_hBrush) ); + HPEN oldPen = SelectObject( hdcPaint, TlsGetValue(_hPen) ); + + if ( flags & DW_DRAW_FILL ) + Polygon( hdcPaint, points, npoints ); + else + Polyline( hdcPaint, points, npoints ); + + SelectObject( hdcPaint, oldBrush ); + SelectObject( hdcPaint, oldPen ); + } + + if ( !pixmap ) + ReleaseDC( handle, hdcPaint ); + } +#endif + if(points) + free(points); } /* Draw a rectangle on a window (preferably a render window). @@ -8997,6 +10225,34 @@ */ void API dw_draw_rect(HWND handle, HPIXMAP pixmap, int flags, int x, int y, int width, int height) { +#ifdef GDIPLUS + GpGraphics *graphics = NULL; + + if(handle) + GdipCreateFromHWND(handle, &graphics); + else if(pixmap) + GdipCreateFromHDC(pixmap->hdc, &graphics); + else + return; + + /* Enable antialiasing if the DW_DRAW_NOAA flag isn't set */ + if(!(flags & DW_DRAW_NOAA)) + GdipSetSmoothingMode(graphics, SmoothingModeAntiAlias); + + if(flags & DW_DRAW_FILL) + { + GpBrush *brush = TlsGetValue(_gpBrush); + + GdipFillRectangleI(graphics, brush, x, y, width, height); + } + else + { + GpPen *pen = TlsGetValue(_gpPen); + + GdipDrawRectangleI(graphics, pen, x, y, width, height); + } + GdipDeleteGraphics(graphics); +#else HDC hdcPaint; RECT Rect; @@ -9014,6 +10270,7 @@ FrameRect(hdcPaint, &Rect, TlsGetValue(_hBrush)); if(!pixmap) ReleaseDC(handle, hdcPaint); +#endif } /* Draw an arc on a window (preferably a render window). @@ -9031,12 +10288,58 @@ */ void API dw_draw_arc(HWND handle, HPIXMAP pixmap, int flags, int xorigin, int yorigin, int x1, int y1, int x2, int y2) { +#ifdef GDIPLUS + GpGraphics *graphics = NULL; + GpPen *pen = TlsGetValue(_gpPen); + + if(handle) + GdipCreateFromHWND(handle, &graphics); + else if(pixmap) + GdipCreateFromHDC(pixmap->hdc, &graphics); + else + return; + + /* Enable antialiasing if the DW_DRAW_NOAA flag isn't set */ + if(!(flags & DW_DRAW_NOAA)) + GdipSetSmoothingMode(graphics, SmoothingModeAntiAlias); + + if(flags & DW_DRAW_FULL) + { + if(flags & DW_DRAW_FILL) + { + GpBrush *brush = TlsGetValue(_gpBrush); + + GdipFillEllipseI(graphics, brush, x1 < x2 ? x1 : x2, y1 < y2 ? y1 : y2, abs(x1-x2), abs(y1-y2)); + } + else + GdipDrawEllipseI(graphics, pen, x1 < x2 ? x1 : x2, y1 < y2 ? y1 : y2, abs(x1-x2), abs(y1-y2)); + } + else + { + double a1 = atan2((y1-yorigin), (x1-xorigin)); + double a2 = atan2((y2-yorigin), (x2-xorigin)); + double dx = xorigin - x1; + double dy = yorigin - y1; + double r = sqrt(dx*dx + dy*dy); + double sweep; + int ri = (int)r; + + /* Convert to degrees */ + a1 *= (180.0 / M_PI); + a2 *= (180.0 / M_PI); + sweep = fabs(a1 - a2); + + GdipDrawArcI(graphics, pen, xorigin-ri, yorigin-ri, ri*2, ri*2, (REAL)a1, (REAL)sweep); + } + GdipDeleteGraphics(graphics); +#else HDC hdcPaint; HBRUSH oldBrush; HPEN oldPen; double dx = xorigin - x1; double dy = yorigin - y1; double r = sqrt(dx*dx + dy*dy); + int ri = (int)r; if(handle) hdcPaint = GetDC(handle); @@ -9053,13 +10356,42 @@ if(flags & DW_DRAW_FULL) Ellipse(hdcPaint, x1, y1, x2, y2); else - Arc(hdcPaint, xorigin-r, yorigin-r, xorigin+r, yorigin+r, x2, y2, x1, y1); + Arc(hdcPaint, xorigin-ri, yorigin-ri, xorigin+ri, yorigin+ri, x2, y2, x1, y1); SelectObject( hdcPaint, oldBrush ); SelectObject( hdcPaint, oldPen ); if(!pixmap) ReleaseDC(handle, hdcPaint); -} +#endif +} + +#ifdef GDIPLUS +/* Internal function to increase or decrease coordinates/sizes + * by the difference of the screen DPI (96) and the context DPI. + */ +void _convert_dpi(HDC hdc, int *x, int *y, int mult) +{ + int ratiox = (int)GetDeviceCaps(hdc, LOGPIXELSX)/96; + int ratioy = (int)GetDeviceCaps(hdc, LOGPIXELSY)/96; + if(ratiox > 1 && ratioy > 1) + { + if(mult) + { + if(x) + *x *= ratiox; + if(y) + *y *= ratioy; + } + else + { + if(x) + *x /= ratiox; + if(y) + *y /= ratioy; + } + } +} +#endif /* Draw text on a window (preferably a render window). * Parameters: @@ -9076,6 +10408,7 @@ HFONT hFont = 0, oldFont = 0; ColorInfo *cinfo = NULL; COLORREF background; + TCHAR *wtext = UTF8toWide(text); if(handle) hdc = GetDC(handle); @@ -9108,7 +10441,10 @@ SetBkMode(hdc, OPAQUE); SetBkColor(hdc, background); } - TextOut(hdc, x, y, text, strlen(text)); +#ifdef GDIPLUS + _convert_dpi(hdc, &x, &y, TRUE); +#endif + TextOut(hdc, x, y, wtext, (int)_tcslen(wtext)); if(oldFont) SelectObject(hdc, oldFont); if(mustdelete) @@ -9131,6 +10467,7 @@ int mustdelete = 0; HFONT hFont = NULL, oldFont; SIZE sz; + TCHAR *wtext = UTF8toWide(text); if(handle) hdc = GetDC(handle); @@ -9160,7 +10497,7 @@ } oldFont = SelectObject(hdc, hFont); - GetTextExtentPoint32(hdc, text, strlen(text), &sz); + GetTextExtentPoint32(hdc, wtext, (int)_tcslen(wtext), &sz); if(width) *width = sz.cx; @@ -9168,6 +10505,10 @@ if(height) *height = sz.cy; +#ifdef GDIPLUS + _convert_dpi(hdc, width, height, FALSE); +#endif + SelectObject(hdc, oldFont); if(mustdelete) DeleteObject(hFont); @@ -9308,7 +10649,7 @@ } } - pixmap->hbm = (HBITMAP)LoadImage(NULL, file, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); + pixmap->hbm = (HBITMAP)LoadImage(NULL, UTF8toWide(file), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); pixmap->depth = _read_bitmap_header(file); #endif @@ -9370,18 +10711,18 @@ #ifdef GDIPLUS pixmap->hbm = _dw_load_bitmap(file, NULL); #else - pixmap->hbm = (HBITMAP)LoadImage( NULL, file, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); + pixmap->hbm = (HBITMAP)LoadImage( NULL, UTF8toWide(file), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); pixmap->depth = _read_bitmap_header(file); #endif } else { - unlink( file ); + _unlink( file ); free( file ); free( pixmap ); return NULL; } - unlink( file ); + _unlink( file ); free( file ); } @@ -9567,6 +10908,14 @@ sheight = height; } +#ifdef GDIPLUS + /* Do conversion on all the coordinates */ + _convert_dpi(hdcdest, &xdest, &ydest, TRUE); + _convert_dpi(hdcdest, &width, &height, TRUE); + _convert_dpi(hdcsrc, &xsrc, &ysrc, TRUE); + _convert_dpi(hdcsrc, &swidth, &sheight, TRUE); +#endif + /* If it is a 32bpp bitmap (with alpha) use AlphaBlend unless it fails */ if ( srcp && srcp->depth == 32 && AlphaBlend( hdcdest, xdest, ydest, width, height, hdcsrc, xsrc, ysrc, swidth, sheight, bf ) ) { @@ -9635,7 +10984,7 @@ if(!handle) return DW_ERROR_UNKNOWN; - *handle = LoadLibrary(name); + *handle = LoadLibrary(UTF8toWide(name)); return (NULL == *handle); } @@ -9810,7 +11159,7 @@ sa.lpSecurityDescriptor = &_dwsd; sa.bInheritHandle = FALSE; - return CreateEvent(&sa, TRUE, FALSE, name); + return CreateEvent(&sa, TRUE, FALSE, UTF8toWide(name)); } /* Destroy this semaphore. @@ -9820,7 +11169,7 @@ */ HEV API dw_named_event_get(char *name) { - return OpenEvent(EVENT_ALL_ACCESS, FALSE, name); + return OpenEvent(EVENT_ALL_ACCESS, FALSE, UTF8toWide(name)); } /* Resets the event semaphore so threads who call wait @@ -9901,7 +11250,7 @@ sa.lpSecurityDescriptor = &_dwsd; sa.bInheritHandle = FALSE; - handle = CreateFileMapping((HANDLE)0xFFFFFFFF, &sa, PAGE_READWRITE, 0, size, name); + handle = CreateFileMapping((HANDLE)0xFFFFFFFF, &sa, PAGE_READWRITE, 0, size, UTF8toWide(name)); if(!handle) return 0; @@ -9926,7 +11275,7 @@ */ HSHM API dw_named_memory_get(void **dest, int size, char *name) { - HSHM handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, name); + HSHM handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, UTF8toWide(name)); if(!handle) return 0; @@ -9964,6 +11313,10 @@ void **tmp = (void **)data; HPEN hPen; HBRUSH hBrush; +#ifdef GDIPLUS + GpBrush *brush; + GpPen *pen; +#endif _init_thread(); @@ -9975,6 +11328,12 @@ DeleteObject(hPen); if((hBrush = TlsGetValue(_hBrush))) DeleteObject(hBrush); +#ifdef GDIPLUS + if((brush = TlsGetValue(_gpBrush))) + GdipDeleteBrush(brush); + if((pen = TlsGetValue(_gpPen))) + GdipDeletePen(pen); +#endif } /* @@ -10028,6 +11387,12 @@ void API dw_exit(int exitcode) { OleUninitialize(); +#ifdef AEROGLASS + /* Free any in use libraries */ + FreeLibrary(hdwm); +#endif + FreeLibrary(huxtheme); + DestroyWindow(hwndTooltip); exit(exitcode); } @@ -10043,7 +11408,7 @@ HWND API dw_splitbar_new(int type, HWND topleft, HWND bottomright, unsigned long id) { HWND tmp = CreateWindow(SplitbarClassName, - "", + NULL, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN, 0,0,0,0, DW_HWND_OBJECT, @@ -10087,7 +11452,8 @@ dw_window_get_pos_size(handle, NULL, NULL, &width, &height); - _handle_splitbar_resize(handle, percent, type, width, height); + if(width > 0 && height > 0) + _handle_splitbar_resize(handle, percent, type, width, height); } /* @@ -10120,7 +11486,7 @@ MONTHDAYSTATE mds[3]; HWND tmp = CreateWindowEx(WS_EX_CLIENTEDGE, MONTHCAL_CLASS, - "", + NULL, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | MCS_DAYSTATE, 0,0,0,0, DW_HWND_OBJECT, @@ -10232,20 +11598,26 @@ char * API dw_clipboard_get_text(void) { HANDLE handle; - char *tmp, *ret = NULL; + char *ret = NULL; + TCHAR *tmp; +#ifdef UNICODE + int type = CF_UNICODETEXT; +#else + int type = CF_TEXT; +#endif if ( !OpenClipboard( NULL ) ) return ret; - if ( ( handle = GetClipboardData( CF_TEXT) ) == NULL ) + if ( ( handle = GetClipboardData(type) ) == NULL ) { CloseClipboard(); return ret; } - if ( (tmp = GlobalLock(handle)) && strlen(tmp) ) - { - ret = strdup(tmp); + if ( (tmp = GlobalLock(handle)) && _tcslen(tmp) ) + { + ret = _strdup(WideToUTF8(tmp)); GlobalUnlock(handle); } CloseClipboard(); @@ -10261,6 +11633,20 @@ { HGLOBAL ptr1; LPTSTR ptr2; + TCHAR *buf; +#ifdef UNICODE + int type = CF_UNICODETEXT; + char *src = calloc(len + 1, 1); + + memcpy(src, str, len); + buf = UTF8toWide(src); + free(src); + len = (int)_tcslen(buf); +#else + int type = CF_TEXT; + + buf = str; +#endif if ( !OpenClipboard( NULL ) ) return; @@ -10272,16 +11658,14 @@ ptr2 = GlobalLock( ptr1 ); - memcpy( (char *)ptr2, str, len + 1); + memcpy(ptr2, buf, (len + 1) * sizeof(TCHAR)); GlobalUnlock( ptr1 ); EmptyClipboard(); - SetClipboardData( CF_TEXT, ptr1 ); + SetClipboardData( type, ptr1 ); CloseClipboard(); GlobalFree( ptr1 ); - - return; } /* @@ -10311,8 +11695,10 @@ strcpy(env->osName, "Windows XP"); else if(env->MajorVersion == 6 && env->MinorVersion == 0) strcpy(env->osName, "Windows Vista"); - else if(env->MajorVersion == 6 && env->MinorVersion > 0) + else if(env->MajorVersion == 6 && env->MinorVersion == 1) strcpy(env->osName, "Windows 7"); + else if(env->MajorVersion == 6 && env->MinorVersion > 1) + strcpy(env->osName, "Windows 8"); else strcpy(env->osName, "Windows NT"); @@ -10336,14 +11722,14 @@ } /* Helper to make sure all /s are \s */ -void _to_dos(char *dst, char *src) +void _to_dos(TCHAR *dst, TCHAR *src) { int x = 0; while(src[x]) { - if(src[x] == '/') - dst[x] = '\\'; + if(src[x] == TEXT('/')) + dst[x] = TEXT('\\'); else dst[x] = src[x]; x++; @@ -10351,6 +11737,8 @@ dst[x] = 0; } +#define BROWSEBUFSIZE 1000 + /* * Opens a file dialog and queries user selection. * Parameters: @@ -10365,27 +11753,28 @@ */ char * API dw_file_browse(char *title, char *defpath, char *ext, int flags) { - OPENFILENAME of; - char filenamebuf[1001] = {0}; - char filterbuf[1001] = {0}; + OPENFILENAME of = {0}; + TCHAR filenamebuf[BROWSEBUFSIZE+1] = {0}, *fbuf = filenamebuf; + TCHAR filterbuf[BROWSEBUFSIZE+1] = {0}; + TCHAR *exten = UTF8toWide(ext); + TCHAR *dpath = UTF8toWide(defpath); int rc; if ( flags == DW_DIRECTORY_OPEN ) { /* If we aren't building a DLL, use the more simple browser */ #ifndef BUILD_DLL - BROWSEINFO bi; + BROWSEINFO bi = {0}; TCHAR szDir[MAX_PATH]; LPITEMIDLIST pidl; LPMALLOC pMalloc; if (SUCCEEDED(SHGetMalloc(&pMalloc))) { - ZeroMemory(&bi,sizeof(bi)); bi.hwndOwner = NULL; bi.pszDisplayName = 0; bi.pidlRoot = 0; - bi.lpszTitle = title; + bi.lpszTitle = UTF8toWide(title); bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT; bi.lpfn = NULL; /*BrowseCallbackProc*/ @@ -10394,31 +11783,31 @@ { if (SHGetPathFromIDList(pidl,szDir)) { - strncpy(filenamebuf,szDir,1000); + _tcsncpy(filenamebuf,szDir,BROWSEBUFSIZE); } - // In C++: pMalloc->Free(pidl); pMalloc->Release(); + /* In C++: pMalloc->Free(pidl); pMalloc->Release(); */ pMalloc->lpVtbl->Free(pMalloc,pidl); pMalloc->lpVtbl->Release(pMalloc); - return strdup(filenamebuf); + return _strdup(WideToUTF8(filenamebuf)); } } #else if ( XBrowseForFolder( NULL, - (LPCTSTR)defpath, + (LPCTSTR)dpath, -1, - (LPCTSTR)title, + (LPCTSTR)UTF8toWide(title), (LPTSTR)filenamebuf, - 1000, + BROWSEBUFSIZE, FALSE ) ) { - return strdup( filenamebuf ); + return _strdup( WideToUTF8(fbuf) ); } #endif } else { - DWORD att = defpath ? GetFileAttributes(defpath) : INVALID_FILE_ATTRIBUTES; + DWORD att = defpath ? GetFileAttributes(UTF8toWide(defpath)) : INVALID_FILE_ATTRIBUTES; if (ext) { @@ -10427,15 +11816,16 @@ * and format of filter is eg: "c files (*.c)\0*.c\0All Files\0*.*\0\0" */ int len; - char *ptr = filterbuf; - memset( filterbuf, 0, sizeof(filterbuf) ); - len = sprintf( ptr, "%s Files (*.%s)", ext, ext ); - ptr = ptr + len + 1; // past first \0 - len = sprintf( ptr, "*.%s", ext ); - ptr = ptr + len + 1; // past next \0 - len = sprintf( ptr, "All Files" ); - ptr = ptr + len + 1; // past next \0 - len = sprintf( ptr, "*.*" ); + TCHAR *ptr = filterbuf; + TCHAR *start = filterbuf; + + len = _sntprintf( ptr, BROWSEBUFSIZE - (ptr - start), TEXT("%s Files (*.%s)"), exten, exten ); + ptr = ptr + len + 1; /* past first \0 */ + len = _sntprintf( ptr, BROWSEBUFSIZE - (ptr - start), TEXT("*.%s"), exten ); + ptr = ptr + len + 1; /* past next \0 */ + len = _sntprintf( ptr, BROWSEBUFSIZE - (ptr - start), TEXT("All Files") ); + ptr = ptr + len + 1; /* past next \0 */ + len = _sntprintf( ptr, BROWSEBUFSIZE - (ptr - start), TEXT("*.*") ); } memset( &of, 0, sizeof(OPENFILENAME) ); @@ -10443,16 +11833,16 @@ of.lStructSize = sizeof(OPENFILENAME); of.hwndOwner = HWND_DESKTOP; of.hInstance = DWInstance; - of.lpstrTitle = title; - of.lpstrInitialDir = "."; + of.lpstrTitle = UTF8toWide(title); + of.lpstrInitialDir = TEXT("."); if(att != INVALID_FILE_ATTRIBUTES && (att & FILE_ATTRIBUTE_DIRECTORY)) - of.lpstrInitialDir = defpath; + of.lpstrInitialDir = dpath; else if(defpath) - _to_dos(filenamebuf, defpath); + _to_dos(filenamebuf, dpath); of.lpstrFile = filenamebuf; of.lpstrFilter = filterbuf; of.nFilterIndex = 1; - of.nMaxFile = 1000; + of.nMaxFile = BROWSEBUFSIZE; /*of.lpstrDefExt = ext;*/ of.Flags = OFN_NOCHANGEDIR; @@ -10468,7 +11858,7 @@ } if (rc) - return strdup(of.lpstrFile); + return _strdup(WideToUTF8(of.lpstrFile)); } return NULL; } @@ -10503,7 +11893,8 @@ } newparams[count] = NULL; - retcode = _spawnvp(P_NOWAIT, program, (const char * const *)newparams); + /* Why does this return intptr_t ... can the PID exceed an integer value? */ + retcode = (int)_spawnvp(P_NOWAIT, program, (const char * const *)newparams); for(z=0;z<count;z++) { @@ -10529,7 +11920,7 @@ int len, z; browseurl = &url[7]; - len = strlen(browseurl); + len = (int)strlen(browseurl); for(z=0;z<len;z++) { @@ -10540,7 +11931,7 @@ } } - retcode = (int)ShellExecute(NULL, "open", browseurl, NULL, NULL, SW_SHOWNORMAL); + retcode = (int)ShellExecute(NULL, TEXT("open"), UTF8toWide(browseurl), NULL, NULL, SW_SHOWNORMAL); if(retcode<33 && retcode != 2) return DW_ERROR_UNKNOWN; return DW_ERROR_NONE; @@ -10591,7 +11982,7 @@ } print->di.cbSize = sizeof(DOCINFO); - print->di.lpszDocName = jobname ? jobname : "Dynamic Windows Print Job"; + print->di.lpszDocName = jobname ? UTF8toWide(jobname) : TEXT("Dynamic Windows Print Job"); return print; } @@ -10607,7 +11998,7 @@ { DWPrint *p = print; HPIXMAP pixmap; - int x, result = DW_ERROR_UNKNOWN; + int x, width, height, result = DW_ERROR_UNKNOWN; if(!p) return result; @@ -10615,13 +12006,21 @@ if (!(pixmap = calloc(1,sizeof(struct _hpixmap)))) return result; - pixmap->width = GetDeviceCaps(p->pd.hDC, HORZRES); - pixmap->height = GetDeviceCaps(p->pd.hDC, VERTRES); - - pixmap->hbm = CreateCompatibleBitmap(p->pd.hDC, pixmap->width, pixmap->height); + width = GetDeviceCaps(p->pd.hDC, HORZRES); + height = GetDeviceCaps(p->pd.hDC, VERTRES); + + pixmap->hbm = CreateCompatibleBitmap(p->pd.hDC, width, height); pixmap->hdc = p->pd.hDC; pixmap->transcolor = DW_RGB_TRANSPARENT; +#ifdef GDIPLUS + /* Convert the size based on the DPI */ + _convert_dpi(pixmap->hdc, &width, &height, FALSE); +#endif + + pixmap->width = width; + pixmap->height = height; + SelectObject(pixmap->hdc, pixmap->hbm); /* Start the job */ @@ -10667,7 +12066,7 @@ */ char * API dw_user_dir(void) { - static char _user_dir[1024] = ""; + static char _user_dir[1024] = {0}; if(!_user_dir[0]) { @@ -10677,9 +12076,11 @@ if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { DWORD BufSize = 1024; - - GetUserProfileDirectory(hToken, _user_dir, &BufSize); + TCHAR TmpBuf[1024], *Buf = TmpBuf; + + GetUserProfileDirectory(hToken, Buf, &BufSize); CloseHandle(hToken); + strncpy(_user_dir, WideToUTF8(Buf), 1023); } /* If it fails set it to the root directory */ if(!_user_dir[0]) @@ -10691,6 +12092,15 @@ } /* + * Returns a pointer to a static buffer which containes the + * private application data directory. + */ +char * API dw_app_dir(void) +{ + return _dw_exec_dir; +} + +/* * Call a function from the window (widget)'s context. * Parameters: * handle: Window handle of the widget. @@ -10712,7 +12122,7 @@ while(tmp) { - if(stricmp(tmp->varname, varname) == 0) + if(_stricmp(tmp->varname, varname) == 0) return tmp; tmp = tmp->next; } @@ -10733,7 +12143,7 @@ new = malloc(sizeof(UserData)); if(new) { - new->varname = strdup(varname); + new->varname = _strdup(varname); new->data = data; new->next = NULL; @@ -10763,7 +12173,7 @@ while(tmp) { - if(all || stricmp(tmp->varname, varname) == 0) + if(all || _stricmp(tmp->varname, varname) == 0) { if(!prev) { @@ -10862,7 +12272,10 @@ { if(sigfunc) { - int timerid = SetTimer(NULL, 0, interval, _TimerProc); + /* Warning: This seems to return UINT_PTR on some systems... + * which may exceed the storage of int that our API uses. + */ + int timerid = (int)SetTimer(NULL, 0, interval, _TimerProc); if(timerid) { @@ -10927,7 +12340,7 @@ if (window && signame && sigfunc) { - if (stricmp(signame, DW_SIGNAL_SET_FOCUS) == 0) + if (_stricmp(signame, DW_SIGNAL_SET_FOCUS) == 0) window = _normalize_handle(window); if ((message = _findsigmessage(signame)) != 0) @@ -11061,3 +12474,38 @@ } } } + +/* + * Converts a UTF-8 encoded string into a wide string. + * Parameters: + * utf8string: UTF-8 encoded source string. + * Returns: + * Wide string that needs to be freed with dw_free() + * or NULL on failure. + */ +wchar_t * API dw_utf8_to_wchar(char *utf8string) +{ + #ifdef UNICODE + return _myUTF8toWide(utf8string, malloc(MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, NULL, 0) * sizeof(WCHAR))); +#else + return NULL; +#endif +} + +/* + * Converts a wide string into a UTF-8 encoded string. + * Parameters: + * wstring: Wide source string. + * Returns: + * UTF-8 encoded string that needs to be freed with dw_free() + * or NULL on failure. + */ +char * API dw_wchar_to_utf8(wchar_t *wstring) +{ +#ifdef UNICODE + return _myWideToUTF8(wstring, malloc(WideCharToMultiByte(CP_UTF8, 0, wstring, -1, NULL, 0, NULL, NULL))); +#else + return NULL; +#endif +} +