Mercurial > dwindows
diff win/dw.c @ 3:67a643a734d9
Import
author | ktk@81767d24-ef19-dc11-ae90-00e081727c95 |
---|---|
date | Tue, 03 Jul 2001 07:50:39 +0000 |
parents | |
children | 005fa766e8c2 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win/dw.c Tue Jul 03 07:50:39 2001 +0000 @@ -0,0 +1,5568 @@ +/* + * Dynamic Windows: + * A GTK like implementation of the Win32 GUI + * + * (C) 2000,2001 Brian Smith <dbsoft@technologist.com> + * + */ +#define _WIN32_IE 0x0500 +#define WINVER 0x400 +#include <windows.h> +#include <windowsx.h> +#include <commctrl.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <process.h> +#include "dw.h" + +/* this is the callback handle for the window procedure */ +/* make sure you always match the calling convention! */ +int (*filterfunc)(HWND, UINT, WPARAM, LPARAM) = 0L; + +HWND hwndBubble = (HWND)NULL, hwndBubbleLast, DW_HWND_OBJECT = (HWND)NULL; + +HINSTANCE DWInstance = NULL; + +DWORD dwVersion = 0; + +/* I should probably check the actual file version, but this will do for now */ +#define IS_WIN98PLUS (LOBYTE(LOWORD(dwVersion)) > 4 || \ + (LOBYTE(LOWORD(dwVersion)) == 4 && HIBYTE(LOWORD(dwVersion)) > 0)) + +char monthlist[][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec" }; + +int main(int argc, char *argv[]); + +#define ICON_INDEX_LIMIT 200 +HICON lookup[200]; +HIMAGELIST hSmall, hLarge; + +COLORREF _foreground = RGB(127, 127, 127); +COLORREF _background = 0; +HPEN _hPen; +HBRUSH _hBrush; + +#ifdef DWDEBUG +FILE *f; + +void reopen(void) +{ + fclose(f); + f = fopen("dw.log", "at"); +} +#endif + +BYTE _red[] = { 0x00, 0xbb, 0x00, 0xaa, 0x00, 0xbb, 0x00, 0xaa, 0x77, + 0xff, 0x00, 0xee, 0x00, 0xff, 0x00, 0xff, 0xaa, 0x00 }; +BYTE _green[] = { 0x00, 0x00, 0xbb, 0xaa, 0x00, 0x00, 0xbb, 0xaa, 0x77, + 0x00, 0xff, 0xee, 0x00, 0x00, 0xee, 0xff, 0xaa, 0x00 }; +BYTE _blue[] = { 0x00, 0x00, 0x00, 0x00, 0xcc, 0xbb, 0xbb, 0xaa, 0x77, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xee, 0xff, 0xaa, 0x00}; + +HBRUSH _colors[18]; + +static LONG lColor[SPLITBAR_WIDTH] = +{ + DW_CLR_BLACK, + DW_CLR_PALEGRAY, + DW_CLR_WHITE +}; + +void _resize_notebook_page(HWND handle, int pageid); + +#ifdef NO_SIGNALS +#define USE_FILTER +#else +typedef struct _sighandler +{ + struct _sighandler *next; + ULONG message; + HWND window; + void *signalfunction; + void *data; + +} SignalHandler; + +SignalHandler *Root = NULL; +int _index; + +typedef struct +{ + ULONG message; + char name[30]; + +} SignalList; + +/* List of signals and their equivilent Win32 message */ +#define SIGNALMAX 11 + +SignalList SignalTranslate[SIGNALMAX] = { + { WM_SIZE, "configure_event" }, + { WM_CHAR, "key_press_event" }, + { WM_LBUTTONDOWN, "button_press_event" }, + { WM_LBUTTONUP, "button_release_event" }, + { WM_MOUSEMOVE, "motion_notify_event" }, + { WM_CLOSE, "delete_event" }, + { WM_PAINT, "expose_event" }, + { WM_COMMAND, "clicked" }, + { NM_DBLCLK, "container-select" }, + { NM_RCLICK, "container-context" }, + { LBN_SELCHANGE, "item-select" } +}; + +#ifdef BUILD_DLL +void Win32_Set_Instance(HINSTANCE hInstance) +{ + DWInstance = hInstance; +} +#else +char **_convertargs(int *count, char *start) +{ + char *tmp, *argstart, **argv; + int loc = 0, inquotes = 0; + + (*count) = 1; + + tmp = start; + + /* Count the number of entries */ + if(*start) + { + (*count)++; + + while(*tmp) + { + if(*tmp == '"' && inquotes) + inquotes = 0; + else if(*tmp == '"' && !inquotes) + inquotes = 1; + else if(*tmp == ' ' && !inquotes) + { + /* Push past any white space */ + while(*(tmp+1) == ' ') + tmp++; + /* If we aren't at the end of the command + * line increment the count. + */ + if(*(tmp+1)) + (*count)++; + } + tmp++; + } + } + + argv = (char **)malloc(sizeof(char *) * ((*count)+1)); + argv[0] = malloc(260); + GetModuleFileName(DWInstance, argv[0], 260); + + argstart = tmp = start; + + if(*start) + { + loc = 1; + + while(*tmp) + { + if(*tmp == '"' && inquotes) + { + *tmp = 0; + inquotes = 0; + } + else if(*tmp == '"' && !inquotes) + { + argstart = tmp+1; + inquotes = 1; + } + else if(*tmp == ' ' && !inquotes) + { + *tmp = 0; + argv[loc] = strdup(argstart); + + /* Push past any white space */ + while(*(tmp+1) == ' ') + tmp++; + + /* Move the start pointer */ + argstart = tmp+1; + + /* If we aren't at the end of the command + * line increment the count. + */ + if(*(tmp+1)) + loc++; + } + tmp++; + } + if(*argstart) + argv[loc] = strdup(argstart); + } + argv[loc+1] = NULL; + return argv; +} + +/* Ok this is a really big hack but what the hell ;) */ +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + char **argv; + int argc; + + DWInstance = hInstance; + + argv = _convertargs(&argc, lpCmdLine); + + return main(argc, argv); +} +#endif + +/* This function adds a signal handler callback into the linked list. + */ +void _new_signal(ULONG message, HWND window, void *signalfunction, void *data) +{ + SignalHandler *new = malloc(sizeof(SignalHandler)); + + new->message = message; + new->window = window; + new->signalfunction = signalfunction; + new->data = data; + new->next = NULL; + + if (!Root) + Root = new; + else + { + SignalHandler *prev = NULL, *tmp = Root; + while(tmp) + { + prev = tmp; + tmp = tmp->next; + } + if(prev) + prev->next = new; + else + Root = new; + } +} + +/* Finds the message number for a given signal name */ +ULONG _findsigmessage(char *signame) +{ + int z; + + for(z=0;z<SIGNALMAX;z++) + { + if(stricmp(signame, SignalTranslate[z].name) == 0) + return SignalTranslate[z].message; + } + return 0L; +} +#endif + +/* This function removes and handlers on windows and frees + * the user memory allocated to it. + */ +BOOL CALLBACK _free_window_memory(HWND handle, LPARAM lParam) +{ + void *ptr = (void *)GetWindowLong(handle, GWL_USERDATA); + +#ifndef NO_SIGNALS + dw_signal_disconnect_by_window(handle); +#endif + + if(ptr) + { + SetWindowLong(handle, GWL_USERDATA, 0); + free(ptr); + } + return TRUE; +} + +/* This function returns 1 if the window (widget) handle + * passed to it is a valid window that can gain input focus. + */ +int _validate_focus(HWND handle) +{ + char tmpbuf[100]; + + if(!handle) + return 0; + + GetClassName(handle, tmpbuf, 99); + + /* These are the window classes which can + * obtain input focus. + */ + if(strnicmp(tmpbuf, EDITCLASSNAME, strlen(EDITCLASSNAME))==0 || /* Entryfield */ + strnicmp(tmpbuf, BUTTONCLASSNAME, strlen(BUTTONCLASSNAME))==0 || /* Button */ + strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME))==0 || /* Combobox */ + strnicmp(tmpbuf, LISTBOXCLASSNAME, strlen(LISTBOXCLASSNAME))==0 || /* List box */ + strnicmp(tmpbuf, UPDOWN_CLASS, strlen(UPDOWN_CLASS))==0 || /* Spinbutton */ + strnicmp(tmpbuf, WC_LISTVIEW, strlen(WC_LISTVIEW))== 0) /* Container */ + return 1; + return 0; +} + +HWND _normalize_handle(HWND handle) +{ + char tmpbuf[100] = ""; + + GetClassName(handle, tmpbuf, 99); + if(strnicmp(tmpbuf, UPDOWN_CLASS, strlen(UPDOWN_CLASS))==0) /* Spinner */ + { + ColorInfo *cinfo = (ColorInfo *)GetWindowLong(handle, GWL_USERDATA); + + if(cinfo && cinfo->buddy) + return cinfo->buddy; + } + return handle; +} + +int _focus_check_box(Box *box, HWND handle, int start) +{ + int z; + static HWND lasthwnd, firsthwnd; + static int finish_searching; + + /* Start is 2 when we have cycled completely and + * need to set the focus to the last widget we found + * that was valid. + */ + if(start == 2) + { + if(lasthwnd) + SetFocus(lasthwnd); + return 0; + } + + /* Start is 1 when we are entering the function + * for the first time, it is zero when entering + * the function recursively. + */ + if(start == 1) + { + lasthwnd = handle; + finish_searching = 0; + firsthwnd = 0; + } + + for(z=box->count-1;z>-1;z--) + { + if(box->items[z].type == TYPEBOX) + { + Box *thisbox = (Box *)GetWindowLong(box->items[z].hwnd, GWL_USERDATA); + + if(thisbox && _focus_check_box(thisbox, handle, start == 3 ? 3 : 0)) + return 1; + } + else + { + if(box->items[z].hwnd == handle) + { + if(lasthwnd == handle && firsthwnd) + SetFocus(firsthwnd); + else if(lasthwnd == handle && !firsthwnd) + finish_searching = 1; + else + SetFocus(lasthwnd); + + /* If we aren't looking for the last handle, + * return immediately. + */ + if(!finish_searching) + return 1; + } + if(_validate_focus(box->items[z].hwnd)) + { + /* Start is 3 when we are looking for the + * first valid item in the layout. + */ + if(start == 3) + { + SetFocus(_normalize_handle(box->items[z].hwnd)); + return 1; + } + + if(!firsthwnd) + firsthwnd = _normalize_handle(box->items[z].hwnd); + + lasthwnd = _normalize_handle(box->items[z].hwnd); + } + else + { + char tmpbuf[100] = ""; + + GetClassName(box->items[z].hwnd, tmpbuf, 99); + + if(strnicmp(tmpbuf, WC_TABCONTROL, strlen(WC_TABCONTROL))==0) /* Notebook */ + { + NotebookPage **array = (NotebookPage **)GetWindowLong(box->items[z].hwnd, GWL_USERDATA); + int pageid = TabCtrl_GetCurSel(box->items[z].hwnd); + + if(pageid > -1 && array && array[pageid]) + { + Box *notebox; + + if(array[pageid]->hwnd) + { + notebox = (Box *)GetWindowLong(array[pageid]->hwnd, GWL_USERDATA); + + if(notebox && _focus_check_box(notebox, handle, start == 3 ? 3 : 0)) + return 1; + } + } + } + } + } + } + return 0; +} + +/* This function finds the first widget in the + * layout and moves the current focus to it. + */ +void _initial_focus(HWND handle) +{ + Box *thisbox; + + if(handle) + thisbox = (Box *)GetWindowLong(handle, GWL_USERDATA); + + if(thisbox) + { + _focus_check_box(thisbox, handle, 3); + } +} + +/* This function finds the current widget in the + * layout and moves the current focus to the next item. + */ +void _shift_focus(HWND handle) +{ + Box *thisbox; + + HWND box, lastbox = GetParent(handle); + + /* Find the toplevel window */ + while((box = GetParent(lastbox))) + { + lastbox = box; + } + + thisbox = (Box *)GetWindowLong(lastbox, GWL_USERDATA); + if(thisbox) + { + if(_focus_check_box(thisbox, handle, 1) == 0) + _focus_check_box(thisbox, handle, 2); + } +} + +/* ResetWindow: + * Resizes window to the exact same size to trigger + * recalculation of frame. + */ +void _ResetWindow(HWND hwndFrame) +{ + RECT rcl; + + GetWindowRect(hwndFrame, &rcl); + SetWindowPos(hwndFrame, HWND_TOP, 0, 0, rcl.right - rcl.left, + rcl.bottom - rcl.top - 1, SWP_NOMOVE | SWP_NOZORDER); + SetWindowPos(hwndFrame, HWND_TOP, 0, 0, rcl.right - rcl.left, + rcl.bottom - rcl.top, SWP_NOMOVE | SWP_NOZORDER); +} + +/* Function: TrackRectangle + * Abstract: Tracks given rectangle. + * + * If rclBounds is NULL, then track rectangle on entire desktop. + * rclTrack is in window coorditates and will be mapped to + * desktop. + */ + +BOOL _TrackRectangle(HWND hwndBase, RECTL* rclTrack, RECTL* rclBounds) +{ + ULONG rc = 0; +#if 0 + TRACKINFO track; + + track.cxBorder = 1; + track.cyBorder = 1; + track.cxGrid = 1; + track.cyGrid = 1; + track.cxKeyboard = 8; + track.cyKeyboard = 8; + + if(!rclTrack) + return FALSE; + + if(rclBounds) + { + track.rclBoundary = *rclBounds; + } + else + { + track.rclBoundary.yTop = + track.rclBoundary.xRight = 3000; + track.rclBoundary.yBottom = + track.rclBoundary.xLeft = -3000; + } + + track.rclTrack = *rclTrack; + + MapWindowPoints(hwndBase, + HWND_DESKTOP, + (PPOINT)&track.rclTrack, + 2); + + track.ptlMinTrackSize.x = track.rclTrack.xRight + - track.rclTrack.xLeft; + track.ptlMinTrackSize.y = track.rclTrack.yTop + - track.rclTrack.yBottom; + track.ptlMaxTrackSize.x = track.rclTrack.xRight + - track.rclTrack.xLeft; + track.ptlMaxTrackSize.y = track.rclTrack.yTop + - track.rclTrack.yBottom; + + track.fs = TF_MOVE | TF_ALLINBOUNDARY; + + rc = WinTrackRect(HWND_DESKTOP, 0, &track); + + if(rc) + *rclTrack = track.rclTrack; + +#endif + return rc; +} + +/* 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; + 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); + + for(z=0;z<thisbox->count;z++) + { + if(thisbox->items[z].type == TYPEBOX) + { + int initialx, initialy; + Box *tmp = (Box *)GetWindowLong(thisbox->items[z].hwnd, GWL_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) + { + 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; + +#ifdef DWDEBUG + if(pass > 1) + { + fprintf(f, "FARK! depth %d\r\nwidth = %d, height = %d, nux = %d, nuy = %d, upx = %d, upy = %d xratio = %f, yratio = %f\r\n\r\n", + *depth, thisbox->items[z].width, thisbox->items[z].height, nux, nuy, tmp->upx, tmp->upy, tmp->xratio, tmp->yratio); + reopen(); + } +#endif + if(thisbox->type == BOXVERT) + { + if((thisbox->items[z].width-((thisbox->items[z].pad*2)+(tmp->pad*2)))!=0) + tmp->xratio = ((float)((thisbox->items[z].width * thisbox->xratio)-((thisbox->items[z].pad*2)+(tmp->pad*2))))/((float)(thisbox->items[z].width-((thisbox->items[z].pad*2)+(tmp->pad*2)))); + } + 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 == BOXHORZ) + { + if((thisbox->items[z].height-((thisbox->items[z].pad*2)+(tmp->pad*2)))!=0) + tmp->yratio = ((float)((thisbox->items[z].height * thisbox->yratio)-((thisbox->items[z].pad*2)+(tmp->pad*2))))/((float)(thisbox->items[z].height-((thisbox->items[z].pad*2)+(tmp->pad*2)))); + } + 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)++; + +#ifdef DWDEBUG + if(pass > 1) + { + fprintf(f, "Before Resize Box depth %d\r\nx = %d, y = %d, usedx = %d, usedy = %d, usedpadx = %d, usedpady = %d xratio = %f, yratio = %f\r\n\r\n", + *depth, x, y, *usedx, *usedy, *usedpadx, *usedpady, tmp->xratio, tmp->yratio); + reopen(); + } +#endif + + _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; + +#ifdef DWDEBUG + if(pass > 1) + { + fprintf(f, "After Resize Box depth %d\r\nx = %d, y = %d, usedx = %d, usedy = %d, usedpadx = %d, usedpady = %d width = %d, height = %d\r\n\r\n", + *depth, x, y, *usedx, *usedy, *usedpadx, *usedpady, thisbox->items[z].width, thisbox->items[z].height); + reopen(); + } +#endif + } + } + + if(pass > 1 && *depth > 0) + { + if(thisbox->type == BOXVERT) + thisbox->items[z].xratio = ((float)((thisbox->width * thisbox->parentxratio)-((thisbox->items[z].pad*2)+(thisbox->parentpad*2))))/((float)(thisbox->minwidth-((thisbox->items[z].pad*2)+(thisbox->parentpad*2)))); + else + thisbox->items[z].xratio = ((float)((thisbox->width * thisbox->parentxratio)-thisbox->upx))/((float)(thisbox->minwidth-thisbox->upx)); + + if(thisbox->type == BOXHORZ) + thisbox->items[z].yratio = ((float)((thisbox->height * thisbox->parentyratio)-((thisbox->items[z].pad*2)+(thisbox->parentpad*2))))/((float)(thisbox->minheight-((thisbox->items[z].pad*2)+(thisbox->parentpad*2)))); + else + thisbox->items[z].yratio = ((float)((thisbox->height * thisbox->parentyratio)-thisbox->upy))/((float)(thisbox->minheight-thisbox->upy)); +#ifdef DWDEBUG + fprintf(f, "RATIO- xratio = %f, yratio = %f, width = %d, height = %d, pad = %d, box xratio = %f, box yratio = %f, parent xratio = %f, parent yratio = %f, minwidth = %d, minheight = %d, width = %d, height = %d, upx = %d, upy = %d\r\n\r\n", + thisbox->items[z].xratio, thisbox->items[z].yratio, thisbox->items[z].width, thisbox->items[z].height, thisbox->items[z].pad, thisbox->xratio, thisbox->yratio, thisbox->parentxratio, thisbox->parentyratio, thisbox->minwidth, thisbox->minheight, thisbox->width, thisbox->height, thisbox->upx, thisbox->upy); + reopen(); +#endif + } + else + { + thisbox->items[z].xratio = thisbox->xratio; + thisbox->items[z].yratio = thisbox->yratio; + } + + if(thisbox->type == BOXVERT) + { + if((thisbox->items[z].width + (thisbox->items[z].pad*2)) > uxmax) + uxmax = (thisbox->items[z].width + (thisbox->items[z].pad*2)); + if(thisbox->items[z].hsize != SIZEEXPAND) + { + if(((thisbox->items[z].pad*2) + thisbox->items[z].width) > upxmax) + upxmax = (thisbox->items[z].pad*2) + thisbox->items[z].width; + } + else + { + if(thisbox->items[z].pad*2 > upxmax) + upxmax = thisbox->items[z].pad*2; + } + } + 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 == BOXHORZ) + { + if((thisbox->items[z].height + (thisbox->items[z].pad*2)) > uymax) + uymax = (thisbox->items[z].height + (thisbox->items[z].pad*2)); + if(thisbox->items[z].vsize != SIZEEXPAND) + { + if(((thisbox->items[z].pad*2) + thisbox->items[z].height) > upymax) + upymax = (thisbox->items[z].pad*2) + thisbox->items[z].height; + } + 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 = */ + } + 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; + +#ifdef DWDEBUG + fprintf(f, "Done Calc depth %d\r\nusedx = %d, usedy = %d, usedpadx = %d, usedpady = %d, currentx = %d, currenty = %d, uxmax = %d, uymax = %d\r\n\r\n", + *depth, *usedx, *usedy, *usedpadx, *usedpady, currentx, currenty, uxmax, uymax); + reopen(); +#endif + + /* The second pass is for expansion and 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 == BOXVERT) + thisbox->items[z].width = uxmax-(thisbox->items[z].pad*2); + if(thisbox->items[z].vsize == SIZEEXPAND && thisbox->type == BOXHORZ) + 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 *)GetWindowLong(thisbox->items[z].hwnd, GWL_USERDATA); + + if(tmp) + { + if(*depth > 0) + { + if(thisbox->type == BOXVERT) + { + tmp->xratio = ((float)((thisbox->items[z].width * thisbox->xratio)-((thisbox->items[z].pad*2)+(thisbox->pad*2))))/((float)(tmp->minwidth-((thisbox->items[z].pad*2)+(thisbox->pad*2)))); + tmp->width = thisbox->items[z].width; + } + if(thisbox->type == BOXHORZ) + { + tmp->yratio = ((float)((thisbox->items[z].height * thisbox->yratio)-((thisbox->items[z].pad*2)+(thisbox->pad*2))))/((float)(tmp->minheight-((thisbox->items[z].pad*2)+(thisbox->pad*2)))); + tmp->height = thisbox->items[z].height; + } + } + + (*depth)++; + + /*tmp->xratio = ((float)((thisbox->items[z].width * thisbox->xratio)-tmp->upx) )/((float)(tmp->minwidth-tmp->upx)); + tmp->yratio = ((float)((thisbox->items[z].height * thisbox->yratio)-tmp->upy))/((float)(tmp->minheight-tmp->upy));*/ + +#ifdef DWDEBUG + fprintf(f, "2- Resize Box depth %d\r\nx = %d, y = %d, usedx = %d, usedy = %d, usedpadx = %d, usedpady = %d xratio = %f, yratio = %f,\r\nupx = %d, upy = %d, width = %d, height = %d, minwidth = %d, minheight = %d, box xratio = %f, box yratio = %f\r\n\r\n", + *depth, x, y, *usedx, *usedy, *usedpadx, *usedpady, tmp->xratio, tmp->yratio, tmp->upx, tmp->upy, thisbox->items[z].width, thisbox->items[z].height, tmp->minwidth, tmp->minheight, thisbox->xratio, thisbox->yratio); + reopen(); +#endif + + _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) + { + 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; + + GetClassName(handle, tmpbuf, 99); + + if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME))==0) + { + /* Handle special case Combobox */ + SetWindowPos(handle, HWND_TOP, currentx + pad, currenty + pad, + width + vectorx, (height + vectory) + 400, 0); + } + else if(strnicmp(tmpbuf, UPDOWN_CLASS, strlen(UPDOWN_CLASS))==0) + { + /* Handle special case Spinbutton */ + ColorInfo *cinfo = (ColorInfo *)GetWindowLong(handle, GWL_USERDATA); + + SetWindowPos(handle, HWND_TOP, currentx + pad + ((width + vectorx) - 20), currenty + pad, + 20, height + vectory, 0); + + if(cinfo) + { + SetWindowPos(cinfo->buddy, HWND_TOP, currentx + pad, currenty + pad, + (width + vectorx) - 20, height + vectory, 0); + } + } + else + { + /* Everything else */ + SetWindowPos(handle, HWND_TOP, currentx + pad, currenty + pad, + width + vectorx, height + vectory, 0); + if(thisbox->items[z].type == TYPEBOX) + { + Box *boxinfo = (Box *)GetWindowLong(handle, GWL_USERDATA); + + if(boxinfo && boxinfo->grouphwnd) + SetWindowPos(boxinfo->grouphwnd, HWND_TOP, 0, 0, + width + vectorx, height + vectory, 0); + + } + } + + /* Notebook dialog requires additional processing */ + if(strncmp(tmpbuf, WC_TABCONTROL, strlen(WC_TABCONTROL))==0) + { + RECT rect; + NotebookPage **array = (NotebookPage **)GetWindowLong(handle, GWL_USERDATA); + int pageid = TabCtrl_GetCurSel(handle); + + if(pageid > -1 && array && array[pageid]) + { + GetClientRect(handle,&rect); + TabCtrl_AdjustRect(handle,FALSE,&rect); + MoveWindow(array[pageid]->hwnd,rect.left,rect.top, + rect.right - rect.left,rect.bottom-rect.top, + TRUE); + ShowWindow(array[pageid]->hwnd,SW_SHOWNORMAL); + } + } + +#ifdef DWDEBUG + fprintf(f, "Window Pos depth %d\r\ncurrentx = %d, currenty = %d, pad = %d, width = %d, height = %d, vectorx = %d, vectory = %d, Box type = %s\r\n\r\n", + *depth, currentx, currenty, pad, width, height, vectorx, vectory,thisbox->type == BOXHORZ ? "Horizontal" : "Vertical"); + reopen(); +#endif + + if(thisbox->type == BOXHORZ) + currentx += width + vectorx + (pad * 2); + if(thisbox->type == BOXVERT) + currenty += height + vectory + (pad * 2); + } + } + } + return 0; +} + +void _do_resize(Box *thisbox, int x, int y) +{ + if(x != 0 && y != 0) { + if(thisbox) + { + int usedx = 0, usedy = 0, depth = 0, usedpadx = 0, usedpady = 0; + + _resize_box(thisbox, &depth, x, y, &usedx, &usedy, 1, &usedpadx, &usedpady); + + thisbox->xratio = ((float)(x-usedpadx))/((float)(usedx-usedpadx)); + thisbox->yratio = ((float)(y-usedpady))/((float)(usedy-usedpady)); + +#ifdef DWDEBUG + fprintf(f, "WM_SIZE Resize Box Pass 1\r\nx = %d, y = %d, usedx = %d, usedy = %d, usedpadx = %d, usedpady = %d xratio = %f, yratio = %f\r\n\r\n", + x, y, usedx, usedy, usedpadx, usedpady, thisbox->xratio, thisbox->yratio); + reopen(); +#endif + + usedpadx = usedpady = usedx = usedy = depth = 0; + + _resize_box(thisbox, &depth, x, y, &usedx, &usedy, 2, &usedpadx, &usedpady); +#ifdef DWDEBUG + fprintf(f, "WM_SIZE Resize Box Pass 2\r\nx = %d, y = %d, usedx = %d, usedy = %d, usedpadx = %d, usedpady = %d\r\n", + x, y, usedx, usedy, usedpadx, usedpady); + reopen(); +#endif + } + } +} + +/* 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) +{ + int result = -1; + static int command_active = 0; +#ifndef NO_SIGNALS + SignalHandler *tmp = Root; +#endif + void (* windowfunc)(PVOID); + ULONG origmsg = msg; + + if(msg == WM_RBUTTONDOWN || msg == WM_MBUTTONDOWN) + msg = WM_LBUTTONDOWN; + if(msg == WM_RBUTTONUP || msg == WM_MBUTTONUP) + msg = WM_LBUTTONUP; + + if(filterfunc) + result = filterfunc(hWnd, msg, mp1, mp2); + +#ifndef NO_SIGNALS + if(result == -1) + { + /* Avoid infinite recursion */ + command_active = 1; + + /* Find any callbacks for this function */ + while(tmp) + { + if(tmp->message == msg || msg == WM_COMMAND) + { + switch(msg) + { + case WM_SIZE: + { + int (*sizefunc)(HWND, int, int, void *) = tmp->signalfunction; + + if(hWnd == tmp->window) + { + result = sizefunc(tmp->window, LOWORD(mp2), HIWORD(mp2), tmp->data); + tmp = NULL; + } + } + break; + case WM_LBUTTONDOWN: + { + POINTS pts = MAKEPOINTS(mp2); + int (*buttonfunc)(HWND, int, int, int, void *) = (int (*)(HWND, int, int, int, void *))tmp->signalfunction; + + if(hWnd == tmp->window) + { + int button; + + switch(origmsg) + { + case WM_LBUTTONDOWN: + button = 1; + break; + case WM_RBUTTONDOWN: + button = 2; + break; + case WM_MBUTTONDOWN: + button = 3; + break; + } + result = buttonfunc(tmp->window, pts.x, pts.y, button, tmp->data); + tmp = NULL; + } + } + break; + case WM_LBUTTONUP: + { + POINTS pts = MAKEPOINTS(mp2); + int (*buttonfunc)(HWND, int, int, int, void *) = (int (*)(HWND, int, int, int, void *))tmp->signalfunction; + + if(hWnd == tmp->window) + { + int button; + + switch(origmsg) + { + case WM_LBUTTONUP: + button = 1; + break; + case WM_RBUTTONUP: + button = 2; + break; + case WM_MBUTTONUP: + button = 3; + break; + } + result = buttonfunc(tmp->window, pts.x, pts.y, button, tmp->data); + tmp = NULL; + } + } + break; + case WM_MOUSEMOVE: + { + POINTS pts = MAKEPOINTS(mp2); + int (*motionfunc)(HWND, int, int, int, void *) = (int (*)(HWND, int, int, int, void *))tmp->signalfunction; + + if(hWnd == tmp->window) + { + int keys = 0; + + if (mp1 & MK_LBUTTON) + keys = DW_BUTTON1_MASK; + if (mp1 & MK_RBUTTON) + keys |= DW_BUTTON2_MASK; + if (mp1 & MK_MBUTTON) + keys |= DW_BUTTON3_MASK; + + result = motionfunc(tmp->window, pts.x, pts.y, keys, tmp->data); + tmp = NULL; + } + } + break; + case WM_CHAR: + { + int (*keypressfunc)(HWND, int, void *) = tmp->signalfunction; + + if(hWnd == tmp->window) + { + result = keypressfunc(tmp->window, LOWORD(mp2), tmp->data); + tmp = NULL; + } + } + break; + case WM_CLOSE: + { + int (*closefunc)(HWND, void *) = tmp->signalfunction; + + if(hWnd == tmp->window) + { + result = closefunc(tmp->window, tmp->data); + tmp = NULL; + } + } + break; + case WM_PAINT: + { + PAINTSTRUCT ps; + DWExpose exp; + int (*exposefunc)(HWND, DWExpose *, void *) = tmp->signalfunction; + + if(hWnd == tmp->window) + { + BeginPaint(hWnd, &ps); + exp.x = ps.rcPaint.left; + exp.y = ps.rcPaint.top; + exp.width = ps.rcPaint.right - ps.rcPaint.left; + exp.height = ps.rcPaint.bottom - ps.rcPaint.top; + result = exposefunc(hWnd, &exp, tmp->data); + EndPaint(hWnd, &ps); + } + } + break; + case WM_COMMAND: + { + int (*clickfunc)(HWND, void *) = tmp->signalfunction; + HWND command; + ULONG passthru = (ULONG)LOWORD(mp1); + ULONG message = HIWORD(mp1); + + command = (HWND)passthru; + + if(message == LBN_SELCHANGE || message == CBN_SELCHANGE) + { + int (*listboxselectfunc)(HWND, int, void *) = tmp->signalfunction; + + if(tmp->message == LBN_SELCHANGE && tmp->window == (HWND)mp2) + { + result = listboxselectfunc(tmp->window, dw_listbox_selected(tmp->window), tmp->data); + tmp = NULL; + } + } /* Make sure it's the right window, and the right ID */ + else if(tmp->window < (HWND)65536 && command == tmp->window) + { + result = clickfunc(tmp->window, tmp->data); + tmp = NULL; + } + } + break; + } + } + if(tmp) + tmp = tmp->next; + } + command_active = 0; + } +#endif + + /* Now that any handlers are done... do normal processing */ + switch( msg ) + { + case WM_PAINT: + { + PAINTSTRUCT ps; + + BeginPaint(hWnd, &ps); + EndPaint(hWnd, &ps); + } + break; + case WM_SIZE: + { + static int lastx = -1, lasty = -1; + static HWND lasthwnd = 0; + + if(lastx != LOWORD(mp2) || lasty != HIWORD(mp2) || lasthwnd != hWnd) + { + Box *mybox = (Box *)GetWindowLong(hWnd, GWL_USERDATA); + + lastx = LOWORD(mp2); + lasty = HIWORD(mp2); + lasthwnd = hWnd; + + _do_resize(mybox,LOWORD(mp2),HIWORD(mp2)); + } + } + break; + case WM_CHAR: + if(LOWORD(mp1) == '\t') + { + _shift_focus(hWnd); + return TRUE; + } + break; + case WM_USER: + windowfunc = (void *)mp1; + + if(windowfunc) + windowfunc((void *)mp2); + break; + case WM_NOTIFY: + { + NMHDR FAR *tem=(NMHDR FAR *)mp2; + + if(tem->code == TCN_SELCHANGING) + { + int num=TabCtrl_GetCurSel(tem->hwndFrom); + NotebookPage **array = (NotebookPage **)GetWindowLong(tem->hwndFrom, GWL_USERDATA); + + if(num > -1 && array && array[num]) + SetParent(array[num]->hwnd, DW_HWND_OBJECT); + + } + else if(tem->code == TCN_SELCHANGE) + { + int num=TabCtrl_GetCurSel(tem->hwndFrom); + NotebookPage **array = (NotebookPage **)GetWindowLong(tem->hwndFrom, GWL_USERDATA); + + if(num > -1 && array && array[num]) + SetParent(array[num]->hwnd, tem->hwndFrom); + + _resize_notebook_page(tem->hwndFrom, num); + } + } + break; + case WM_GETMINMAXINFO: + { + MINMAXINFO *info = (MINMAXINFO *)mp2; + info->ptMinTrackSize.x = 8; + info->ptMinTrackSize.y = 8; + return 0; + } + break; + case WM_DESTROY: + /* Free memory before destroying */ +#if 0 + /* Is this the right message? I seem to be + * getting WM_DESTROY on windows that aren't + * being destroyed. + */ + _free_window_memory(hWnd, 0); + EnumChildWindows(hWnd, _free_window_memory, 0); +#endif + break; + } + if(filterfunc && result != -1) + return result; + else + return DefWindowProc(hWnd, msg, mp1, mp2); +} + +BOOL CALLBACK _framewndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) +{ + switch( msg ) + { + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + SetActiveWindow(hWnd); + break; + case WM_COMMAND: + case WM_NOTIFY: + _wndproc(hWnd, msg, mp1, mp2); + break; + } + return DefWindowProc(hWnd, msg, mp1, mp2); +} + +BOOL CALLBACK _rendwndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) +{ + switch( msg ) + { + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + SetActiveWindow(hWnd); + _wndproc(hWnd, msg, mp1, mp2); + break; + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_MOUSEMOVE: + case WM_PAINT: + case WM_SIZE: + case WM_COMMAND: + _wndproc(hWnd, msg, mp1, mp2); + break; + } + return DefWindowProc(hWnd, msg, mp1, mp2); +} + +BOOL CALLBACK _spinnerwndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) +{ + ColorInfo *cinfo; + + cinfo = (ColorInfo *)GetWindowLong(hWnd, GWL_USERDATA); + + if(cinfo) + { + switch( msg ) + { + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_CHAR: + { + BOOL ret; + + if(!cinfo || !cinfo->pOldProc) + ret = DefWindowProc(hWnd, msg, mp1, mp2); + ret = CallWindowProc(cinfo->pOldProc, hWnd, msg, mp1, mp2); + + /* Tell the edit control that a buttonpress has + * occured and to update it's window title. + */ + if(cinfo->buddy) + SendMessage(cinfo->buddy, WM_USER+10, 0, 0); + + return ret; + } + break; + case WM_USER+10: + { + if(cinfo->buddy) + { + char tempbuf[100] = ""; + long position; + + GetWindowText(cinfo->buddy, tempbuf, 99); + + position = atol(tempbuf); + + if(IS_WIN98PLUS) + SendMessage(hWnd, UDM_SETPOS32, 0, (LPARAM)position); + else + SendMessage(hWnd, UDM_SETPOS, 0, (LPARAM)MAKELONG((short)position, 0)); + } + } + break; + } + } + + if(!cinfo || !cinfo->pOldProc) + return DefWindowProc(hWnd, msg, mp1, mp2); + return CallWindowProc(cinfo->pOldProc, hWnd, msg, mp1, mp2); +} + +BOOL CALLBACK _colorwndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) +{ + ColorInfo *cinfo; + char tmpbuf[100]; + + cinfo = (ColorInfo *)GetWindowLong(hWnd, GWL_USERDATA); + + GetClassName(hWnd, tmpbuf, 99); + if(strcmp(tmpbuf, FRAMECLASSNAME) == 0) + cinfo = &(((Box *)cinfo)->cinfo); + + if(cinfo) + { + switch( msg ) + { + case WM_CHAR: + if(LOWORD(mp1) == '\t') + { + if(cinfo->buddy) + _shift_focus(cinfo->buddy); + else + _shift_focus(hWnd); + return FALSE; + } + /* Tell the spinner control that a keypress has + * occured and to update it's internal value. + */ + if(cinfo->buddy) + SendMessage(cinfo->buddy, WM_USER+10, 0, 0); + break; + case WM_USER+10: + { + if(cinfo->buddy) + { + long val, position; + char tmpbuf[100] = ""; + + GetWindowText(cinfo->buddy, tmpbuf, 99); + + position = atol(tmpbuf); + + if(IS_WIN98PLUS) + val = (long)SendMessage(cinfo->buddy, UDM_GETPOS32, 0, 0); + else + val = (long)SendMessage(cinfo->buddy, UDM_GETPOS, 0, 0); + + if(val != position) + { + sprintf(tmpbuf, "%d", val); + SetWindowText(hWnd, tmpbuf); + } + } + } + break; + case WM_KEYUP: + { + if(mp1 == VK_UP || mp1 == VK_DOWN) + { + if(cinfo->buddy) + PostMessage(hWnd, WM_USER+10, 0, 0); + } + } + break; + case WM_CTLCOLORSTATIC: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORBTN: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORMSGBOX: + case WM_CTLCOLORSCROLLBAR: + { + ColorInfo *thiscinfo = (ColorInfo *)GetWindowLong((HWND)mp2, GWL_USERDATA); + if(thiscinfo && thiscinfo->fore != -1 && thiscinfo->back != -1) + { + if(thiscinfo->fore > -1 && thiscinfo->back > -1 && + thiscinfo->fore < 18 && thiscinfo->back < 18) + { + SetTextColor((HDC)mp1, RGB(_red[thiscinfo->fore], + _green[thiscinfo->fore], + _blue[thiscinfo->fore])); + SetBkColor((HDC)mp1, RGB(_red[thiscinfo->back], + _green[thiscinfo->back], + _blue[thiscinfo->back])); + SelectObject((HDC)mp1, _colors[thiscinfo->back]); + return (LRESULT)_colors[thiscinfo->back]; + } + if((thiscinfo->fore & DW_RGB_COLOR) == DW_RGB_COLOR && (thiscinfo->back & 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))); + SetBkColor((HDC)mp1, RGB(DW_RED_VALUE(thiscinfo->back), + DW_GREEN_VALUE(thiscinfo->back), + DW_BLUE_VALUE(thiscinfo->back))); + DeleteObject(thiscinfo->hbrush); + thiscinfo->hbrush = CreateSolidBrush(RGB(DW_RED_VALUE(thiscinfo->back), + DW_GREEN_VALUE(thiscinfo->back), + DW_BLUE_VALUE(thiscinfo->back))); + return (LRESULT)thiscinfo->hbrush; + } + } + + } + break; + } + } + + if(!cinfo || !cinfo->pOldProc) + return DefWindowProc(hWnd, msg, mp1, mp2); + return CallWindowProc(cinfo->pOldProc, hWnd, msg, mp1, mp2); +} + +BOOL CALLBACK _containerwndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2) +{ + ContainerInfo *cinfo; + + cinfo = (ContainerInfo *)GetWindowLong(hWnd, GWL_USERDATA); + + switch( msg ) + { + case WM_COMMAND: + case WM_NOTIFY: + _wndproc(hWnd, msg, mp1, mp2); + break; +#ifndef NO_SIGNALS + case WM_LBUTTONDBLCLK: + case WM_CHAR: + { + LV_ITEM lvi; + int iItem; + + if(LOWORD(mp1) == '\t') + { + _shift_focus(hWnd); + return FALSE; + } + + if(msg == WM_CHAR && (char)mp1 != '\r') + break; + + iItem = ListView_GetNextItem(hWnd, -1, LVNI_FOCUSED); + + if(iItem > -1) + { + lvi.iItem = iItem; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hWnd, &lvi); + } + else + lvi.lParam = (LPARAM)NULL; + + { + SignalHandler *tmp = Root; + + while(tmp) + { + if(tmp->message == NM_DBLCLK && tmp->window == hWnd) + { + int (*containerselectfunc)(HWND, char *, void *) = tmp->signalfunction; + + /* Seems to be having lParam as 1 which really sucks */ + if(lvi.lParam < 100) + lvi.lParam = 0; + + containerselectfunc(tmp->window, (char *)lvi.lParam, tmp->data); + tmp = NULL; + } + if(tmp) + tmp = tmp->next; + } + } + } + break; + case WM_CONTEXTMENU: + { + LONG x,y; + LV_ITEM lvi; + int iItem; + + iItem = ListView_GetNextItem(hWnd, -1, LVNI_FOCUSED); + + if(iItem > -1) + { + lvi.iItem = iItem; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hWnd, &lvi); + } + else + lvi.lParam = (LPARAM)NULL; + + dw_pointer_query_pos(&x, &y); + + { + SignalHandler *tmp = Root; + + while(tmp) + { + if(tmp->message == NM_RCLICK && tmp->window == hWnd) + { + int (*containercontextfunc)(HWND, char *, int, int, void *) = tmp->signalfunction; + + /* Seems to be having lParam as 1 which really sucks */ + if(lvi.lParam < 100) + lvi.lParam = 0; + + containercontextfunc(tmp->window, (char *)lvi.lParam, x, y, tmp->data); + tmp = NULL; + } + if(tmp) + tmp = tmp->next; + } + } + } + break; +#else + case WM_CHAR: + if(LOWORD(mp1) == '\t') + { + _shift_focus(hWnd); + return FALSE; + } + break; +#endif + } + + if(!cinfo || !cinfo->pOldProc) + return DefWindowProc(hWnd, msg, mp1, mp2); + return CallWindowProc(cinfo->pOldProc, hWnd, msg, mp1, mp2); +} + +void _changebox(Box *thisbox, int percent, int type) +{ + int z; + + for(z=0;z<thisbox->count;z++) + { + if(thisbox->items[z].type == TYPEBOX) + { + Box *tmp = (Box*)GetWindowLong(thisbox->items[z].hwnd, GWL_USERDATA); + _changebox(tmp, percent, type); + } + else + { + if(type == BOXHORZ) + { + if(thisbox->items[z].hsize == SIZEEXPAND) + thisbox->items[z].width = (int)(((float)thisbox->items[z].origwidth) * (((float)percent)/((float)100.0))); + } + else + { + if(thisbox->items[z].vsize == SIZEEXPAND) + thisbox->items[z].height = (int)(((float)thisbox->items[z].origheight) * (((float)percent)/((float)100.0))); + } + } + } +} + +/* This handles any activity on the splitbars (sizers) */ +BOOL CALLBACK _splitwndproc(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2) +{ + HWND hwndFrame = 0; + Box *thisbox = 0; + + hwndFrame = GetParent(hwnd); + if(hwndFrame) + thisbox = (Box *)GetWindowLong(hwndFrame, GWL_USERDATA); + + switch (msg) + { + case WM_ACTIVATE: + case WM_SETFOCUS: + return FALSE; + + case WM_PAINT: + { + HDC hdcPaint; + PAINTSTRUCT ps; + POINT ptlStart[SPLITBAR_WIDTH]; + POINT ptlEnd[SPLITBAR_WIDTH]; + RECT rcPaint; + USHORT i; + + hdcPaint = BeginPaint(hwnd, &ps); + GetWindowRect(hwnd, &rcPaint); + + if(thisbox->type == BOXHORZ) + { + for(i = 0; i < SPLITBAR_WIDTH; i++) + { + ptlStart[i].x = i; + ptlStart[i].y = 0; + + ptlEnd[i].x = i; + ptlEnd[i].y = rcPaint.bottom - rcPaint.top; + } + } + else + { + for(i = 0; i < SPLITBAR_WIDTH; i++) + { + ptlStart[i].x = 0; + ptlStart[i].y = i; + + ptlEnd[i].x = rcPaint.right - rcPaint.left; + ptlEnd[i].y = i; + } + } + + for(i = 0; i < SPLITBAR_WIDTH; i++) + { + HPEN hPen; + HPEN hOldPen; + + hPen = CreatePen(PS_SOLID, 1, RGB (_red[lColor[i]], _green[lColor[i]], _blue[lColor[i]])); + hOldPen = (HPEN)SelectObject(hdcPaint, hPen); + MoveToEx(hdcPaint, ptlStart[i].x, ptlStart[i].y, NULL); + LineTo(hdcPaint, ptlEnd[i].x, ptlEnd[i].y); + SelectObject(hdcPaint, hOldPen); + DeleteObject(hPen); + } + EndPaint(hwnd, &ps); + } + return FALSE; + case WM_MOUSEMOVE: + { + if(thisbox->type == BOXHORZ) + SetCursor(LoadCursor(NULL, IDC_SIZEWE)); + else + SetCursor(LoadCursor(NULL, IDC_SIZENS)); + } + return FALSE; +#if 0 + case WM_BUTTON1DOWN: + { + ULONG rc; + RECTL rclFrame; + RECTL rclBounds; + RECTL rclStart; + USHORT startSize, orig, actual; + + GetWindowRect(hwnd, &rclFrame); + GetWindowRect(hwnd, &rclStart); + + GetWindowRect(hwndFrame, &rclBounds); + + WinMapWindowPoints(hwndFrame, HWND_DESKTOP, + (PPOINTL)&rclBounds, 2); + WinMapWindowPoints(hwnd, HWND_DESKTOP, + (PPOINTL)&rclStart, 2); + + if(thisbox->type == BOXHORZ) + { + orig = thisbox->items[0].origwidth; + actual = thisbox->items[0].width; + + startSize = (rclStart.xLeft - rclBounds.xLeft) + * (((float)orig)/((float)actual)); + } + else + { + orig = thisbox->items[0].origheight; + actual = thisbox->items[0].height; + + startSize = (rclStart.yBottom - rclBounds.yBottom) + * (((float)actual)/((float)orig)); + } + + rc = _TrackRectangle(hwnd, &rclFrame, &rclBounds); + + if(rc == TRUE) + { + USHORT usNewRB; + USHORT usSize; + USHORT percent; + int z; + + if(thisbox->type == BOXHORZ) + { + usNewRB = rclFrame.xLeft + - rclBounds.xLeft; + usSize = rclBounds.xRight + - rclBounds.xLeft; + } + else + { + usNewRB = rclFrame.yBottom + - rclBounds.yBottom; + usSize = rclBounds.yTop + - rclBounds.yBottom; + } + + percent = (usNewRB*100)/startSize; + + for(z=0;z<thisbox->count;z++) + { + if(thisbox->items[z].type == TYPEBOX) + { + Box *tmp = (Box *)GetWindowLong(thisbox->items[z].hwnd, GWL_USERDATA); + _changebox(tmp, percent, thisbox->type); + } + else + { + if(thisbox->items[z].hwnd == hwnd) + percent = (startSize*100)/usNewRB; + + if(thisbox->type == BOXHORZ) + { + if(thisbox->items[z].hsize == SIZEEXPAND) + thisbox->items[z].width = (int)(((float)thisbox->items[z].origwidth) * (((float)percent)/((float)100.0))); + } + else + { + if(thisbox->items[z].vsize == SIZEEXPAND) + thisbox->items[z].height = (int)(((float)thisbox->items[z].origheight) * (((float)percent)/((float)100.0))); + } + } + } + + _ResetWindow(GetWindow(hwnd, GW_OWNER)); + } + } + return MRFROMSHORT(FALSE); +#endif + } + return DefWindowProc(hwnd, msg, mp1, mp2); +} + +/* Function: _BtProc + * Abstract: Subclass procedure for buttons + */ + +BOOL CALLBACK _BtProc(HWND hwnd, ULONG msg, WPARAM mp1, LPARAM mp2) +{ + BubbleButton *bubble; + static int bMouseOver = 0; + POINT point; + RECT rect; + + bubble = (BubbleButton *)GetWindowLong(hwnd, GWL_USERDATA); + + if(!bubble) + return DefWindowProc(hwnd, msg, mp1, mp2); + + switch(msg) + { +#ifndef NO_SIGNALS + case WM_LBUTTONUP: + { + SignalHandler *tmp = Root; + + /* Find any callbacks for this function */ + while(tmp) + { + if(tmp->message == WM_COMMAND) + { + int (*clickfunc)(HWND, void *) = tmp->signalfunction; + + /* Make sure it's the right window, and the right ID */ + if(tmp->window == hwnd) + { + clickfunc(tmp->window, tmp->data); + tmp = NULL; + } + } + if(tmp) + tmp= tmp->next; + } + } + break; +#endif + case WM_CHAR: + { +#ifndef NO_SIGNALS + /* A button press should also occur for an ENTER or SPACE press + * while the button has the active input focus. + */ + if(LOWORD(mp1) == '\r' || LOWORD(mp1) == ' ') + { + SignalHandler *tmp = Root; + + /* Find any callbacks for this function */ + while(tmp) + { + if(tmp->message == WM_COMMAND) + { + int (*clickfunc)(HWND, void *) = tmp->signalfunction; + + /* Make sure it's the right window, and the right ID */ + if(tmp->window == hwnd) + { + clickfunc(tmp->window, tmp->data); + tmp = NULL; + } + } + if(tmp) + tmp= tmp->next; + } + } +#endif + if(LOWORD(mp1) == '\t') + { + _shift_focus(hwnd); + return FALSE; + } + } + break; + case WM_TIMER: + if (hwndBubble) + { + DestroyWindow(hwndBubble); + hwndBubble = 0; + KillTimer(hwnd, 1); + } + break; + + case WM_MOUSEMOVE: + GetCursorPos(&point); + GetWindowRect(hwnd, &rect); + + if(PtInRect(&rect, point)){ + if(hwnd != GetCapture()){ + SetCapture(hwnd); + } + if(!bMouseOver){ + bMouseOver = 1; + if(!*bubble->bubbletext) + break; + + if(hwndBubble) + { + DestroyWindow(hwndBubble); + hwndBubble = 0; + KillTimer(hwndBubbleLast, 1); + } + + if(!hwndBubble) + { + POINTL ptlWork = {0,0}; + ULONG ulColor = DW_CLR_YELLOW; + SIZE size; + HDC hdc; + RECT rect; + void *oldproc; + + /* Use the WS_EX_TOOLWINDOW extended style + * so the window doesn't get listed in the + * taskbar. + */ + hwndBubble = CreateWindowEx(WS_EX_TOOLWINDOW, + STATICCLASSNAME, + bubble->bubbletext, + BS_TEXT | WS_POPUP | + WS_BORDER | + SS_CENTER, + 0,0,50,20, + HWND_DESKTOP, + NULL, + NULL, + NULL); + + dw_window_set_font(hwndBubble, DefaultFont); + dw_window_set_color(hwndBubble, DW_CLR_BLACK, DW_CLR_YELLOW); + + hwndBubbleLast = hwnd; + + SetTimer(hwnd, 1, 3000, NULL); + + hdc = GetDC(hwndBubble); + + GetTextExtentPoint(hdc, bubble->bubbletext, strlen(bubble->bubbletext), &size); + + MapWindowPoints(hwnd, HWND_DESKTOP, (LPPOINT)&ptlWork, 1); + + GetWindowRect(hwnd, &rect); + + SetWindowPos(hwndBubble, + HWND_TOP, + ptlWork.x, + ptlWork.y + (rect.bottom-rect.top) + 1, + size.cx + 2, + size.cy + 2, + SWP_NOACTIVATE | SWP_SHOWWINDOW); + + } + } + } + else{ + /* Calling ReleaseCapture in Win95 also causes WM_CAPTURECHANGED + * to be sent. Be sure to account for that. + */ + ReleaseCapture(); + + if(bMouseOver){ + bMouseOver = 0; + DestroyWindow(hwndBubble); + hwndBubble = 0; + KillTimer(hwndBubbleLast, 1); + } + } + break; + case WM_CAPTURECHANGED: + /* This message means we are losing the capture for some reason + * Either because we intentionally lost it or another window + * stole it + */ + if(bMouseOver){ + bMouseOver = 0; + DestroyWindow(hwndBubble); + hwndBubble = 0; + KillTimer(hwndBubbleLast, 1); + } + break; + } + + if(!bubble->pOldProc) + return DefWindowProc(hwnd, msg, mp1, mp2); + return CallWindowProc(bubble->pOldProc, hwnd, msg, mp1, mp2); +} + +void _resize_notebook_page(HWND handle, int pageid) +{ + RECT rect; + NotebookPage **array = (NotebookPage **)GetWindowLong(handle, GWL_USERDATA); + + if(array && array[pageid]) + { + Box *box = (Box *)GetWindowLong(array[pageid]->hwnd, GWL_USERDATA); + + GetClientRect(handle,&rect); + TabCtrl_AdjustRect(handle,FALSE,&rect); + MoveWindow(array[pageid]->hwnd,rect.left,rect.top, + rect.right - rect.left,rect.bottom-rect.top, + TRUE); + if(box) + _do_resize(box, rect.right - rect.left, rect.bottom - rect.top); + + ShowWindow(array[pageid]->hwnd,SW_SHOWNORMAL); + } +} + +/* + * Initializes the Dynamic Windows engine. + * Parameters: + * newthread: True if this is the only thread. + * False if there is already a message loop running. + */ +int dw_init(int newthread) +{ + WNDCLASS wc; + int z; + INITCOMMONCONTROLSEX icc; + + icc.dwSize = sizeof(INITCOMMONCONTROLSEX); + icc.dwICC = ICC_WIN95_CLASSES; + + InitCommonControlsEx(&icc); + + memset(lookup, 0, sizeof(HICON) * ICON_INDEX_LIMIT); + + memset(&wc, 0, sizeof(WNDCLASS)); + wc.style = CS_DBLCLKS /*| CS_HREDRAW | CS_VREDRAW*/; + wc.lpfnWndProc = (WNDPROC)_wndproc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 32; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = ClassName; + + RegisterClass(&wc); + + memset(&wc, 0, sizeof(WNDCLASS)); + wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = (WNDPROC)_splitwndproc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = SplitbarClassName; + + RegisterClass(&wc); + + memset(&wc, 0, sizeof(WNDCLASS)); + wc.style = CS_DBLCLKS /*| CS_HREDRAW | CS_VREDRAW*/; + wc.lpfnWndProc = (WNDPROC)_framewndproc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 32; + wc.hbrBackground = (HBRUSH)COLOR_WINDOW; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.lpszMenuName = NULL; + wc.lpszClassName = FRAMECLASSNAME; + + for(z=0;z<18;z++) + _colors[z] = CreateSolidBrush(RGB(_red[z],_green[z],_blue[z])); + + RegisterClass(&wc); + + memset(&wc, 0, sizeof(WNDCLASS)); + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)_wndproc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = NULL; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.lpszMenuName = NULL; + wc.lpszClassName = ObjectClassName; + + RegisterClass(&wc); + + /* Since Windows 95/98/NT don't have a HWND_OBJECT class + * also known as a input only window, I will create a + * temporary window that isn't visible and really does nothing + * except temporarily hold the child windows before they are + * packed into their correct parent. + */ + + DW_HWND_OBJECT = CreateWindow(ObjectClassName, "", 0, 0, 0, + 0, 0, HWND_DESKTOP, NULL, NULL, NULL); + + if(!DW_HWND_OBJECT) + { + dw_messagebox("Dynamic Windows", "Could not initialize the object window. error code %d", GetLastError()); + exit(1); + } + +#ifdef DWDEBUG + f = fopen("dw.log", "wt"); +#endif + /* We need the version to check capability like up-down controls */ + dwVersion = GetVersion(); + + _hPen = CreatePen(PS_SOLID, 1, _foreground); + _hBrush = CreateSolidBrush(_foreground); + + return 0; +} + +/* + * Runs a message loop for Dynamic Windows. + * Parameters: + * currenthab: The handle to the current anchor block + * or NULL if this DW is handling the message loop. + * func: Function pointer to the message filter function. + */ +void dw_main(HAB currenthab, void *func) +{ + MSG msg; + + /* Setup the filter function */ + filterfunc = func; + + while (GetMessage(&msg,NULL,0,0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + +#ifdef DWDEBUG + fclose(f); +#endif +} + +/* + * Free's memory allocated by dynamic windows. + * Parameters: + * ptr: Pointer to dynamic windows allocated + * memory to be free()'d. + */ +void dw_free(void *ptr) +{ + free(ptr); +} + +/* + * Allocates and initializes a dialog struct. + * Parameters: + * data: User defined data to be passed to functions. + */ +DWDialog *dw_dialog_new(void *data) +{ + DWDialog *tmp = malloc(sizeof(DWDialog)); + + tmp->eve = dw_event_new(); + dw_event_reset(tmp->eve); + tmp->data = data; + tmp->done = FALSE; + tmp->result = NULL; + + return tmp; +} + +/* + * Accepts a dialog struct and returns the given data to the + * initial called of dw_dialog_wait(). + * Parameters: + * dialog: Pointer to a dialog struct aquired by dw_dialog_new). + * result: Data to be returned by dw_dialog_wait(). + */ +int dw_dialog_dismiss(DWDialog *dialog, void *result) +{ + dialog->result = result; + dw_event_post(dialog->eve); + dialog->done = TRUE; + return 0; +} + +/* + * Accepts a dialog struct waits for dw_dialog_dismiss() to be + * called by a signal handler with the given dialog struct. + * Parameters: + * dialog: Pointer to a dialog struct aquired by dw_dialog_new). + */ +void *dw_dialog_wait(DWDialog *dialog) +{ + MSG msg; + void *tmp; + + while (GetMessage(&msg,NULL,0,0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + if(dialog->done) + break; + } + dw_event_close(&dialog->eve); + tmp = dialog->result; + free(dialog); + return tmp; +} + +/* + * Displays a Message Box with given text and title.. + * Parameters: + * title: The title of the message box. + * format: printf style format string. + * ...: Additional variables for use in the format. + */ +int dw_messagebox(char *title, char *format, ...) +{ + va_list args; + char outbuf[256]; + + va_start(args, format); + vsprintf(outbuf, format, args); + va_end(args); + + MessageBox(HWND_DESKTOP, outbuf, title, MB_OK); + + return strlen(outbuf); +} + +/* + * Displays a Message Box with given text and title.. + * Parameters: + * title: The title of the message box. + * text: The text to display in the box. + * Returns: + * True if YES False of NO. + */ +int dw_yesno(char *title, char *text) +{ + if(MessageBox(HWND_DESKTOP, text, title, MB_YESNO)==IDYES) + return TRUE; + return FALSE; +} + +/* + * Makes the window visible. + * Parameters: + * handle: The window handle to make visible. + */ +int dw_window_show(HWND handle) +{ + int rc = ShowWindow(handle, TRUE); + SetFocus(handle); + _initial_focus(handle); + return rc; +} + +/* + * Makes the window invisible. + * Parameters: + * handle: The window handle to make visible. + */ +int dw_window_hide(HWND handle) +{ + return ShowWindow(handle, FALSE); +} + +/* + * Destroys a window and all of it's children. + * Parameters: + * handle: The window handle to destroy. + */ +int dw_window_destroy(HWND handle) +{ + return DestroyWindow(handle); +} + +/* + * Changes a window's parent to newparent. + * Parameters: + * handle: The window handle to destroy. + * newparent: The window's new parent window. + */ +void dw_window_reparent(HWND handle, HWND newparent) +{ + SetParent(handle, newparent); +} + +HFONT _aquire_font(char *fontname) +{ + HFONT hfont; + int z, size = 9; + LOGFONT lf; + + if(fontname == DefaultFont) + hfont = GetStockObject(DEFAULT_GUI_FONT); + else + { + for(z=0;z<strlen(fontname);z++) + { + if(fontname[z]=='.') + break; + } + size = atoi(fontname) + 5; + + lf.lfHeight = size; + lf.lfWidth = 0; + lf.lfEscapement = 0; + lf.lfOrientation = 0; + lf.lfItalic = 0; + lf.lfUnderline = 0; + lf.lfStrikeOut = 0; + lf.lfWeight = FW_NORMAL; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfOutPrecision = 0; + lf.lfClipPrecision = 0; + lf.lfQuality = DEFAULT_QUALITY; + lf.lfPitchAndFamily = DEFAULT_PITCH | FW_DONTCARE; + strcpy(lf.lfFaceName, &fontname[z+1]); + + hfont = CreateFontIndirect(&lf); + } + return hfont; +} + +/* + * Sets the font used by a specified window (widget) handle. + * Parameters: + * handle: The window (widget) handle. + * fontname: Name and size of the font in the form "size.fontname" + */ +int dw_window_set_font(HWND handle, char *fontname) +{ + HFONT hfont = _aquire_font(fontname); + ColorInfo *cinfo; + + cinfo = (ColorInfo *)GetWindowLong(handle, GWL_USERDATA); + + if(fontname) + { + if(cinfo) + { + strcpy(cinfo->fontname, fontname); + } + else + { + cinfo = calloc(1, sizeof(ColorInfo)); + cinfo->fore = cinfo->back = -1; + cinfo->buddy = 0; + + strcpy(cinfo->fontname, fontname); + + cinfo->pOldProc = SubclassWindow(handle, _colorwndproc); + SetWindowLong(handle, GWL_USERDATA, (ULONG)cinfo); + } + } + SendMessage(handle, WM_SETFONT, (WPARAM)hfont, FALSE); + return 0; +} + +/* + * Sets the colors used by a specified window (widget) handle. + * Parameters: + * handle: The window (widget) handle. + * fore: Foreground color in RGB format. + * back: Background color in RGB format. + */ +int dw_window_set_color(HWND handle, ULONG fore, ULONG back) +{ + ColorInfo *cinfo; + char tmpbuf[100]; + + cinfo = (ColorInfo *)GetWindowLong(handle, GWL_USERDATA); + + GetClassName(handle, tmpbuf, 99); + + if(strnicmp(tmpbuf, FRAMECLASSNAME, strlen(FRAMECLASSNAME))==0) + return FALSE; + + if(cinfo) + { + cinfo->fore = fore; + cinfo->back = back; + } + else + { + cinfo = calloc(1, sizeof(ColorInfo)); + + cinfo->fore = fore; + cinfo->back = back; + cinfo->buddy = 0; + + cinfo->pOldProc = SubclassWindow(handle, _colorwndproc); + SetWindowLong(handle, GWL_USERDATA, (ULONG)cinfo); + } + return TRUE; +} + +/* + * Sets the font used by a specified window (widget) handle. + * Parameters: + * handle: The window (widget) handle. + * border: Size of the window border in pixels. + */ +int dw_window_set_border(HWND handle, int border) +{ + return 0; +} + +/* + * Captures the mouse input to this window. + * Parameters: + * handle: Handle to receive mouse input. + */ +void dw_window_capture(HWND handle) +{ + SetCapture(handle); +} + +/* + * Releases previous mouse capture. + */ +void dw_window_release(void) +{ + ReleaseCapture(); +} + +/* + * Create a new Window Frame. + * Parameters: + * owner: The Owner's window handle or HWND_DESKTOP. + * title: The Window title. + * flStyle: Style flags, see the DW reference. + */ +HWND dw_window_new(HWND hwndOwner, char *title, ULONG flStyle) +{ + HWND hwndframe; + Box *newbox = malloc(sizeof(Box)); + + newbox->pad = 0; + newbox->type = BOXVERT; + newbox->count = 0; + + if(!(flStyle & WS_CAPTION)) + flStyle |= WS_POPUPWINDOW; + if(flStyle & DW_FCF_TASKLIST) + { + ULONG newflags = (flStyle | WS_CLIPCHILDREN) & ~DW_FCF_TASKLIST; + hwndframe = CreateWindow(ClassName, title, newflags, CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner, NULL, NULL, NULL); + } + else + hwndframe = CreateWindowEx(WS_EX_TOOLWINDOW, ClassName, title, flStyle | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner, NULL, NULL, NULL); + SetWindowLong(hwndframe, GWL_USERDATA, (ULONG)newbox); + + return hwndframe; +} + +/* + * Create a new Box to be packed. + * Parameters: + * type: Either BOXVERT (vertical) or BOXHORZ (horizontal). + * pad: Number of pixels to pad around the box. + */ +HWND dw_box_new(int type, int pad) +{ + Box *newbox = malloc(sizeof(Box)); + HWND hwndframe; + + newbox->pad = pad; + newbox->type = type; + newbox->count = 0; + newbox->grouphwnd = (HWND)NULL; + + hwndframe = CreateWindow(FRAMECLASSNAME, + "", + WS_CHILD | WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + NULL, + NULL, + NULL); + + newbox->cinfo.pOldProc = SubclassWindow(hwndframe, _colorwndproc); + newbox->cinfo.fore = newbox->cinfo.back = -1; + + SetWindowLong(hwndframe, GWL_USERDATA, (ULONG)newbox); + return hwndframe; +} + +/* + * Create a new Group Box to be packed. + * Parameters: + * type: Either BOXVERT (vertical) or BOXHORZ (horizontal). + * pad: Number of pixels to pad around the box. + * title: Text to be displayined in the group outline. + */ +HWND dw_groupbox_new(int type, int pad, char *title) +{ + Box *newbox = malloc(sizeof(Box)); + HWND hwndframe; + + newbox->pad = pad; + newbox->type = type; + newbox->count = 0; + + hwndframe = CreateWindow(FRAMECLASSNAME, + "", + WS_CHILD, + 0,0,2000,1000, + DW_HWND_OBJECT, + NULL, + NULL, + NULL); + + newbox->grouphwnd = CreateWindow(BUTTONCLASSNAME, + title, + WS_CHILD | BS_GROUPBOX | + WS_VISIBLE | WS_CLIPCHILDREN, + 0,0,2000,1000, + hwndframe, + NULL, + NULL, + NULL); + + SetWindowLong(hwndframe, GWL_USERDATA, (ULONG)newbox); + dw_window_set_font(newbox->grouphwnd, DefaultFont); + return hwndframe; +} + +/* + * Create a bitmap object to be packed. + * Parameters: + * id: An ID to be used with WinWindowFromID() or 0L. + */ +HWND dw_bitmap_new(ULONG id) +{ + return CreateWindow(STATICCLASSNAME, + "", + SS_BITMAP | WS_CHILD | WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + NULL, + NULL, + NULL); +} + +/* + * Create a notebook object to be packed. + * Parameters: + * id: An ID to be used for getting the resource from the + * resource file. + */ +HWND dw_notebook_new(ULONG id, int top) +{ + ULONG flags = 0; + HWND tmp; + NotebookPage **array = calloc(256, sizeof(NotebookPage *)); + + if(!top) + flags = TCS_BOTTOM; + + tmp = CreateWindow(WC_TABCONTROL, + "", + WS_CHILD | WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + NULL, + NULL, + NULL); + SetWindowLong(tmp, GWL_USERDATA, (ULONG)array); + dw_window_set_font(tmp, DefaultFont); + return tmp; +} + +/* + * Create a menu object to be popped up. + * Parameters: + * id: An ID to be used for getting the resource from the + * resource file. + */ +HMENUI dw_menu_new(ULONG id) +{ + HMENUI tmp = malloc(sizeof(struct _hmenui)); + + if(!tmp) + return NULL; + + tmp->menu = CreatePopupMenu(); + tmp->hwnd = NULL; + return tmp; +} + +/* + * Create a menubar on a window. + * Parameters: + * location: Handle of a window frame to be attached to. + */ +HMENUI dw_menubar_new(HWND location) +{ + HMENUI tmp = malloc(sizeof(struct _hmenui)); + + if(!tmp) + return NULL; + + tmp->menu = CreateMenu(); + tmp->hwnd = location; + + SetMenu(location, tmp->menu); + return tmp; +} + +/* + * Destroys a menu created with dw_menubar_new or dw_menu_new. + * Parameters: + * menu: Handle of a menu. + */ +void dw_menu_destroy(HMENUI *menu) +{ + if(menu && *menu) + { + DestroyMenu((*menu)->menu); + free(*menu); + *menu = NULL; + } +} + +/* + * Adds a menuitem or submenu to an existing menu. + * Parameters: + * menu: The handle the the existing menu. + * title: The title text on the menu item to be added. + * id: An ID to be used for message passing. + * end: If TRUE memu is positioned at the end of the menu. + * check: If TRUE menu is "check"able. + * flags: Extended attributes to set on the menu. + * submenu: Handle to an existing menu to be a submenu or NULL. + */ +HWND dw_menu_append_item(HMENUI menux, char *title, ULONG id, ULONG flags, int end, int check, HMENUI submenu) +{ + MENUITEMINFO mii; + HMENU menu; + + if(!menux) + return NULL; + + menu = menux->menu; + + mii.cbSize = sizeof(MENUITEMINFO); + mii.fMask = MIIM_ID | MIIM_SUBMENU | MIIM_TYPE; + + /* Convert from OS/2 style accellerators to Win32 style */ + if(title) + { + char *tmp = title; + + while(*tmp) + { + if(*tmp == '~') + *tmp = '&'; + tmp++; + } + } + + if(title && *title) + mii.fType = MFT_STRING; + else + mii.fType = MFT_SEPARATOR; + + mii.wID = id; + mii.hSubMenu = submenu ? submenu->menu : 0; + mii.dwTypeData = title; + mii.cch = strlen(title); + + InsertMenuItem(menu, 65535, TRUE, &mii); + if(menux->hwnd) + DrawMenuBar(menux->hwnd); + return (HWND)id; +} + +/* + * Sets the state of a menu item check. + * Parameters: + * menu: The handle the the existing menu. + * id: Menuitem id. + * check: TRUE for checked FALSE for not checked. + */ +void dw_menu_item_set_check(HMENUI menux, int id, int check) +{ + MENUITEMINFO mii; + HMENU menu; + + if(!menux) + return; + + menu = menux->menu; + + mii.cbSize = sizeof(MENUITEMINFO); + mii.fMask = MIIM_STATE; + if(check) + mii.fState = MFS_CHECKED; + else + mii.fState = MFS_UNCHECKED; + SetMenuItemInfo(menu, id, FALSE, &mii); +} + +/* + * Pops up a context menu at given x and y coordinates. + * Parameters: + * menu: The handle the the existing menu. + * parent: Handle to the window initiating the popup. + * x: X coordinate. + * y: Y coordinate. + */ +void dw_menu_popup(HMENUI *menu, HWND parent, int x, int y) +{ + if(menu && *menu) + { + TrackPopupMenu((*menu)->menu, 0, x, y, 0, parent, NULL); + free(*menu); + *menu = NULL; + } +} + + +/* + * Create a container object to be packed. + * Parameters: + * id: An ID to be used for getting the resource from the + * resource file. + */ +HWND dw_container_new(ULONG id) +{ + HWND tmp = CreateWindow(WC_LISTVIEW, + "", + WS_CHILD | LVS_REPORT | + LVS_SHAREIMAGELISTS | WS_BORDER | + WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + (HMENU)id, + NULL, + NULL); + ContainerInfo *cinfo = (ContainerInfo *)calloc(1, sizeof(ContainerInfo)); + + if(!cinfo) + { + DestroyWindow(tmp); + return NULL; + } + + cinfo->pOldProc = (WNDPROC)SubclassWindow(tmp, _containerwndproc); + + SetWindowLong(tmp, GWL_USERDATA, (ULONG)cinfo); + dw_window_set_font(tmp, DefaultFont); + return tmp; +} + +/* + * Returns the current X and Y coordinates of the mouse pointer. + * Parameters: + * x: Pointer to variable to store X coordinate. + * y: Pointer to variable to store Y coordinate. + */ +void dw_pointer_query_pos(long *x, long *y) +{ + POINT ptl; + + GetCursorPos(&ptl); + if(x && y) + { + *x = ptl.x; + *y = ptl.y; + } +} + +/* + * Sets the X and Y coordinates of the mouse pointer. + * Parameters: + * x: X coordinate. + * y: Y coordinate. + */ +void dw_pointer_set_pos(long x, long y) +{ + SetCursorPos(x, y); +} + +/* + * Create a new static text window (widget) to be packed. + * Parameters: + * text: The text to be display by the static text widget. + * id: An ID to be used with WinWindowFromID() or 0L. + */ +HWND dw_text_new(char *text, ULONG id) +{ + HWND tmp = CreateWindow(STATICCLASSNAME, + text, + BS_TEXT | WS_CHILD | WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + (HMENU)id, + NULL, + NULL); + dw_window_set_font(tmp, DefaultFont); + return tmp; +} + +/* + * Create a new Multiline Editbox window (widget) to be packed. + * Parameters: + * id: An ID to be used with WinWindowFromID() or 0L. + */ +HWND dw_mle_new(ULONG id) +{ + + HWND tmp = CreateWindow(EDITCLASSNAME, + "", + WS_BORDER | ES_AUTOHSCROLL | + WS_VSCROLL | ES_MULTILINE | + ES_WANTRETURN | WS_CHILD | + WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + (HMENU)id, + NULL, + NULL); + dw_window_set_font(tmp, DefaultFont); + return tmp; +} + +/* + * Create a new Entryfield window (widget) to be packed. + * Parameters: + * text: The default text to be in the entryfield widget. + * id: An ID to be used with WinWindowFromID() or 0L. + */ +HWND dw_entryfield_new(char *text, ULONG id) +{ + HWND tmp = CreateWindow(EDITCLASSNAME, + text, + ES_WANTRETURN | WS_CHILD | + WS_BORDER | ES_AUTOHSCROLL | + WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + (HMENU)id, + NULL, + NULL); + ColorInfo *cinfo = calloc(1, sizeof(ColorInfo)); + + cinfo->back = cinfo->fore = -1; + cinfo->buddy = 0; + + cinfo->pOldProc = SubclassWindow(tmp, _colorwndproc); + SetWindowLong(tmp, GWL_USERDATA, (ULONG)cinfo); + dw_window_set_font(tmp, DefaultFont); + return tmp; +} + +/* + * Create a new Entryfield passwird window (widget) to be packed. + * Parameters: + * text: The default text to be in the entryfield widget. + * id: An ID to be used with WinWindowFromID() or 0L. + */ +HWND dw_entryfield_password_new(char *text, ULONG id) +{ + HWND tmp = CreateWindow(EDITCLASSNAME, + text, + ES_WANTRETURN | WS_CHILD | + ES_PASSWORD | WS_BORDER | + ES_AUTOHSCROLL | WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + (HMENU)id, + NULL, + NULL); + ColorInfo *cinfo = calloc(1, sizeof(ColorInfo)); + + cinfo->back = cinfo->fore = -1; + cinfo->buddy = 0; + + cinfo->pOldProc = SubclassWindow(tmp, _colorwndproc); + SetWindowLong(tmp, GWL_USERDATA, (ULONG)cinfo); + dw_window_set_font(tmp, DefaultFont); + return tmp; +} + +/* + * Create a new Combobox window (widget) to be packed. + * Parameters: + * text: The default text to be in the combpbox widget. + * id: An ID to be used with WinWindowFromID() or 0L. + */ +HWND dw_combobox_new(char *text, ULONG id) +{ + HWND tmp = CreateWindow(COMBOBOXCLASSNAME, + "", + WS_CHILD | CBS_DROPDOWN | WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + (HMENU)id, + NULL, + NULL); + ContainerInfo *cinfo = (ContainerInfo *)calloc(1, sizeof(ContainerInfo)); + + if(!cinfo) + { + DestroyWindow(tmp); + return NULL; + } + + cinfo->cinfo.fore = -1; + cinfo->cinfo.back = -1; + cinfo->pOldProc = (WNDPROC)SubclassWindow(tmp, _containerwndproc); + + SetWindowLong(tmp, GWL_USERDATA, (ULONG)cinfo); + dw_window_set_font(tmp, DefaultFont); + return tmp; +} + +/* + * Create a new button window (widget) to be packed. + * Parameters: + * text: The text to be display by the static text widget. + * id: An ID to be used with WinWindowFromID() or 0L. + */ +HWND dw_button_new(char *text, ULONG id) +{ + BubbleButton *bubble = malloc(sizeof(BubbleButton)); + + HWND tmp = CreateWindow(BUTTONCLASSNAME, + text, + WS_CHILD | BS_PUSHBUTTON | WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + (HMENU)id, + NULL, + NULL); + + bubble->id = id; + bubble->bubbletext[0] = '\0'; + bubble->pOldProc = (WNDPROC)SubclassWindow(tmp, _BtProc); + + SetWindowLong(tmp, GWL_USERDATA, (ULONG)bubble); + dw_window_set_font(tmp, DefaultFont); + return tmp; +} + +/* + * Create a new bitmap button window (widget) to be packed. + * Parameters: + * text: Bubble help text to be displayed. + * id: An ID of a bitmap in the resource file. + */ +HWND dw_bitmapbutton_new(char *text, ULONG id) +{ + HWND tmp; + BubbleButton *bubble = malloc(sizeof(BubbleButton)); + HBITMAP hbitmap = LoadBitmap(DWInstance, MAKEINTRESOURCE(id)); + + tmp = CreateWindow(BUTTONCLASSNAME, + "", + WS_CHILD | BS_PUSHBUTTON | + BS_BITMAP | WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + (HMENU)id, + NULL, + NULL); + + bubble->id = id; + strncpy(bubble->bubbletext, text, BUBBLE_HELP_MAX - 1); + bubble->bubbletext[BUBBLE_HELP_MAX - 1] = '\0'; + bubble->pOldProc = (WNDPROC)SubclassWindow(tmp, _BtProc); + + SetWindowLong(tmp, GWL_USERDATA, (ULONG)bubble); + + SendMessage(tmp, BM_SETIMAGE, + (WPARAM) IMAGE_BITMAP, + (LPARAM) hbitmap); + return tmp; +} + +/* + * Create a new spinbutton window (widget) to be packed. + * Parameters: + * text: The text to be display by the static text widget. + * id: An ID to be used with WinWindowFromID() or 0L. + */ +HWND dw_spinbutton_new(char *text, ULONG id) +{ + ULONG *data = malloc(sizeof(ULONG)); + HWND buddy = CreateWindow(EDITCLASSNAME, + text, + WS_CHILD | WS_BORDER | + ES_NUMBER | WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + NULL, + NULL, + NULL); + HWND tmp = CreateUpDownControl( + WS_CHILD | UDS_ALIGNRIGHT | + UDS_ARROWKEYS | UDS_SETBUDDYINT | + UDS_WRAP | UDS_NOTHOUSANDS, + 0, + 0, + 2000, + 1000, + DW_HWND_OBJECT, + id, + DWInstance, + buddy, + 0, + 100, + 0); + ColorInfo *cinfo = calloc(1, sizeof(ColorInfo)); + + cinfo->back = cinfo->fore = -1; + cinfo->buddy = tmp; + + cinfo->pOldProc = SubclassWindow(buddy, _colorwndproc); + SetWindowLong(buddy, GWL_USERDATA, (ULONG)cinfo); + + cinfo = calloc(1, sizeof(ColorInfo)); + cinfo->buddy = buddy; + cinfo->pOldProc = SubclassWindow(tmp, _spinnerwndproc); + + SetWindowLong(tmp, GWL_USERDATA, (ULONG)cinfo); + dw_window_set_font(buddy, DefaultFont); + return tmp; +} + +/* + * Create a new radiobutton window (widget) to be packed. + * Parameters: + * text: The text to be display by the static text widget. + * id: An ID to be used with WinWindowFromID() or 0L. + */ +HWND dw_radiobutton_new(char *text, ULONG id) +{ + HWND tmp = CreateWindow(BUTTONCLASSNAME, + text, + WS_CHILD | BS_AUTORADIOBUTTON | + WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + (HMENU)id, + NULL, + NULL); + + ColorInfo *cinfo = calloc(1, sizeof(ColorInfo)); + + cinfo->back = cinfo->fore = -1; + cinfo->buddy = 0; + cinfo->user = 0; + + cinfo->pOldProc = SubclassWindow(tmp, _colorwndproc); + SetWindowLong(tmp, GWL_USERDATA, (ULONG)cinfo); + dw_window_set_font(tmp, DefaultFont); + return tmp; +} + + +/* + * Create a new slider window (widget) to be packed. + * Parameters: + * id: An ID to be used with WinWindowFromID() or 0L. + */ +HWND dw_slider_new(ULONG id) +{ + return CreateWindow(PROGRESS_CLASS, + "", + WS_CHILD | WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + NULL, + NULL, + NULL); +} + +/* + * Create a new checkbox window (widget) to be packed. + * Parameters: + * text: The text to be display by the static text widget. + * id: An ID to be used with WinWindowFromID() or 0L. + */ +HWND dw_checkbox_new(char *text, ULONG id) +{ + HWND tmp = CreateWindow(BUTTONCLASSNAME, + text, + WS_CHILD | BS_AUTOCHECKBOX | + BS_TEXT | WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + NULL, + NULL, + NULL); + ColorInfo *cinfo = calloc(1, sizeof(ColorInfo)); + + cinfo->back = cinfo->fore = -1; + cinfo->buddy = 0; + cinfo->user = 1; + + cinfo->pOldProc = SubclassWindow(tmp, _colorwndproc); + SetWindowLong(tmp, GWL_USERDATA, (ULONG)cinfo); + dw_window_set_font(tmp, DefaultFont); + return tmp; +} + +/* + * Create a new listbox window (widget) to be packed. + * Parameters: + * id: An ID to be used with WinWindowFromID() or 0L. + * multi: Multiple select TRUE or FALSE. + */ +HWND dw_listbox_new(ULONG id, int multi) +{ + HWND tmp = CreateWindow(LISTBOXCLASSNAME, + "", + LBS_NOINTEGRALHEIGHT | WS_CHILD | LBS_HASSTRINGS | + LBS_NOTIFY | WS_BORDER | WS_CLIPCHILDREN | + WS_VSCROLL | (multi ? LBS_EXTENDEDSEL : 0) , + 0,0,2000,1000, + DW_HWND_OBJECT, + NULL, + NULL, + NULL); + ContainerInfo *cinfo = (ContainerInfo *)calloc(1, sizeof(ContainerInfo)); + + if(!cinfo) + { + DestroyWindow(tmp); + return NULL; + } + + cinfo->cinfo.fore = -1; + cinfo->cinfo.back = -1; + cinfo->pOldProc = (WNDPROC)SubclassWindow(tmp, _containerwndproc); + + SetWindowLong(tmp, GWL_USERDATA, (ULONG)cinfo); + dw_window_set_font(tmp, DefaultFont); + return tmp; +} + +/* + * Sets the icon used for a given window. + * Parameters: + * handle: Handle to the window. + * id: An ID to be used to specify the icon. + */ +void dw_window_set_icon(HWND handle, ULONG id) +{ + HICON hicon = LoadIcon(DWInstance, MAKEINTRESOURCE(id)); + + SendMessage(handle, WM_SETICON, + (WPARAM) IMAGE_ICON, + (LPARAM) hicon); +} + +/* + * Sets the bitmap used for a given static window. + * Parameters: + * handle: Handle to the window. + * id: An ID to be used to specify the icon. + */ +void dw_window_set_bitmap(HWND handle, ULONG id) +{ + HBITMAP hbitmap = LoadBitmap(DWInstance, MAKEINTRESOURCE(id)); + + SendMessage(handle, STM_SETIMAGE, + (WPARAM) IMAGE_BITMAP, + (LPARAM) hbitmap); +} + +/* + * Sets the text used for a given window. + * Parameters: + * handle: Handle to the window. + * text: The text associsated with a given window. + */ +void dw_window_set_text(HWND handle, char *text) +{ + SetWindowText(handle, text); +} + +/* + * Gets the text used for a given window. + * Parameters: + * handle: Handle to the window. + * Returns: + * text: The text associsated with a given window. + */ +char *dw_window_get_text(HWND handle) +{ + char tempbuf[4096] = ""; + + GetWindowText(handle, tempbuf, 4095); + tempbuf[4095] = 0; + + return strdup(tempbuf); +} + +/* + * Disables given window (widget). + * Parameters: + * handle: Handle to the window. + */ +void dw_window_disable(HWND handle) +{ + EnableWindow(handle, FALSE); +} + +/* + * Enables given window (widget). + * Parameters: + * handle: Handle to the window. + */ +void dw_window_enable(HWND handle) +{ + EnableWindow(handle, TRUE); +} + +/* + * Gets the child window handle with specified ID. + * Parameters: + * handle: Handle to the parent window. + * id: Integer ID of the child. + */ +HWND dw_window_from_id(HWND handle, int id) +{ + return 0L; +} +/* + * 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. + * 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. + * vsize: TRUE if the window (widget) should expand vertically to fill space given. + * pad: Number of pixels of padding around the item. + */ +void dw_box_pack_start(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad) +{ + Box *thisbox; + + thisbox = (Box *)GetWindowLong(box, GWL_USERDATA); + if(thisbox) + { + int z; + Item *tmpitem, *thisitem = thisbox->items; + char tmpbuf[100]; + + tmpitem = malloc(sizeof(Item)*(thisbox->count+1)); + + for(z=0;z<thisbox->count;z++) + { + tmpitem[z] = thisitem[z]; + } + + GetClassName(item, tmpbuf, 99); + + if(strnicmp(tmpbuf, FRAMECLASSNAME, 2)==0) + tmpitem[thisbox->count].type = TYPEBOX; + else + tmpitem[thisbox->count].type = TYPEITEM; + + tmpitem[thisbox->count].hwnd = item; + tmpitem[thisbox->count].origwidth = tmpitem[thisbox->count].width = width; + tmpitem[thisbox->count].origheight = tmpitem[thisbox->count].height = height; + tmpitem[thisbox->count].pad = pad; + if(hsize) + tmpitem[thisbox->count].hsize = SIZEEXPAND; + else + tmpitem[thisbox->count].hsize = SIZESTATIC; + + if(vsize) + tmpitem[thisbox->count].vsize = SIZEEXPAND; + else + tmpitem[thisbox->count].vsize = SIZESTATIC; + + thisbox->items = tmpitem; + + if(thisbox->count) + free(thisitem); + + thisbox->count++; + + SetParent(item, box); + ShowWindow(item, SW_SHOW); + if(strncmp(tmpbuf, UPDOWN_CLASS, strlen(UPDOWN_CLASS))==0) + { + ColorInfo *cinfo = (ColorInfo *)GetWindowLong(item, GWL_USERDATA); + + if(cinfo) + { + SetParent(cinfo->buddy, box); + ShowWindow(cinfo->buddy, SW_SHOW); + SendMessage(item, UDM_SETBUDDY, (WPARAM)cinfo->buddy, 0); + } + } + } +} + +/* + * Sets the size of a given window (widget). + * Parameters: + * handle: Window (widget) handle. + * width: New width in pixels. + * height: New height in pixels. + */ +void dw_window_set_usize(HWND handle, ULONG width, ULONG height) +{ + SetWindowPos(handle, (HWND)NULL, 0, 0, width, height, SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOMOVE); +} + +/* + * Returns the width of the screen. + */ +int dw_screen_width(void) +{ + return GetSystemMetrics(SM_CXSCREEN); +} + +/* + * Returns the height of the screen. + */ +int dw_screen_height(void) +{ + return GetSystemMetrics(SM_CYSCREEN); +} + +/* This should return the current color depth */ +unsigned long dw_color_depth(void) +{ + int bpp; + HDC hdc = GetDC(HWND_DESKTOP); + + bpp = GetDeviceCaps(hdc, BITSPIXEL); + + ReleaseDC(HWND_DESKTOP, hdc); + + return bpp; +} + + +/* + * Sets the position of a given window (widget). + * Parameters: + * handle: Window (widget) handle. + * x: X location from the bottom left. + * y: Y location from the bottom left. + */ +void dw_window_set_pos(HWND handle, ULONG x, ULONG y) +{ + SetWindowPos(handle, (HWND)NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); +} + +/* + * Sets the position and size of a given window (widget). + * Parameters: + * handle: Window (widget) handle. + * x: X location from the bottom left. + * y: Y location from the bottom left. + * width: Width of the widget. + * height: Height of the widget. + */ +void dw_window_set_pos_size(HWND handle, ULONG x, ULONG y, ULONG width, ULONG height) +{ + SetWindowPos(handle, (HWND)NULL, x, y, width, height, SWP_NOZORDER | SWP_SHOWWINDOW); +} + +/* + * Gets the position and size of a given window (widget). + * Parameters: + * handle: Window (widget) handle. + * x: X location from the bottom left. + * y: Y location from the bottom left. + * width: Width of the widget. + * height: Height of the widget. + */ +void dw_window_get_pos_size(HWND handle, ULONG *x, ULONG *y, ULONG *width, ULONG *height) +{ + WINDOWPLACEMENT wp; + + wp.length = sizeof(WINDOWPLACEMENT); + + GetWindowPlacement(handle, &wp); + if(x) + *x = wp.rcNormalPosition.left; + if(y) + *y = wp.rcNormalPosition.top; + if(width) + *width = wp.rcNormalPosition.right - wp.rcNormalPosition.left; + if(height) + *height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top; + +} + +/* + * Sets the style of a given window (widget). + * Parameters: + * handle: Window (widget) handle. + * width: New width in pixels. + * height: New height in pixels. + */ +void dw_window_set_style(HWND handle, ULONG style, ULONG mask) +{ + ULONG tmp, currentstyle = GetWindowLong(handle, GWL_STYLE); + + tmp = currentstyle | mask; + tmp ^= mask; + tmp |= style; + + SetWindowLong(handle, GWL_STYLE, tmp); +} + +/* Finds the physical ID from the reference ID */ +int _findnotebookid(NotebookPage **array, int pageid) +{ + int z; + + for(z=0;z<256;z++) + { + if(array[z] && array[z]->realid == pageid) + return z; + } + return -1; +} + +/* + * Adds a new page to specified notebook. + * Parameters: + * handle: Window (widget) handle. + * flags: Any additional page creation flags. + * front: If TRUE page is added at the beginning. + */ +ULONG dw_notebook_page_new(HWND handle, ULONG flags, int front) +{ + NotebookPage **array = (NotebookPage **)GetWindowLong(handle, GWL_USERDATA); + + if(array) + { + int z, refid = -1; + + for(z=0;z<256;z++) + { + if(_findnotebookid(array, z) == -1) + { + refid = z; + break; + } + } + + if(refid == -1) + return -1; + + for(z=0;z<256;z++) + { + if(!array[z]) + { + int oldpage = TabCtrl_GetCurSel(handle); + + array[z] = calloc(1, sizeof(NotebookPage)); + array[z]->realid = refid; + array[z]->item.mask = TCIF_TEXT; + array[z]->item.iImage = -1; + array[z]->item.pszText = ""; + TabCtrl_InsertItem(handle, z, &(array[z]->item)); + + if(oldpage > -1 && array[oldpage]) + SetParent(array[oldpage]->hwnd, DW_HWND_OBJECT); + + TabCtrl_SetCurSel(handle, z); + return refid; + } + } + } + return -1; +} + +/* + * Sets the text on the specified notebook tab. + * Parameters: + * handle: Notebook handle. + * pageid: Page ID of the tab to set. + * text: Pointer to the text to set. + */ +void dw_notebook_page_set_text(HWND handle, ULONG pageidx, char *text) +{ + + NotebookPage **array = (NotebookPage **)GetWindowLong(handle, GWL_USERDATA); + int pageid; + + if(!array) + return; + + pageid = _findnotebookid(array, pageidx); + + if(pageid > -1 && array[pageid]) + { + array[pageid]->item.mask = TCIF_TEXT; + array[pageid]->item.pszText = text; + TabCtrl_SetItem(handle, pageid, &(array[pageid]->item)); + _resize_notebook_page(handle, pageid); + } +} + +/* + * Sets the text on the specified notebook tab status area. + * Parameters: + * handle: Notebook handle. + * pageid: Page ID of the tab to set. + * text: Pointer to the text to set. + */ +void dw_notebook_page_set_status_text(HWND handle, ULONG pageid, char *text) +{ +} + +/* + * Packs the specified box into the notebook page. + * Parameters: + * handle: Handle to the notebook to be packed. + * pageid: Page ID in the notebook which is being packed. + * page: Box handle to be packed. + */ +void dw_notebook_pack(HWND handle, ULONG pageidx, HWND page) +{ + NotebookPage **array = (NotebookPage **)GetWindowLong(handle, GWL_USERDATA); + int pageid; + + if(!array) + return; + + pageid = _findnotebookid(array, pageidx); + + if(pageid > -1 && array[pageid]) + { + HWND tmpbox = dw_box_new(BOXVERT, 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; + if(pageidx == dw_notebook_page_query(handle)) + { + SetParent(tmpbox, handle); + _resize_notebook_page(handle, pageid); + } + } +} + +/* + * Remove a page from a notebook. + * Parameters: + * handle: Handle to the notebook widget. + * pageid: ID of the page to be destroyed. + */ +void dw_notebook_page_destroy(HWND handle, unsigned int pageidx) +{ + NotebookPage **array = (NotebookPage **)GetWindowLong(handle, GWL_USERDATA); + int newid = -1, z, pageid; + + if(!array) + return; + + pageid = _findnotebookid(array, pageidx); + + if(pageid < 0) + return; + + if(array[pageid]) + { + SetParent(array[pageid]->hwnd, DW_HWND_OBJECT); + free(array[pageid]); + array[pageid] = NULL; + } + + TabCtrl_DeleteItem(handle, pageid); + + /* Shift the pages over 1 */ + for(z=pageid;z<255;z++) + array[z] = array[z+1]; + array[255] = NULL; + + for(z=0;z<256;z++) + { + if(array[z]) + { + newid = z; + break; + } + } + if(newid > -1) + { + SetParent(array[newid]->hwnd, handle); + _resize_notebook_page(handle, newid); + dw_notebook_page_set(handle, array[newid]->realid); + } +} + +/* + * Queries the currently visible page ID. + * Parameters: + * handle: Handle to the notebook widget. + */ +unsigned int dw_notebook_page_query(HWND handle) +{ + NotebookPage **array = (NotebookPage **)GetWindowLong(handle, GWL_USERDATA); + int physid = TabCtrl_GetCurSel(handle); + + if(physid > -1 && physid < 256 && array && array[physid]) + return array[physid]->realid; + return -1; +} + +/* + * Sets the currently visible page ID. + * Parameters: + * handle: Handle to the notebook widget. + * pageid: ID of the page to be made visible. + */ +void dw_notebook_page_set(HWND handle, unsigned int pageidx) +{ + NotebookPage **array = (NotebookPage **)GetWindowLong(handle, GWL_USERDATA); + int pageid; + + if(!array) + return; + + pageid= _findnotebookid(array, pageidx); + + if(pageid > -1 && pageid < 256) + TabCtrl_SetCurSel(handle, pageid); +} + +/* + * Appends the specified text to the listbox's (or combobox) entry list. + * Parameters: + * handle: Handle to the listbox to be appended to. + * text: Text to append into listbox. + */ +void dw_listbox_append(HWND handle, char *text) +{ + char tmpbuf[100]; + + GetClassName(handle, tmpbuf, 99); + + if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME))==0) + SendMessage(handle, + CB_ADDSTRING, + 0, (LPARAM)text); + else + SendMessage(handle, + LB_ADDSTRING, + 0, (LPARAM)text); +} + +/* + * Clears the listbox's (or combobox) list of all entries. + * Parameters: + * handle: Handle to the listbox to be cleared. + */ +void dw_listbox_clear(HWND handle) +{ + char tmpbuf[100]; + + GetClassName(handle, tmpbuf, 99); + + if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME))==0) + { + char *buf = dw_window_get_text(handle); + + SendMessage(handle, + CB_RESETCONTENT, 0L, 0L); + + if(buf) + { + dw_window_set_text(handle, buf); + free(buf); + } + } + else + SendMessage(handle, + LB_RESETCONTENT, 0L, 0L); +} + +/* + * Sets the text of a given listbox entry. + * Parameters: + * handle: Handle to the listbox to be queried. + * index: Index into the list to be queried. + * buffer: Buffer where text will be copied. + */ +void dw_listbox_set_text(HWND handle, unsigned int index, char *buffer) +{ + unsigned int sel = (unsigned int)SendMessage(handle, LB_GETCURSEL, 0, 0); + SendMessage(handle, LB_DELETESTRING, (WPARAM)index, 0); + SendMessage(handle, LB_INSERTSTRING, (WPARAM)index, (LPARAM)buffer); + SendMessage(handle, LB_SETCURSEL, (WPARAM)sel, 0); + SendMessage(handle, LB_SETSEL, (WPARAM)TRUE, (LPARAM)sel); +} + +/* + * Copies the given index item's text into buffer. + * Parameters: + * handle: Handle to the listbox to be queried. + * index: Index into the list to be queried. + * buffer: Buffer where text will be copied. + * length: Length of the buffer (including NULL). + */ +void dw_listbox_query_text(HWND handle, unsigned int index, char *buffer, unsigned int length) +{ + SendMessage(handle, + LB_GETTEXT, (WPARAM)index, (LPARAM)buffer); +} + +/* + * Returns the index to the item in the list currently selected. + * Parameters: + * handle: Handle to the listbox to be queried. + */ +unsigned int dw_listbox_selected(HWND handle) +{ + char tmpbuf[100]; + + GetClassName(handle, tmpbuf, 99); + + if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME))==0) + return (unsigned int)SendMessage(handle, + CB_GETCURSEL, + 0, 0); + + return (unsigned int)SendMessage(handle, + LB_GETCURSEL, + 0, 0); +} + +/* + * Returns the index to the current selected item or -1 when done. + * Parameters: + * handle: Handle to the listbox to be queried. + * where: Either the previous return or -1 to restart. + */ +int dw_listbox_selected_multi(HWND handle, int where) +{ + int *array, count, z; + + count = (int)SendMessage(handle, LB_GETSELCOUNT, 0, 0); + if(count > 0) + { + array = malloc(sizeof(int)*count); + SendMessage(handle, LB_GETSELITEMS, (WPARAM)count, (LPARAM)array); + + if(where == -1) + { + int ret = array[0]; + free(array); + return ret; + } + for(z=0;z<count;z++) + { + if(array[z] == where && (z+1) < count) + { + int ret = array[z+1]; + free(array); + return ret; + } + } + free(array); + } + return -1; +} + +/* + * Sets the selection state of a given index. + * Parameters: + * handle: Handle to the listbox to be set. + * index: Item index. + * state: TRUE if selected FALSE if unselected. + */ +void dw_listbox_select(HWND handle, int index, int state) +{ + char tmpbuf[100]; + + GetClassName(handle, tmpbuf, 99); + + if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME))==0) + SendMessage(handle, CB_SETCURSEL, (WPARAM)index, 0); + else + { + SendMessage(handle, LB_SETCURSEL, (WPARAM)index, 0); + SendMessage(handle, LB_SETSEL, (WPARAM)state, (LPARAM)index); + } + _wndproc(handle, WM_COMMAND, (WPARAM)(LBN_SELCHANGE << 16), (LPARAM)handle); +} + +/* + * Deletes the item with given index from the list. + * Parameters: + * handle: Handle to the listbox to be set. + * index: Item index. + */ +void dw_listbox_delete(HWND handle, int index) +{ + SendMessage(handle, LB_DELETESTRING, (WPARAM)index, 0); +} + +/* + * Returns the listbox's item count. + * Parameters: + * handle: Handle to the listbox to be cleared. + */ +int dw_listbox_count(HWND handle) +{ + char tmpbuf[100]; + + GetClassName(handle, tmpbuf, 99); + + if(strnicmp(tmpbuf, COMBOBOXCLASSNAME, strlen(COMBOBOXCLASSNAME))==0) + return (int)SendMessage(handle, + CB_GETCOUNT,0L, 0L); + + return (int)SendMessage(handle, + LB_GETCOUNT,0L, 0L); +} + +/* + * Sets the topmost item in the viewport. + * Parameters: + * handle: Handle to the listbox to be cleared. + * top: Index to the top item. + */ +void dw_listbox_set_top(HWND handle, int top) +{ + SendMessage(handle, LB_SETTOPINDEX, (WPARAM)top, 0); +} + +#define MLE_MAX 200000 +/* + * Adds text to an MLE box and returns the current point. + * Parameters: + * handle: Handle to the MLE to be queried. + * buffer: Text buffer to be imported. + * startpoint: Point to start entering text. + */ +unsigned int dw_mle_import(HWND handle, char *buffer, int startpoint) +{ + char *tmpbuf = malloc(MLE_MAX+1); + int len; + + if(startpoint < 0) + startpoint = 0; + + GetWindowText(handle, tmpbuf, MLE_MAX); + tmpbuf[MLE_MAX] = 0; + + len = strlen(tmpbuf); + if(len) + memcpy(&tmpbuf[startpoint+strlen(buffer)], &tmpbuf[startpoint], (len-startpoint)); + memcpy(&tmpbuf[startpoint], buffer, strlen(buffer)); + + tmpbuf[len+strlen(buffer)] = 0; + + SetWindowText(handle, tmpbuf); + + free(tmpbuf); + return startpoint+strlen(buffer); +} + +/* + * Grabs text from an MLE box. + * Parameters: + * handle: Handle to the MLE to be queried. + * buffer: Text buffer to be exported. + * startpoint: Point to start grabbing text. + * length: Amount of text to be grabbed. + */ +void dw_mle_export(HWND handle, char *buffer, int startpoint, int length) +{ + char *tmpbuf = malloc(MLE_MAX+1); + + GetWindowText(handle, tmpbuf, MLE_MAX); + tmpbuf[MLE_MAX] = 0; + + memcpy(buffer, &tmpbuf[startpoint], length); + + free(tmpbuf); +} + +/* + * Obtains information about an MLE box. + * Parameters: + * handle: Handle to the MLE to be queried. + * bytes: A pointer to a variable to return the total bytes. + * lines: A pointer to a variable to return the number of lines. + */ +void dw_mle_query(HWND handle, unsigned long *bytes, unsigned long *lines) +{ + char *tmpbuf = malloc(MLE_MAX+1); + + GetWindowText(handle, tmpbuf, MLE_MAX); + tmpbuf[MLE_MAX] = 0; + + if(bytes) + *bytes = strlen(tmpbuf); + if(lines) + *lines = (unsigned long)SendMessage(handle, EM_GETLINECOUNT, 0, 0); + + free(tmpbuf); +} + +/* + * Deletes text from an MLE box. + * Parameters: + * handle: Handle to the MLE to be deleted from. + * startpoint: Point to start deleting text. + * length: Amount of text to be deleted. + */ +void dw_mle_delete(HWND handle, int startpoint, int length) +{ + char *tmpbuf = malloc(MLE_MAX+1); + int len; + + GetWindowText(handle, tmpbuf, MLE_MAX); + tmpbuf[MLE_MAX] = 0; + + len = strlen(tmpbuf); + + strcpy(&tmpbuf[startpoint], &tmpbuf[startpoint+length]); + + SetWindowText(handle, tmpbuf); + + free(tmpbuf); +} + +/* + * Clears all text from an MLE box. + * Parameters: + * handle: Handle to the MLE to be cleared. + */ +void dw_mle_clear(HWND handle) +{ + SetWindowText(handle, ""); +} + +/* + * Sets the visible line of an MLE box. + * Parameters: + * handle: Handle to the MLE. + * line: Line to be visible. + */ +void dw_mle_set_visible(HWND handle, int line) +{ + int point = (int)SendMessage(handle, EM_LINEINDEX, (WPARAM)line, 0); + dw_mle_set(handle, point); +} + +/* + * Sets the current cursor position of an MLE box. + * Parameters: + * handle: Handle to the MLE to be positioned. + * point: Point to position cursor. + */ +void dw_mle_set(HWND handle, int point) +{ + SendMessage(handle, EM_SETSEL, (WPARAM)point, (LPARAM)point); + SendMessage(handle, EM_SCROLLCARET, 0, 0); +} + +/* + * Finds text in an MLE box. + * Parameters: + * handle: Handle to the MLE to be cleared. + * text: Text to search for. + * point: Start point of search. + * flags: Search specific flags. + */ +int dw_mle_search(HWND handle, char *text, int point, unsigned long flags) +{ + char *tmpbuf = malloc(MLE_MAX+1); + int z, len, textlen, retval = 0; + + GetWindowText(handle, tmpbuf, MLE_MAX); + tmpbuf[MLE_MAX] = 0; + + len = strlen(tmpbuf); + textlen = strlen(text); + + if(flags & DW_MLE_CASESENSITIVE) + { + for(z=point;z<(len-textlen) && !retval;z++) + { + if(strncmp(&tmpbuf[z], text, textlen) == 0) + retval = z + textlen; + } + } + else + { + for(z=point;z<(len-textlen) && !retval;z++) + { + if(strnicmp(&tmpbuf[z], text, textlen) == 0) + retval = z + textlen; + } + } + + if(retval) + { + SendMessage(handle, EM_SETSEL, (WPARAM)retval - textlen, (LPARAM)retval); + SendMessage(handle, EM_SCROLLCARET, 0, 0); + } + + free(tmpbuf); + + return retval; +} + +/* + * Stops redrawing of an MLE box. + * Parameters: + * handle: Handle to the MLE to freeze. + */ +void dw_mle_freeze(HWND handle) +{ +} + +/* + * Resumes redrawing of an MLE box. + * Parameters: + * handle: Handle to the MLE to thaw. + */ +void dw_mle_thaw(HWND handle) +{ +} + +/* + * Returns the range of the slider. + * Parameters: + * handle: Handle to the slider to be queried. + */ +unsigned int dw_slider_query_range(HWND handle) +{ + return (unsigned int)SendMessage(handle, PBM_GETRANGE, (WPARAM)FALSE, 0); +} + +/* + * Sets the slider position. + * Parameters: + * handle: Handle to the slider to be set. + * position: Position of the slider withing the range. + */ +void dw_slider_set_pos(HWND handle, unsigned int position) +{ + SendMessage(handle, PBM_SETPOS, (WPARAM)position, 0); +} + +/* + * Sets the spinbutton value. + * Parameters: + * handle: Handle to the spinbutton to be set. + * position: Current value of the spinbutton. + */ +void dw_spinbutton_set_pos(HWND handle, long position) +{ + char tmpbuf[100]; + ColorInfo *cinfo = (ColorInfo *)GetWindowLong(handle, GWL_USERDATA); + + sprintf(tmpbuf, "%d", position); + + if(cinfo && cinfo->buddy) + SetWindowText(cinfo->buddy, tmpbuf); + + if(IS_WIN98PLUS) + SendMessage(handle, UDM_SETPOS32, 0, (LPARAM)position); + else + SendMessage(handle, UDM_SETPOS, 0, (LPARAM)MAKELONG((short)position, 0)); +} + +/* + * Sets the spinbutton limits. + * Parameters: + * handle: Handle to the spinbutton to be set. + * position: Current value of the spinbutton. + * position: Current value of the spinbutton. + */ +void dw_spinbutton_set_limits(HWND handle, long upper, long lower) +{ + if(IS_WIN98PLUS) + SendMessage(handle, UDM_SETRANGE32, (WPARAM)lower,(LPARAM)upper); + else + SendMessage(handle, UDM_SETRANGE32, (WPARAM)((short)lower), + (LPARAM)((short)upper)); +} + +/* + * Sets the entryfield character limit. + * Parameters: + * handle: Handle to the spinbutton to be set. + * limit: Number of characters the entryfield will take. + */ +void dw_entryfield_set_limit(HWND handle, ULONG limit) +{ + SendMessage(handle, EM_SETLIMITTEXT, (WPARAM)limit, 0); +} + +/* + * Returns the current value of the spinbutton. + * Parameters: + * handle: Handle to the spinbutton to be queried. + */ +long dw_spinbutton_query(HWND handle) +{ + if(IS_WIN98PLUS) + return (long)SendMessage(handle, UDM_GETPOS32, 0, 0); + else + return (long)SendMessage(handle, UDM_GETPOS, 0, 0); +} + +/* + * Returns the state of the checkbox. + * Parameters: + * handle: Handle to the checkbox to be queried. + */ +int dw_checkbox_query(HWND handle) +{ + if(SendMessage(handle, BM_GETCHECK, 0, 0) == BST_CHECKED) + return TRUE; + return FALSE; +} + +/* + * Sets the state of the checkbox. + * Parameters: + * handle: Handle to the checkbox to be queried. + * value: TRUE for checked, FALSE for unchecked. + */ +void dw_checkbox_set(HWND handle, int value) +{ + ColorInfo *cinfo = (ColorInfo *)GetWindowLong(handle, GWL_USERDATA); + + if(cinfo && !cinfo->user) + SendMessage(handle, BM_CLICK, 0, 0); + SendMessage(handle, BM_SETCHECK, (WPARAM)value, 0); +} + +/* + * Sets up the container columns. + * Parameters: + * handle: Handle to the container to be configured. + * flags: An array of unsigned longs with column flags. + * titles: An array of strings with column text titles. + * count: The number of columns (this should match the arrays). + * separator: The column number that contains the main separator. + * (only used on OS/2 but must be >= 0 on all) + */ +int dw_container_setup(HWND handle, unsigned long *flags, char **titles, int count, int separator) +{ + ContainerInfo *cinfo = (ContainerInfo *)GetWindowLong(handle, GWL_USERDATA); + int z, l = 0; + unsigned long *tempflags = malloc(sizeof(unsigned long) * (count + 2)); + LV_COLUMN lvc; + + if(separator == -1) + l = 1; + + memcpy(&tempflags[l], flags, sizeof(unsigned long) * count); + tempflags[count + l] = 0; + cinfo->flags = tempflags; + + + for(z=0;z<count;z++) + { + lvc.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM /*| LVCF_FORMAT*/; + lvc.pszText = titles[z]; + lvc.cchTextMax = strlen(titles[z]); + lvc.fmt = flags[z]; + lvc.cx = 75; + lvc.iSubItem = count; + SendMessage(handle, LVM_INSERTCOLUMN, (WPARAM)z + l, (LPARAM)&lvc); + } + ListView_SetExtendedListViewStyle(handle, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); + return TRUE; +} + +/* + * Sets up the filesystem columns, note: filesystem always has an icon/filename field. + * Parameters: + * handle: Handle to the container to be configured. + * flags: An array of unsigned longs with column flags. + * titles: An array of strings with column text titles. + * count: The number of columns (this should match the arrays). + */ +int dw_filesystem_setup(HWND handle, unsigned long *flags, char **titles, int count) +{ + LV_COLUMN lvc; + + lvc.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; + lvc.pszText = "Filename"; + lvc.cchTextMax = 8; + lvc.fmt = 0; + if(!count) + lvc.cx = 300; + else + lvc.cx = 150; + lvc.iSubItem = count; + SendMessage(handle, LVM_INSERTCOLUMN, (WPARAM)0, (LPARAM)&lvc); + dw_container_setup(handle, flags, titles, count, -1); + return TRUE; +} + +/* + * Obtains an icon from a module (or header in GTK). + * Parameters: + * module: Handle to module (DLL) in OS/2 and Windows. + * id: A unsigned long id int the resources on OS/2 and + * Windows, on GTK this is converted to a pointer + * to an embedded XPM. + */ +unsigned long dw_icon_load(unsigned long module, unsigned long id) +{ + return (unsigned long)LoadIcon(DWInstance, MAKEINTRESOURCE(id)); +} + +/* + * Frees a loaded resource in OS/2 and Windows. + * Parameters: + * handle: Handle to icon returned by dw_icon_load(). + */ +void dw_icon_free(unsigned long handle) +{ + DestroyIcon((HICON)handle); +} + +/* + * Allocates memory used to populate a container. + * Parameters: + * handle: Handle to the container window (widget). + * rowcount: The number of items to be populated. + */ +void *dw_container_alloc(HWND handle, int rowcount) +{ + return (void *)handle; +} + +/* Finds a icon in the table, otherwise it adds it to the table + * and returns the index in the table. + */ +int _lookup_icon(HWND handle, HICON hicon) +{ + int z; + static HWND lasthwnd = NULL; + + if(!lookup[0]) + { + hSmall = ImageList_Create(16, 16, FALSE, ICON_INDEX_LIMIT, 0); + hLarge = ImageList_Create(32, 32, FALSE, ICON_INDEX_LIMIT, 0); + } + for(z=0;z<ICON_INDEX_LIMIT;z++) + { + if(!lookup[z]) + { + lookup[z] = hicon; + ImageList_AddIcon(hSmall, hicon); + ImageList_AddIcon(hLarge, hicon); + ListView_SetImageList(handle, hSmall, LVSIL_SMALL); + ListView_SetImageList(handle, hLarge, LVSIL_NORMAL); + lasthwnd = handle; + return z; + } + + if(hicon == lookup[z]) + { + if(lasthwnd != handle) + { + ListView_SetImageList(handle, hSmall, LVSIL_SMALL); + ListView_SetImageList(handle, hLarge, LVSIL_NORMAL); + lasthwnd = handle; + } + return z; + } + } + return -1; +} + +/* + * Sets an item in specified row and column to the given data. + * Parameters: + * handle: Handle to the container window (widget). + * pointer: Pointer to the allocated memory in dw_container_alloc(). + * column: Zero based column of data being set. + * row: Zero based row of data being set. + * data: Pointer to the data to be added. + */ +void dw_filesystem_set_file(HWND handle, void *pointer, int row, char *filename, unsigned long icon) +{ + LV_ITEM lvi; + + lvi.iItem = row; + lvi.iSubItem = 0; + lvi.mask = LVIF_DI_SETITEM | LVIF_IMAGE | LVIF_TEXT; + lvi.pszText = filename; + lvi.cchTextMax = strlen(filename); + lvi.iImage = _lookup_icon(handle, (HICON)icon); + + ListView_InsertItem(handle, &lvi); +} + +/* + * Sets an item in specified row and column to the given data. + * Parameters: + * handle: Handle to the container window (widget). + * pointer: Pointer to the allocated memory in dw_container_alloc(). + * column: Zero based column of data being set. + * row: Zero based row of data being set. + * data: Pointer to the data to be added. + */ +void dw_filesystem_set_item(HWND handle, void *pointer, int column, int row, void *data) +{ + dw_container_set_item(handle, pointer, column + 1, row, data); +} + +/* + * Sets an item in specified row and column to the given data. + * Parameters: + * handle: Handle to the container window (widget). + * pointer: Pointer to the allocated memory in dw_container_alloc(). + * column: Zero based column of data being set. + * row: Zero based row of data being set. + * data: Pointer to the data to be added. + */ +void dw_container_set_item(HWND handle, void *pointer, int column, int row, void *data) +{ + ContainerInfo *cinfo = (ContainerInfo *)GetWindowLong(handle, GWL_USERDATA); + ULONG *flags; + LV_ITEM lvi; + char textbuffer[100], *destptr = textbuffer; + + if(!cinfo || !cinfo->flags || !data) + return; + + flags = cinfo->flags; + + lvi.mask = LVIF_DI_SETITEM | LVIF_TEXT; + lvi.iItem = row; + lvi.iSubItem = column; + + 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); + } + else if(flags[column] & DW_CFA_STRING) + { + char *tmp = *((char **)data); + + lvi.pszText = tmp; + lvi.cchTextMax = strlen(tmp); + destptr = tmp; + } + else if(flags[column] & DW_CFA_ULONG) + { + ULONG tmp = *((ULONG *)data); + + sprintf(textbuffer, "%lu", tmp); + + lvi.pszText = textbuffer; + lvi.cchTextMax = strlen(textbuffer); + } + else if(flags[column] & DW_CFA_DATE) + { + CDATE fdate = *((CDATE *)data); + + sprintf(textbuffer, "%s %d, %d", monthlist[fdate.month], fdate.day, fdate.year); + lvi.pszText = textbuffer; + lvi.cchTextMax = strlen(textbuffer); + } + else if(flags[column] & DW_CFA_TIME) + { + CTIME ftime = *((CTIME *)data); + + if(ftime.hours > 12) + sprintf(textbuffer, "%d:%s%dpm", ftime.hours - 12, (ftime.minutes < 10) ? "0" : "", ftime.minutes); + else + sprintf(textbuffer, "%d:%s%dam", ftime.hours ? ftime.hours : 12, (ftime.minutes < 10) ? "0" : "", ftime.minutes); + lvi.pszText = textbuffer; + lvi.cchTextMax = strlen(textbuffer); + } + + if(column == 0) + ListView_InsertItem(handle, &lvi); + else + ListView_SetItemText(handle, row, column, destptr); +} + +/* + * Sets the title of a row in the container. + * Parameters: + * pointer: Pointer to the allocated memory in dw_container_alloc(). + * row: Zero based row of data being set. + * title: String title of the item. + */ +void dw_container_set_row_title(void *pointer, int row, char *title) +{ + LV_ITEM lvi; + HWND container = (HWND)pointer; + + lvi.iItem = row; + lvi.iSubItem = 0; + lvi.mask = LVIF_PARAM; + lvi.lParam = (LPARAM)title; + + if(!ListView_SetItem(container, &lvi) && lvi.lParam) + { + free((void *)lvi.lParam); + lvi.lParam = 0; + } + +} + +/* + * Sets the title of a row in the container. + * Parameters: + * handle: Handle to the container window (widget). + * pointer: Pointer to the allocated memory in dw_container_alloc(). + * rowcount: The number of rows to be inserted. + */ +void dw_container_insert(HWND handle, void *pointer, int rowcount) +{ + /* This isn't a separate step in windows. */ +} + +/* + * Removes all rows from a container. + * Parameters: + * handle: Handle to the window (widget) to be cleared. + */ +void dw_container_clear(HWND handle) +{ + /* May need to delete manually so I can + * remove the memory allocated for the + * lParam field. + */ + ListView_DeleteAllItems(handle); +} + +/* + * Removes all rows from a container. + * Parameters: + * handle: Handle to the window (widget) to be cleared. + */ +void dw_container_set_view(HWND handle, unsigned long flags, int iconwidth, int iconheight) +{ +} + +/* + * Starts a new query of a container. + * Parameters: + * handle: Handle to the window (widget) to be queried. + * flags: If this parameter is DW_CRA_SELECTED it will only + * return items that are currently selected. Otherwise + * it will return all records in the container. + */ +char *dw_container_query_start(HWND handle, unsigned long flags) +{ + LV_ITEM lvi; + + if(flags) + _index = ListView_GetNextItem(handle, -1, LVNI_SELECTED); + else + _index = ListView_GetNextItem(handle, -1, LVNI_ALL); + + + lvi.iItem = _index; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(handle, &lvi); + + return (char *)lvi.lParam; +} + +/* + * Continues an existing query of a container. + * Parameters: + * handle: Handle to the window (widget) to be queried. + * flags: If this parameter is DW_CRA_SELECTED it will only + * return items that are currently selected. Otherwise + * it will return all records in the container. + */ +char *dw_container_query_next(HWND handle, unsigned long flags) +{ + LV_ITEM lvi; + + if(flags) + _index = ListView_GetNextItem(handle, _index, LVNI_SELECTED); + else + _index = ListView_GetNextItem(handle, _index, LVNI_ALL); + + if(_index == -1) + return NULL; + + lvi.iItem = _index; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(handle, &lvi); + + return (char *)lvi.lParam; +} + +/* + * Creates a rendering context widget (window) to be packed. + * Parameters: + * id: An id to be used with dw_window_from_id. + * Returns: + * A handle to the widget or NULL on failure. + */ +HWND dw_render_new(unsigned long id) +{ + HWND tmp = CreateWindow(ObjectClassName, + "", + WS_CHILD | WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + NULL, + NULL, + NULL); + SubclassWindow(tmp, _rendwndproc); + return tmp; +} + +/* Sets the current foreground drawing color. + * Parameters: + * red: red value. + * green: green value. + * blue: blue value. + */ +void dw_color_foreground_set(unsigned long value) +{ + DeleteObject(_hPen); + DeleteObject(_hBrush); + _foreground = RGB(DW_RED_VALUE(value), DW_GREEN_VALUE(value), DW_BLUE_VALUE(value)); + _hPen = CreatePen(PS_SOLID, 1, _foreground); + _hBrush = CreateSolidBrush(_foreground); +} + +/* Sets the current background drawing color. + * Parameters: + * red: red value. + * green: green value. + * blue: blue value. + */ +void dw_color_background_set(unsigned long value) +{ + + _background = RGB(DW_RED_VALUE(value), DW_GREEN_VALUE(value), DW_BLUE_VALUE(value)); +} + +/* Draw a point on a window (preferably a render window). + * Parameters: + * handle: Handle to the window. + * pixmap: Handle to the pixmap. (choose only one of these) + * x: X coordinate. + * y: Y coordinate. + */ +void dw_draw_point(HWND handle, HPIXMAP pixmap, int x, int y) +{ + HDC hdcPaint; + + if(handle) + hdcPaint = GetDC(handle); + else if(pixmap) + hdcPaint = pixmap->hdc; + else + return; + + SetPixel(hdcPaint, x, y, _foreground); + if(!pixmap) + ReleaseDC(handle, hdcPaint); +} + +/* Draw a line on a window (preferably a render window). + * Parameters: + * handle: Handle to the window. + * pixmap: Handle to the pixmap. (choose only one of these) + * x1: First X coordinate. + * y1: First Y coordinate. + * x2: Second X coordinate. + * y2: Second Y coordinate. + */ +void dw_draw_line(HWND handle, HPIXMAP pixmap, int x1, int y1, int x2, int y2) +{ + HDC hdcPaint; + HPEN oldPen; + + if(handle) + hdcPaint = GetDC(handle); + else if(pixmap) + hdcPaint = pixmap->hdc; + else + return; + + oldPen = SelectObject(hdcPaint, _hPen); + MoveToEx(hdcPaint, x1, y1, NULL); + LineTo(hdcPaint, x2, y2); + SelectObject(hdcPaint, oldPen); + /* For some reason Win98 (at least) fails + * to draw the last pixel. So I do it myself. + */ + SetPixel(hdcPaint, x2, y2, _foreground); + if(!pixmap) + ReleaseDC(handle, hdcPaint); +} + +/* Draw a rectangle on a window (preferably a render window). + * Parameters: + * handle: Handle to the window. + * pixmap: Handle to the pixmap. (choose only one of these) + * x: X coordinate. + * y: Y coordinate. + * width: Width of rectangle. + * height: Height of rectangle. + */ +void dw_draw_rect(HWND handle, HPIXMAP pixmap, int fill, int x, int y, int width, int height) +{ + HDC hdcPaint; + HPEN oldPen; + HBRUSH oldBrush; + + if(handle) + hdcPaint = GetDC(handle); + else if(pixmap) + hdcPaint = pixmap->hdc; + else + return; + + oldPen = SelectObject(hdcPaint, _hPen); + oldBrush = SelectObject(hdcPaint, _hBrush); + Rectangle(hdcPaint, x, y, x + width, y + height); + SelectObject(hdcPaint, oldPen); + SelectObject(hdcPaint, oldBrush); + if(!pixmap) + ReleaseDC(handle, hdcPaint); +} + +/* Draw text on a window (preferably a render window). + * Parameters: + * handle: Handle to the window. + * pixmap: Handle to the pixmap. (choose only one of these) + * x: X coordinate. + * y: Y coordinate. + * text: Text to be displayed. + */ +void dw_draw_text(HWND handle, HPIXMAP pixmap, int x, int y, char *text) +{ + HDC hdc; + int size = 9, z, mustdelete = 0; + HFONT hFont, oldFont; + + if(handle) + { + hdc = GetDC(handle); + hFont = (HFONT)SendMessage(handle, WM_GETFONT, 0, 0); + } + else if(pixmap) + { + hdc = pixmap->hdc; + hFont = (HFONT)SendMessage(pixmap->handle, WM_GETFONT, 0, 0); + } + else + return; + + if(!hFont) + { + ColorInfo *cinfo; + + if(handle) + cinfo = (ColorInfo *)GetWindowLong(handle, GWL_USERDATA); + else + cinfo = (ColorInfo *)GetWindowLong(pixmap->handle, GWL_USERDATA); + + if(cinfo) + { + hFont = _aquire_font(cinfo->fontname); + mustdelete = 1; + } + } + oldFont = SelectObject(hdc, hFont); + SetTextColor(hdc, _foreground); + SetBkMode(hdc, TRANSPARENT); + TextOut(hdc, x, y, text, strlen(text)); + SelectObject(hdc, oldFont); + if(mustdelete) + DeleteObject(hFont); + if(!pixmap) + ReleaseDC(handle, hdc); +} + +/* Call this after drawing to the screen to make sure + * anything you have drawn is visible. + */ +void dw_flush(void) +{ +} + +/* + * Creates a pixmap with given parameters. + * Parameters: + * handle: Window handle the pixmap is associated with. + * width: Width of the pixmap in pixels. + * height: Height of the pixmap in pixels. + * depth: Color depth of the pixmap. + * Returns: + * A handle to a pixmap or NULL on failure. + */ +HPIXMAP dw_pixmap_new(HWND handle, unsigned long width, unsigned long height, int depth) +{ + HPIXMAP pixmap; + BITMAP bm; + HDC hdc; + + if (!(pixmap = calloc(1,sizeof(struct _hpixmap)))) + return NULL; + + hdc = GetDC(handle); + + pixmap->width = width; pixmap->height = height; + + pixmap->handle = handle; + pixmap->hbm = CreateCompatibleBitmap(hdc, width, height); + pixmap->hdc = CreateCompatibleDC(hdc); + + SelectObject(pixmap->hdc, pixmap->hbm); + + ReleaseDC(handle, hdc); + + return pixmap; +} + +/* + * Creates a pixmap from internal resource graphic specified by id. + * Parameters: + * handle: Window handle the pixmap is associated with. + * id: Resource ID associated with requested pixmap. + * Returns: + * A handle to a pixmap or NULL on failure. + */ +HPIXMAP dw_pixmap_grab(HWND handle, ULONG id) +{ + HPIXMAP pixmap; + BITMAP bm; + HDC hdc; + + if (!(pixmap = calloc(1,sizeof(struct _hpixmap)))) + return NULL; + + hdc = GetDC(handle); + + + pixmap->hbm = LoadBitmap(DWInstance, MAKEINTRESOURCE(id)); + pixmap->hdc = CreateCompatibleDC(hdc); + + GetObject(pixmap->hbm, sizeof(BITMAP), (void *)&bm); + + pixmap->width = bm.bmWidth; pixmap->height = bm.bmHeight; + + SelectObject(pixmap->hdc, pixmap->hbm); + + ReleaseDC(handle, hdc); + + return pixmap; +} + +/* + * Destroys an allocated pixmap. + * Parameters: + * pixmap: Handle to a pixmap returned by + * dw_pixmap_new.. + */ +void dw_pixmap_destroy(HPIXMAP pixmap) +{ + if(pixmap) + { + DeleteDC(pixmap->hdc); + DeleteObject(pixmap->hbm); + free(pixmap); + } +} + +/* + * Copies from one item to another. + * Parameters: + * dest: Destination window handle. + * destp: Destination pixmap. (choose only one). + * xdest: X coordinate of destination. + * ydest: Y coordinate of destination. + * width: Width of area to copy. + * height: Height of area to copy. + * src: Source window handle. + * srcp: Source pixmap. (choose only one). + * xsrc: X coordinate of source. + * ysrc: Y coordinate of source. + */ +void dw_pixmap_bitblt(HWND dest, HPIXMAP destp, int xdest, int ydest, int width, int height, HWND src, HPIXMAP srcp, int xsrc, int ysrc) +{ + HDC hdcdest; + HDC hdcsrc; + + if(dest) + hdcdest = GetDC(dest); + else if(destp) + hdcdest = destp->hdc; + else + return; + + if(src) + hdcsrc = GetDC(src); + else if(srcp) + hdcsrc = srcp->hdc; + else + return; + + BitBlt(hdcdest, xdest, ydest, width, height, hdcsrc, xsrc, ysrc, SRCCOPY); + + if(!destp) + ReleaseDC(dest, hdcdest); + if(!srcp) + ReleaseDC(src, hdcsrc); +} + +/* + * Emits a beep. + * Parameters: + * freq: Frequency. + * dur: Duration. + */ +void dw_beep(int freq, int dur) +{ + Beep(freq, dur); +} + +/* + * Returns the handle to an unnamed mutex semaphore. + */ +HMTX dw_mutex_new(void) +{ + return (HMTX)CreateMutex(NULL, FALSE, NULL); +} + +/* + * Closes a semaphore created by dw_mutex_new(). + * Parameters: + * mutex: The handle to the mutex returned by dw_mutex_new(). + */ +void dw_mutex_close(HMTX mutex) +{ + CloseHandle((HANDLE)mutex); +} + +/* + * Tries to gain access to the semaphore, if it can't it blocks. + * Parameters: + * mutex: The handle to the mutex returned by dw_mutex_new(). + */ +void dw_mutex_lock(HMTX mutex) +{ + WaitForSingleObject((HANDLE)mutex, INFINITE); +} + +/* + * Reliquishes the access to the semaphore. + * Parameters: + * mutex: The handle to the mutex returned by dw_mutex_new(). + */ +void dw_mutex_unlock(HMTX mutex) +{ + ReleaseMutex((HANDLE)mutex); +} + +/* + * Returns the handle to an unnamed event semaphore. + */ +HEV dw_event_new(void) +{ + return CreateEvent(NULL, TRUE, FALSE, NULL); +} + +/* + * Resets a semaphore created by dw_event_new(). + * Parameters: + * eve: The handle to the event returned by dw_event_new(). + */ +int dw_event_reset(HEV eve) +{ + return ResetEvent(eve); +} + +/* + * Posts a semaphore created by dw_event_new(). Causing all threads + * waiting on this event in dw_event_wait to continue. + * Parameters: + * eve: The handle to the event returned by dw_event_new(). + */ +int dw_event_post(HEV eve) +{ + return SetEvent(eve); +} + +/* + * Waits on a semaphore created by dw_event_new(), until the + * event gets posted or until the timeout expires. + * Parameters: + * eve: The handle to the event returned by dw_event_new(). + */ +int dw_event_wait(HEV eve, unsigned long timeout) +{ + int rc; + + rc = WaitForSingleObject(eve, timeout); + if(rc == WAIT_OBJECT_0) + return 1; + if(rc == WAIT_ABANDONED) + return -1; + return 0; +} + +/* + * Closes a semaphore created by dw_event_new(). + * Parameters: + * eve: The handle to the event returned by dw_event_new(). + */ +int dw_event_close(HEV *eve) +{ + if(eve) + return CloseHandle(*eve); + return FALSE; +} + +/* + * Creates a new thread with a starting point of func. + * Parameters: + * func: Function which will be run in the new thread. + * data: Parameter(s) passed to the function. + * stack: Stack size of new thread (OS/2 and Windows only). + */ +DWTID dw_thread_new(void *func, void *data, int stack) +{ +#if defined(__CYGWIN__) + return 0; +#else + return (DWTID)_beginthread((void(*)(void *))func, stack, data); +#endif +} + +/* + * Ends execution of current thread immediately. + */ +void dw_thread_end(void) +{ +#if !defined(__CYGWIN__) + _endthread(); +#endif +} + +/* + * Returns the current thread's ID. + */ +DWTID dw_thread_id(void) +{ +#if defined(__CYGWIN__) + return 0; +#else + return (DWTID)GetCurrentThreadId(); +#endif +} + +/* + * Cleanly terminates a DW session, should be signal handler safe. + * Parameters: + * exitcode: Exit code reported to the operating system. + */ +void dw_exit(int exitcode) +{ + exit(exitcode); +} + +/* + * Pack a splitbar (sizer) into the specified box from the start. + * Parameters: + * box: Window handle of the box to be packed into. + */ +void dw_box_pack_splitbar_start(HWND box) +{ + Box *thisbox = (Box *)GetWindowLong(box, GWL_USERDATA); + + if(thisbox) + { + HWND tmp = CreateWindow(SplitbarClassName, + "", + WS_CHILD | WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + NULL, + NULL, + NULL); + if(thisbox->type == BOXVERT) + dw_box_pack_start(box, tmp, 1, SPLITBAR_WIDTH, TRUE, FALSE, 0); + else + dw_box_pack_start(box, tmp, SPLITBAR_WIDTH, 1, FALSE, TRUE, 0); + + } +} + +/* + * Pack a splitbar (sizer) into the specified box from the end. + * Parameters: + * box: Window handle of the box to be packed into. + */ +void dw_box_pack_splitbar_end(HWND box) +{ + Box *thisbox = (Box *)GetWindowLong(box, GWL_USERDATA); + + if(thisbox) + { + HWND tmp = CreateWindow(SplitbarClassName, + "", + WS_CHILD | WS_CLIPCHILDREN, + 0,0,2000,1000, + DW_HWND_OBJECT, + NULL, + NULL, + NULL); + if(thisbox->type == BOXVERT) + dw_box_pack_end(box, tmp, 1, SPLITBAR_WIDTH, TRUE, FALSE, 0); + else + dw_box_pack_end(box, tmp, SPLITBAR_WIDTH, 1, FALSE, TRUE, 0); + + } +} + +/* + * 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. + * 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. + * vsize: TRUE if the window (widget) should expand vertically to fill space given. + * pad: Number of pixels of padding around the item. + */ +void dw_box_pack_end(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad) +{ + Box *thisbox; + + thisbox = (Box *)GetWindowLong(box, GWL_USERDATA); + if(thisbox) + { + int z; + Item *tmpitem, *thisitem = thisbox->items; + char tmpbuf[100]; + + tmpitem = malloc(sizeof(Item)*(thisbox->count+1)); + + for(z=0;z<thisbox->count;z++) + { + tmpitem[z+1] = thisitem[z]; + } + + GetClassName(item, tmpbuf, 99); + + if(strnicmp(tmpbuf, FRAMECLASSNAME, 2)==0) + tmpitem[0].type = TYPEBOX; + else + tmpitem[0].type = TYPEITEM; + + tmpitem[0].hwnd = item; + tmpitem[0].origwidth = tmpitem[0].width = width; + tmpitem[0].origheight = tmpitem[0].height = height; + tmpitem[0].pad = pad; + if(hsize) + tmpitem[0].hsize = SIZEEXPAND; + else + tmpitem[0].hsize = SIZESTATIC; + + if(vsize) + tmpitem[0].vsize = SIZEEXPAND; + else + tmpitem[0].vsize = SIZESTATIC; + + thisbox->items = tmpitem; + + if(thisbox->count) + free(thisitem); + + thisbox->count++; + + SetParent(item, box); + ShowWindow(item, SW_SHOW); + if(strncmp(tmpbuf, UPDOWN_CLASS, strlen(UPDOWN_CLASS))==0) + { + ColorInfo *cinfo = (ColorInfo *)GetWindowLong(item, GWL_USERDATA); + + if(cinfo) + { + SetParent(cinfo->buddy, box); + ShowWindow(cinfo->buddy, SW_SHOW); + SendMessage(item, UDM_SETBUDDY, (WPARAM)cinfo->buddy, 0); + } + } + } +} + +/* + * Returns some information about the current operating environment. + * Parameters: + * env: Pointer to a DWEnv struct. + */ +void dw_environment_query(DWEnv *env) +{ + if(!env) + return; + + /* Get the Windows version. */ + + env->MajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); + env->MinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion))); + + /* Get the build number for Windows NT/Windows 2000. */ + + env->MinorBuild = 0; + + if (dwVersion < 0x80000000) + { + if(env->MajorVersion == 5) + strcpy(env->osName, "Windows 2000"); + else + strcpy(env->osName, "Windows NT"); + + env->MajorBuild = (DWORD)(HIWORD(dwVersion)); + } + else + { + strcpy(env->osName, "Windows 95/98/ME"); + env->MajorBuild = 0; + } +} + +/* + * Opens a file dialog and queries user selection. + * Parameters: + * title: Title bar text for dialog. + * defpath: The default path of the open dialog. + * ext: Default file extention. + * flags: DW_FILE_OPEN or DW_FILE_SAVE. + * Returns: + * NULL on error. A malloced buffer containing + * the file path on success. + * + */ +char *dw_file_browse(char *title, char *defpath, char *ext, int flags) +{ + OPENFILENAME of; + char filenamebuf[1001] = ""; + int rc; + + if(ext) + { + strcpy(filenamebuf, "*."); + strcat(filenamebuf, ext); + } + + memset(&of, 0, sizeof(OPENFILENAME)); + + of.lStructSize = sizeof(OPENFILENAME); + of.hwndOwner = HWND_DESKTOP; + of.hInstance = DWInstance; + of.lpstrInitialDir = defpath; + of.lpstrTitle = title; + of.lpstrFile = filenamebuf; + of.nMaxFile = 1000; + of.lpstrDefExt = ext; + of.Flags = 0; + + if(flags & DW_FILE_SAVE) + rc = GetSaveFileName(&of); + else + rc = GetOpenFileName(&of); + + if(rc) + return strdup(of.lpstrFile); + + return NULL; +} + +/* + * Execute and external program in a seperate session. + * Parameters: + * program: Program name with optional path. + * type: Either DW_EXEC_CON or DW_EXEC_GUI. + * params: An array of pointers to string arguements. + * Returns: + * -1 on error. + */ +int dw_exec(char *program, int type, char **params) +{ + char **newparams; + int retcode, count = 0, z; + + while(params[count]) + { + count++; + } + + newparams = (char **)malloc(sizeof(char *) * (count+1)); + + for(z=0;z<count;z++) + { + newparams[z] = malloc(strlen(params[z])+3); + strcpy(newparams[z], "\""); + strcat(newparams[z], params[z]); + strcat(newparams[z], "\""); + } + newparams[count] = NULL; + + retcode = spawnvp(P_NOWAIT, program, newparams); + + for(z=0;z<count;z++) + { + free(newparams[z]); + } + free(newparams); + + return retcode; +} + +/* + * Loads a web browser pointed at the given URL. + * Parameters: + * url: Uniform resource locator. + */ +int dw_browse(char *url) +{ + char *browseurl = url; + int retcode; + + if(strlen(url) > 7 && strncmp(url, "file://", 7) == 0) + { + int len, z; + + browseurl = &url[7]; + len = strlen(browseurl); + + for(z=0;z<len;z++) + { + if(browseurl[z] == '|') + browseurl[z] = ':'; + if(browseurl[z] == '/') + browseurl[z] = '\\'; + } + } + + retcode = (int)ShellExecute(NULL, "open", browseurl, NULL, NULL, SW_SHOWNORMAL); + if(retcode<33 && retcode != 2) + return -1; + return 1; +} + +/* + * Returns a pointer to a static buffer which containes the + * current user directory. Or the root directory (C:\ on + * OS/2 and Windows). + */ +char *dw_user_dir(void) +{ + static char _user_dir[1024] = ""; + + if(!_user_dir[0]) + { + /* Figure out how to do this the "Windows way" */ + char *home = getenv("HOME"); + + if(home) + strcpy(_user_dir, home); + else + strcpy(_user_dir, "C:\\"); + } + return _user_dir; +} + +/* + * Call a function from the window (widget)'s context. + * Parameters: + * handle: Window handle of the widget. + * function: Function pointer to be called. + * data: Pointer to the data to be passed to the function. + */ +void dw_window_function(HWND handle, void *function, void *data) +{ + SendMessage(handle, WM_USER, (WPARAM)function, (LPARAM)data); +} + +#ifndef NO_SIGNALS +/* + * Add a callback to a window event. + * Parameters: + * window: Window handle of signal to be called back. + * signame: A string pointer identifying which signal to be hooked. + * sigfunc: The pointer to the function to be used as the callback. + * data: User data to be passed to the handler function. + */ +void dw_signal_connect(HWND window, char *signame, void *sigfunc, void *data) +{ + ULONG message = 0L; + + if(window && signame && sigfunc) + { + if((message = _findsigmessage(signame)) != 0) + _new_signal(message, window, sigfunc, data); + } +} + +/* + * Removes callbacks for a given window with given name. + * Parameters: + * window: Window handle of callback to be removed. + */ +void dw_signal_disconnect_by_name(HWND window, char *signame) +{ + SignalHandler *prev = NULL, *tmp = Root; + ULONG message; + + if(!window || !signame || (message = _findsigmessage(signame)) == 0) + return; + + while(tmp) + { + if(tmp->window == window && tmp->message == message) + { + if(prev) + { + prev->next = tmp->next; + free(tmp); + tmp = prev->next; + } + else + { + Root = tmp->next; + free(tmp); + tmp = Root; + } + } + else + { + prev = tmp; + tmp = tmp->next; + } + } +} + +/* + * Removes all callbacks for a given window. + * Parameters: + * window: Window handle of callback to be removed. + */ +void dw_signal_disconnect_by_window(HWND window) +{ + SignalHandler *prev = NULL, *tmp = Root; + + while(tmp) + { + if(tmp->window == window) + { + if(prev) + { + prev->next = tmp->next; + free(tmp); + tmp = prev->next; + } + else + { + Root = tmp->next; + free(tmp); + tmp = Root; + } + } + else + { + prev = tmp; + tmp = tmp->next; + } + } +} + +/* + * Removes all callbacks for a given window with specified data. + * Parameters: + * window: Window handle of callback to be removed. + * data: Pointer to the data to be compared against. + */ +void dw_signal_disconnect_by_data(HWND window, void *data) +{ + SignalHandler *prev = NULL, *tmp = Root; + + while(tmp) + { + if(tmp->window == window && tmp->data == data) + { + if(prev) + { + prev->next = tmp->next; + free(tmp); + tmp = prev->next; + } + else + { + Root = tmp->next; + free(tmp); + tmp = Root; + } + } + else + { + prev = tmp; + tmp = tmp->next; + } + } +} +#endif + +#ifdef TEST +HWND mainwindow, + listbox, + okbutton, + cancelbutton, + lbbox, + stext, + buttonbox, + testwindow, + testbox, + testok, + testcancel, + testbox2, + testok2, + testcancel2, + notebook; +int count = 2; + +#ifdef USE_FILTER +/* Do any handling you need in the filter function */ +LONG testfilter(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + switch(msg) + { + case WM_COMMAND: + switch (COMMANDMSG(&msg)->cmd) + { + case 1001L: + case 1002L: + dw_window_destroy(mainwindow);; + count--; + break; + case 1003L: + case 1004L: + dw_window_destroy(testwindow);; + count--; + break; + } + if(!count) + exit(0); + break; + } + /* Return -1 to allow the default handlers to return. */ + return TRUE; +} +#else +int test_callback(HWND window, void *data) +{ + dw_window_destroy((HWND)data); + /* Return -1 to allow the default handlers to return. */ + count--; + if(!count) + exit(0); + return -1; +} +#endif + +/* + * Let's demonstrate the functionality of this library. :) + */ +int WINAPI WinMain( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow +) +{ + ULONG flStyle = DW_FCF_SYSMENU | DW_FCF_TITLEBAR | + DW_FCF_SHELLPOSITION | DW_FCF_TASKLIST | DW_FCF_DLGBORDER; + int pageid; + + dw_init(TRUE); + + /* Try a little server dialog. :) */ + mainwindow = dw_window_new(HWND_DESKTOP, "Server", flStyle | DW_FCF_SIZEBORDER | DW_FCF_MINMAX); + + lbbox = dw_box_new(BOXVERT, 10); + + dw_box_pack_start(mainwindow, lbbox, 0, 0, TRUE, TRUE, 0); + + stext = dw_text_new("Choose a server:", 0); + + dw_window_set_style(stext, DW_DT_VCENTER, DW_DT_VCENTER); + + dw_box_pack_start(lbbox, stext, 130, 15, FALSE, FALSE, 10); + + listbox = dw_listbox_new(100L, FALSE); + + dw_box_pack_start(lbbox, listbox, 130, 200, TRUE, TRUE, 10); + + buttonbox = dw_box_new(BOXHORZ, 0); + + dw_box_pack_start(lbbox, buttonbox, 0, 0, TRUE, TRUE, 0); + + okbutton = dw_button_new("Ok", 1001L); + + dw_box_pack_start(buttonbox, okbutton, 50, 30, TRUE, TRUE, 5); + + cancelbutton = dw_button_new("Cancel", 1002L); + + dw_box_pack_start(buttonbox, cancelbutton, 50, 30, TRUE, TRUE, 5); + + /* Set some nice fonts and colors */ + dw_window_set_color(lbbox, DW_CLR_PALEGRAY, DW_CLR_PALEGRAY); + dw_window_set_color(buttonbox, DW_CLR_PALEGRAY, DW_CLR_PALEGRAY); + dw_window_set_font(stext, "9.WarpSans"); + dw_window_set_color(stext, DW_CLR_BLACK, DW_CLR_PALEGRAY); + dw_window_set_font(listbox, "9.WarpSans"); + dw_window_set_font(okbutton, "9.WarpSans"); + dw_window_set_font(cancelbutton, "9.WarpSans"); + + dw_window_show(mainwindow); + + dw_window_set_usize(mainwindow, 170, 340); + + /* Another small example */ + flStyle |= DW_FCF_MINMAX | DW_FCF_SIZEBORDER; + + testwindow = dw_window_new(HWND_DESKTOP, "Wow a test dialog! :) yay!", flStyle); + + testbox = dw_box_new(BOXVERT, 0); + + dw_box_pack_start(testwindow, testbox, 0, 0, TRUE, TRUE, 0); + + notebook = dw_notebook_new(1010L, TRUE); + + dw_box_pack_start(testbox, notebook, 100, 100, TRUE, TRUE, 0); + + testbox = dw_box_new(BOXVERT, 10); + + pageid = dw_notebook_page_new(notebook, 0L, FALSE); + + dw_notebook_page_set_text(notebook, pageid, "Test page"); + dw_notebook_page_set_status_text(notebook, pageid, "Test page"); + + dw_notebook_pack(notebook, pageid, testbox); + + testok = dw_button_new("Ok", 1003L); + + dw_box_pack_start(testbox, testok, 60, 40, TRUE, TRUE, 10); + + testcancel = dw_button_new("Cancel", 1004L); + + dw_box_pack_start(testbox, testcancel, 60, 40, TRUE, TRUE, 10); + + testbox2 = dw_box_new(BOXHORZ, 0); + + dw_box_pack_start(testbox, testbox2, 0, 0, TRUE, TRUE, 0); + + testok2 = dw_button_new("Ok", 1003L); + + dw_box_pack_start(testbox2, testok2, 60, 40, TRUE, TRUE, 10); + + dw_box_pack_splitbar_start(testbox2); + + testcancel2 = dw_button_new("Cancel", 1004L); + + dw_box_pack_start(testbox2, testcancel2, 60, 40, TRUE, TRUE, 10); + + /* Set some nice fonts and colors */ + dw_window_set_color(testbox, DW_CLR_PALEGRAY, DW_CLR_PALEGRAY); + dw_window_set_color(testbox2, DW_CLR_PALEGRAY, DW_CLR_PALEGRAY); + dw_window_set_font(testok, "9.WarpSans"); + dw_window_set_font(testcancel, "9.WarpSans"); + dw_window_set_font(testok2, "9.WarpSans"); + dw_window_set_font(testcancel2, "9.WarpSans"); + + dw_window_show(testwindow); + +#ifdef USE_FILTER + + dw_main(0L, (void *)testfilter); +#else + /* Setup the function callbacks */ + dw_signal_connect(okbutton, "clicked", DW_SIGNAL_FUNC(test_callback), (void *)mainwindow); + dw_signal_connect(cancelbutton, "clicked", DW_SIGNAL_FUNC(test_callback), (void *)mainwindow); + dw_signal_connect(testok, "clicked", DW_SIGNAL_FUNC(test_callback), (void *)testwindow); + dw_signal_connect(testcancel, "clicked", DW_SIGNAL_FUNC(test_callback), (void *)testwindow); + dw_signal_connect(testok2, "clicked", DW_SIGNAL_FUNC(test_callback), (void *)testwindow); + dw_signal_connect(testcancel2, "clicked", DW_SIGNAL_FUNC(test_callback), (void *)testwindow); + dw_signal_connect(mainwindow, "delete_event", DW_SIGNAL_FUNC(test_callback), (void *)mainwindow); + dw_signal_connect(testwindow, "delete_event", DW_SIGNAL_FUNC(test_callback), (void *)testwindow); + + dw_main(0L, NULL); +#endif + + return 0; +} +#endif \ No newline at end of file