Mercurial > dwindows
diff os2/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/os2/dw.c Tue Jul 03 07:50:39 2001 +0000 @@ -0,0 +1,5743 @@ +/* + * Dynamic Windows: + * A GTK like implementation of the PM GUI + * + * (C) 2000,2001 Brian Smith <dbsoft@technologist.com> + * (C) 2000 Achim Hasenmueller <achimha@innotek.de> + * (C) 2000 Peter Nielsen <peter@pmview.com> + * (C) 1998 Sergey I. Yevtushenko (some code borrowed from cell toolkit) + * + */ +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_WIN +#define INCL_GPI + +#include <os2.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <stdarg.h> +#include <stddef.h> +#include <ctype.h> +#include <process.h> +#include "dw.h" + +#define QWP_USER 0 + +char ClassName[] = "dynamicwindows"; +char SplitbarClassName[] = "dwsplitbar"; +char DefaultFont[] = "9.WarpSans"; + +/* this is the callback handle for the window procedure + * make sure you always match the calling convention! + */ +int (* EXPENTRY filterfunc)(HWND, ULONG, MPARAM, MPARAM) = 0L; + +HAB dwhab = 0; +HMQ dwhmq = 0; +DWTID _dwtid = 0; +LONG _foreground = 0xAAAAAA, _background = 0; + +HWND hwndBubble = NULLHANDLE, hwndBubbleLast = NULLHANDLE; +PRECORDCORE pCore = NULL; + +#ifndef min +#define min(a, b) (((a < b) ? a : b)) +#endif + +#ifdef DWDEBUG +FILE *f; + +void reopen(void) +{ + fclose(f); + f = fopen("dw.log", "at"); +} +#endif + +static LONG lColor[SPLITBAR_WIDTH] = +{ + DW_CLR_BLACK, + DW_CLR_PALEGRAY, + DW_CLR_WHITE +}; + +#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; + +typedef struct +{ + ULONG message; + char name[30]; + +} SignalList; + +/* List of signals and their equivilent OS/2 message */ +#define SIGNALMAX 11 + +SignalList SignalTranslate[SIGNALMAX] = { + { WM_SIZE, "configure_event" }, + { WM_CHAR, "key_press_event" }, + { WM_BUTTON1DOWN, "button_press_event" }, + { WM_BUTTON1UP, "button_release_event"}, + { WM_MOUSEMOVE, "motion_notify_event" }, + { WM_CLOSE, "delete_event" }, + { WM_PAINT, "expose_event" }, + { WM_COMMAND, "clicked" }, + { CN_ENTER, "container-select" }, + { CN_CONTEXTMENU, "container-context" }, + { LN_SELECT, "item-select" } +}; + +/* 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. + */ +void _free_window_memory(HWND handle) +{ + HENUM henum; + HWND child; + +#ifndef NO_SIGNALS + dw_signal_disconnect_by_window(handle); +#endif + + henum = WinBeginEnumWindows(handle); + while((child = WinGetNextWindow(henum)) != NULLHANDLE) + { + void *ptr = (void *)WinQueryWindowPtr(handle, QWP_USER); + + if(ptr) + { + WinSetWindowPtr(handle, QWP_USER, 0); + free(ptr); + } + + _free_window_memory(child); + } + WinEndEnumWindows(henum); + return; +} + +/* 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; + + WinQueryClassName(handle, 99, tmpbuf); + + /* These are the window classes which can + * obtain input focus. + */ + if(strncmp(tmpbuf, "#2", 2)==0 || /* Entryfield */ + strncmp(tmpbuf, "#3", 2)==0 || /* Button */ + strncmp(tmpbuf, "#6", 2)==0 || /* Combobox */ + strncmp(tmpbuf, "#7", 2)==0 || /* List box */ + strncmp(tmpbuf, "#10", 3)==0 || /* MLE */ + strncmp(tmpbuf, "#32", 3)==0 || /* Spinbutton */ + strncmp(tmpbuf, "#37", 3)== 0) /* Container */ + return 1; + return 0; +} + +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) + WinSetFocus(HWND_DESKTOP, 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; + } + + /* Vertical boxes are inverted on OS/2 */ + if(box->type == BOXVERT) + { + for(z=0;z<box->count;z++) + { + if(box->items[z].type == TYPEBOX) + { + Box *thisbox = WinQueryWindowPtr(box->items[z].hwnd, QWP_USER); + + if(thisbox && _focus_check_box(thisbox, handle, start == 3 ? 3 : 0)) + return 1; + } + else + { + if(box->items[z].hwnd == handle) + { + if(lasthwnd == handle && firsthwnd) + WinSetFocus(HWND_DESKTOP, firsthwnd); + else if(lasthwnd == handle && !firsthwnd) + finish_searching = 1; + else + WinSetFocus(HWND_DESKTOP, 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) + { + WinSetFocus(HWND_DESKTOP, box->items[z].hwnd); + return 1; + } + + if(!firsthwnd) + firsthwnd = box->items[z].hwnd; + + lasthwnd = box->items[z].hwnd; + } + else + { + char tmpbuf[100] = ""; + + WinQueryClassName(box->items[z].hwnd, 99, tmpbuf); + if(strncmp(tmpbuf, "#40", 3)==0) /* Notebook */ + { + Box *notebox; + HWND page = (HWND)WinSendMsg(box->items[z].hwnd, BKM_QUERYPAGEWINDOWHWND, + (MPARAM)dw_notebook_page_query(box->items[z].hwnd), 0); + + if(page) + { + notebox = (Box *)WinQueryWindowPtr(page, QWP_USER); + + if(notebox && _focus_check_box(notebox, handle, start == 3 ? 3 : 0)) + return 1; + } + } + } + } + } + } + else + { + for(z=box->count-1;z>-1;z--) + { + if(box->items[z].type == TYPEBOX) + { + Box *thisbox = WinQueryWindowPtr(box->items[z].hwnd, QWP_USER); + + if(thisbox && _focus_check_box(thisbox, handle, start == 3 ? 3 : 0)) + return 1; + } + else + { + if(box->items[z].hwnd == handle) + { + if(lasthwnd == handle && firsthwnd) + WinSetFocus(HWND_DESKTOP, firsthwnd); + else if(lasthwnd == handle && !firsthwnd) + finish_searching = 1; + else + WinSetFocus(HWND_DESKTOP, 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) + { + WinSetFocus(HWND_DESKTOP, box->items[z].hwnd); + return 1; + } + + if(!firsthwnd) + firsthwnd = box->items[z].hwnd; + + lasthwnd = box->items[z].hwnd; + } + else + { + char tmpbuf[100] = ""; + + WinQueryClassName(box->items[z].hwnd, 99, tmpbuf); + if(strncmp(tmpbuf, "#40", 3)==0) /* Notebook */ + { + Box *notebox; + HWND page = (HWND)WinSendMsg(box->items[z].hwnd, BKM_QUERYPAGEWINDOWHWND, + (MPARAM)dw_notebook_page_query(box->items[z].hwnd), 0); + + if(page) + { + notebox = (Box *)WinQueryWindowPtr(page, QWP_USER); + + 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; + HWND box; + + box = WinWindowFromID(handle, FID_CLIENT); + if(box) + thisbox = WinQueryWindowPtr(box, QWP_USER); + + 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 = WinQueryWindow(handle, QW_PARENT); + + /* Find the toplevel window */ + while((box = WinQueryWindow(lastbox, QW_PARENT)) > 0x80000001) + { + lastbox = box; + } + + thisbox = WinQueryWindowPtr(lastbox, QWP_USER); + if(!thisbox) + { + box = WinWindowFromID(lastbox, FID_CLIENT); + if(box) + thisbox = WinQueryWindowPtr(box, QWP_USER); + } + 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) +{ + SWP swp; + + WinQueryWindowPos(hwndFrame, &swp); + WinSetWindowPos(hwndFrame, HWND_TOP, 0, 0, swp.cx, swp.cy-1, SWP_SIZE); + WinSetWindowPos(hwndFrame, HWND_TOP, 0, 0, swp.cx, swp.cy, SWP_SIZE); +} + +/* This function will recursively search a box and add up the total height of it */ +void _count_size(HWND box, int type, int *xsize, int *xorigsize) +{ + int size = 0, origsize = 0, z; + Box *tmp = WinQueryWindowPtr(box, QWP_USER); + + if(!tmp) + { + *xsize = *xorigsize = 0; + return; + } + + if(type == tmp->type) + { + /* If the box is going in the direction we want, then we + * return the entire sum of the items. + */ + for(z=0;z<tmp->count;z++) + { + if(tmp->items[z].type == TYPEBOX) + { + int s, os; + + _count_size(tmp->items[z].hwnd, type, &s, &os); + size += s; + origsize += os; + } + else + { + size += (type == BOXHORZ ? tmp->items[z].width : tmp->items[z].height); + origsize += (type == BOXHORZ ? tmp->items[z].origwidth : tmp->items[z].origheight); + } + } + } + else + { + /* If the box is not going in the direction we want, then we only + * want to return the maximum value. + */ + int tmpsize = 0, tmporigsize = 0; + + for(z=0;z<tmp->count;z++) + { + if(tmp->items[z].type == TYPEBOX) + _count_size(tmp->items[z].hwnd, type, &tmpsize, &tmporigsize); + else + { + tmpsize = (type == BOXHORZ ? tmp->items[z].width : tmp->items[z].height); + tmporigsize = (type == BOXHORZ ? tmp->items[z].origwidth : tmp->items[z].origheight); + } + + if(tmpsize > size) + size = tmpsize; + } + } + + *xsize = size; + *xorigsize = origsize; +} + + +/* 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) +{ + TRACKINFO track; + APIRET rc; + + 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; + + WinMapWindowPoints(hwndBase, + HWND_DESKTOP, + (PPOINTL)&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; + + 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 vectorx = 0, vectory = 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 = WinQueryWindowPtr(thisbox->items[z].hwnd, QWP_USER); + + initialx = x - (*usedx); + initialy = y - (*usedy); + + if(tmp) + { + int newx, newy; + int nux = *usedx, nuy = *usedy; + int upx = *usedpadx + (tmp->pad*2), upy = *usedpady + (tmp->pad*2); + + /* On the second pass we know how big the box needs to be and how + * much space we have, so we can calculate a ratio for the new box. + */ + if(pass == 2) + { + 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 = WinQueryWindowPtr(thisbox->items[z].hwnd, QWP_USER); + + 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; + + /* 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; + + WinQueryClassName(handle, 99, tmpbuf); + + if(strncmp(tmpbuf, "#2", 2)==0) + { + /* Make the combobox big enough to drop down. :) */ + WinSetWindowPos(handle, HWND_TOP, currentx + pad, (currenty + pad) - 100, + width + vectorx, (height + vectory) + 100, SWP_MOVE | SWP_SIZE | SWP_ZORDER); + } + else if(strncmp(tmpbuf, "#6", 2)==0) + { + /* Entryfields on OS/2 have a thick border that isn't on Windows and GTK */ + WinSetWindowPos(handle, HWND_TOP, (currentx + pad) + 3, (currenty + pad) + 3, + (width + vectorx) - 6, (height + vectory) - 6, SWP_MOVE | SWP_SIZE | SWP_ZORDER); + } + else + { + WinSetWindowPos(handle, HWND_TOP, currentx + pad, currenty + pad, + width + vectorx, height + vectory, SWP_MOVE | SWP_SIZE | SWP_ZORDER); + if(thisbox->items[z].type == TYPEBOX) + { + Box *boxinfo = WinQueryWindowPtr(handle, QWP_USER); + + if(boxinfo && boxinfo->grouphwnd) + WinSetWindowPos(boxinfo->grouphwnd, HWND_TOP, 0, 0, + width + vectorx, height + vectory, SWP_MOVE | SWP_SIZE | SWP_ZORDER); + + } + + } + +#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, usedpadx = 0, usedpady = 0, depth = 0; + + _resize_box(thisbox, &depth, x, y, &usedx, &usedy, 1, &usedpadx, &usedpady); + + if(usedx-usedpadx == 0 || usedy-usedpady == 0) + return; + + thisbox->xratio = ((float)(x-usedpadx))/((float)(usedx-usedpadx)); + thisbox->yratio = ((float)(y-usedpady))/((float)(usedy-usedpady)); + +#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 + + usedx = usedy = usedpadx = usedpady = 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 + } + } +} + +/* This procedure handles WM_QUERYTRACKINFO requests from the frame */ +MRESULT EXPENTRY _sizeproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + PFNWP *blah = WinQueryWindowPtr(hWnd, QWP_USER); + + switch(msg) + { + case WM_QUERYTRACKINFO: + { + if(blah && *blah) + { + PTRACKINFO ptInfo; + int res; + PFNWP myfunc = *blah; + res = (int)myfunc(hWnd, msg, mp1, mp2); + + ptInfo = (PTRACKINFO)(mp2); + + ptInfo->ptlMinTrackSize.y = 8; + ptInfo->ptlMinTrackSize.x = 8; + + return (MRESULT)res; + } + } + } + if(blah && *blah) + { + PFNWP myfunc = *blah; + return myfunc(hWnd, msg, mp1, mp2); + } + + return WinDefWindowProc(hWnd, msg, mp1, mp2); +} +/* Originally just intended for entryfields, it now serves as a generic + * procedure for handling TAB presses to change input focus on controls. + */ +MRESULT EXPENTRY _entryproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + PFNWP *blah = WinQueryWindowPtr(hWnd, QWP_USER); + + switch(msg) + { + case WM_CHAR: + if(SHORT1FROMMP(mp2) == '\t') + { + _shift_focus(hWnd); + return FALSE; + } + break; + } + if(blah && *blah) + { + PFNWP myfunc = *blah; + return myfunc(hWnd, msg, mp1, mp2); + } + + return WinDefWindowProc(hWnd, msg, mp1, mp2); +} + +/* Handle correct painting of a combobox with the WS_CLIPCHILDREN + * flag enabled, and also handle TABs to switch input focus. + */ +MRESULT EXPENTRY _comboproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + PFNWP *blah = WinQueryWindowPtr(hWnd, QWP_USER); + + switch(msg) + { + case WM_CHAR: + if(SHORT1FROMMP(mp2) == '\t') + { + _shift_focus(hWnd); + return FALSE; + } + break; + case WM_PAINT: + { + HWND parent = WinQueryWindow(hWnd, QW_PARENT); + ULONG bcol, av[32]; + HPS hpsPaint; + POINTL ptl; /* Add 6 because it has a thick border like the entryfield */ + unsigned long width, height, thumbheight = WinQuerySysValue(HWND_DESKTOP, SV_CYVSCROLLARROW) + 6; + + WinQueryPresParam(parent, PP_BACKGROUNDCOLORINDEX, 0, &bcol, sizeof(ULONG), &av, QPF_ID1COLORINDEX | QPF_NOINHERIT); + dw_window_get_pos_size(hWnd, 0, 0, &width, &height); + + hpsPaint = WinGetPS(hWnd); + GpiSetColor(hpsPaint, CLR_PALEGRAY); + + ptl.x = 0; + ptl.y = 99; + GpiMove(hpsPaint, &ptl); + + ptl.x = width; + ptl.y = height - thumbheight; + GpiBox(hpsPaint, DRO_FILL, &ptl, 0, 0); + + WinReleasePS(hpsPaint); + } + break; + } + if(blah && *blah) + { + PFNWP myfunc = *blah; + return myfunc(hWnd, msg, mp1, mp2); + } + + return WinDefWindowProc(hWnd, msg, mp1, mp2); +} + +void _GetPPFont(HWND hwnd, char *buff) +{ + ULONG AttrFound; + BYTE AttrValue[128]; + ULONG cbRetLen; + + cbRetLen = WinQueryPresParam(hwnd, + PP_FONTNAMESIZE, + 0, + &AttrFound, + sizeof(AttrValue), + &AttrValue, + QPF_NOINHERIT); + + if(PP_FONTNAMESIZE == AttrFound && cbRetLen) + { + memcpy(buff, AttrValue, cbRetLen); + } +} + +/* Returns height of specified window. */ +int _get_height(HWND handle) +{ + unsigned long height; + dw_window_get_pos_size(handle, NULL, NULL, NULL, &height); + return (int)height; +} + +/* Find the height of the frame a desktop style window is sitting on */ +int _get_frame_height(HWND handle) +{ + while(handle) + { + HWND client; + if((client = WinWindowFromID(handle, FID_CLIENT)) != NULLHANDLE) + { + return _get_height(WinQueryWindow(handle, QW_PARENT)); + } + handle = WinQueryWindow(handle, QW_PARENT); + } + return dw_screen_height(); +} + +#ifndef NO_SIGNALS +MRESULT EXPENTRY _run_event(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + int result = -1; + SignalHandler *tmp = Root; + ULONG origmsg = msg; + + if(msg == WM_BUTTON2DOWN || msg == WM_BUTTON3DOWN) + msg = WM_BUTTON1DOWN; + if(msg == WM_BUTTON2UP || msg == WM_BUTTON3UP) + msg = WM_BUTTON1UP; + + /* Find any callbacks for this function */ + while(tmp) + { + if(tmp->message == msg || msg == WM_CONTROL) + { + switch(msg) + { + case WM_SIZE: + { + int (*sizefunc)(HWND, int, int, void *) = (int (*)(HWND, int, int, void *))tmp->signalfunction; + + if(hWnd == tmp->window || WinWindowFromID(tmp->window, FID_CLIENT) == hWnd) + { + result = sizefunc(tmp->window, SHORT1FROMMP(mp2), SHORT2FROMMP(mp2), tmp->data); + tmp = NULL; + } + } + break; + case WM_BUTTON1DOWN: + { + POINTS pts = (*((POINTS*)&mp1)); + int (*buttonfunc)(HWND, int, int, int, void *) = (int (*)(HWND, int, int, int, void *))tmp->signalfunction; + + if(hWnd == tmp->window || WinWindowFromID(tmp->window, FID_CLIENT) == hWnd || WinQueryCapture(HWND_DESKTOP) == tmp->window) + { + int button; + + switch(origmsg) + { + case WM_BUTTON1DOWN: + button = 1; + break; + case WM_BUTTON2DOWN: + button = 2; + break; + case WM_BUTTON3DOWN: + button = 3; + break; + } + + result = buttonfunc(tmp->window, pts.x, _get_frame_height(tmp->window) - pts.y, button, tmp->data); + tmp = NULL; + } + } + break; + case WM_BUTTON1UP: + { + POINTS pts = (*((POINTS*)&mp1)); + int (*buttonfunc)(HWND, int, int, int, void *) = (int (*)(HWND, int, int, int, void *))tmp->signalfunction; + + if(hWnd == tmp->window || WinWindowFromID(tmp->window, FID_CLIENT) == hWnd || WinQueryCapture(HWND_DESKTOP) == tmp->window) + { + int button; + + switch(origmsg) + { + case WM_BUTTON1UP: + button = 1; + break; + case WM_BUTTON2UP: + button = 2; + break; + case WM_BUTTON3UP: + button = 3; + break; + } + + result = buttonfunc(tmp->window, pts.x, WinQueryWindow(tmp->window, QW_PARENT) == HWND_DESKTOP ? dw_screen_height() - pts.y : _get_height(tmp->window) - pts.y, button, tmp->data); + tmp = NULL; + } + } + break; + case WM_MOUSEMOVE: + { + int (*motionfunc)(HWND, int, int, int, void *) = (int (*)(HWND, int, int, int, void *))tmp->signalfunction; + + if(hWnd == tmp->window || WinWindowFromID(tmp->window, FID_CLIENT) == hWnd || WinQueryCapture(HWND_DESKTOP) == tmp->window) + { + int keys = 0; + SHORT x = SHORT1FROMMP(mp1), y = SHORT2FROMMP(mp1); + + if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000) + keys = DW_BUTTON1_MASK; + if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000) + keys |= DW_BUTTON2_MASK; + if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) & 0x8000) + keys |= DW_BUTTON3_MASK; + + result = motionfunc(tmp->window, x, _get_frame_height(tmp->window) - y, keys, tmp->data); + tmp = NULL; + } + } + break; + case WM_CHAR: + { + int (*keypressfunc)(HWND, int, void *) = (int (*)(HWND, int, void *))tmp->signalfunction; + + if(hWnd == tmp->window) + { + result = keypressfunc(tmp->window, SHORT1FROMMP(mp2), tmp->data); + tmp = NULL; + } + } + break; + case WM_CLOSE: + { + int (*closefunc)(HWND, void *) = (int (*)(HWND, void *))tmp->signalfunction; + + if(hWnd == tmp->window || hWnd == WinWindowFromID(tmp->window, FID_CLIENT)) + { + result = closefunc(tmp->window, tmp->data); + tmp = NULL; + } + } + break; + case WM_PAINT: + { + HPS hps; + DWExpose exp; + int (*exposefunc)(HWND, DWExpose *, void *) = (int (*)(HWND, DWExpose *, void *))tmp->signalfunction; + RECTL rc; + + if(hWnd == tmp->window) + { + int height = _get_height(hWnd); + + hps = WinBeginPaint(hWnd, 0L, &rc); + exp.x = rc.xLeft; + exp.y = height - rc.yTop - 1; + exp.width = rc.xRight - rc. xLeft; + exp.height = rc.yTop - rc.yBottom; + result = exposefunc(hWnd, &exp, tmp->data); + WinEndPaint(hps); + } + } + break; + case WM_COMMAND: + { + int (*clickfunc)(HWND, void *) = (int (*)(HWND, void *))tmp->signalfunction; + ULONG command = COMMANDMSG(&msg)->cmd; + + if(tmp->window < 65536 && command == tmp->window) + { + result = clickfunc(tmp->window, tmp->data); + tmp = NULL; + } + } + break; + case WM_CONTROL: + if(tmp->message == SHORT2FROMMP(mp1)) + { + switch(SHORT2FROMMP(mp1)) + { + case CN_ENTER: + { + int (*containerselectfunc)(HWND, char *, void *) = (int (*)(HWND, char *, void *))tmp->signalfunction; + int id = SHORT1FROMMP(mp1); + HWND conthwnd = dw_window_from_id(hWnd, id); + char *text = NULL; + + if(mp2) + { + PRECORDCORE pre; + + pre = ((PNOTIFYRECORDENTER)mp2)->pRecord; + if(pre) + text = pre->pszIcon; + } + + if(tmp->window == conthwnd) + { + result = containerselectfunc(tmp->window, text, tmp->data); + tmp = NULL; + } + } + break; + case CN_CONTEXTMENU: + { + int (*containercontextfunc)(HWND, char *, int, int, void *) = (int (*)(HWND, char *, int, int, void *))tmp->signalfunction; + int id = SHORT1FROMMP(mp1); + HWND conthwnd = dw_window_from_id(hWnd, id); + char *text = NULL; + LONG x,y; + + if(mp2) + { + PRECORDCORE pre; + + pre = (PRECORDCORE)mp2; + text = pre->pszIcon; + } + + + dw_pointer_query_pos(&x, &y); + + if(tmp->window == conthwnd) + { + result = containercontextfunc(tmp->window, text, x, y, tmp->data); + tmp = NULL; + } + } + break; + case LN_SELECT: + { + int (*listboxselectfunc)(HWND, int, void *) = (int (*)(HWND, int, void *))tmp->signalfunction; + int id = SHORT1FROMMP(mp1); + HWND conthwnd = dw_window_from_id(hWnd, id); + + if(tmp->window == conthwnd || (!id && tmp->window == (HWND)mp2)) + { + char buf1[500], classbuf[100]; + unsigned int index = dw_listbox_selected(tmp->window); + + dw_listbox_query_text(tmp->window, index, buf1, 500); + + WinQueryClassName(tmp->window, 99, classbuf); + + if(id && strncmp(classbuf, "#6", 2)==0) + { + char *buf2; + + buf2 = dw_window_get_text(tmp->window); + + /* This is to make sure the listboxselect function doesn't + * get called if the user is modifying the entry text. + */ + if(buf2 && *buf2 && *buf1 && strncmp(buf1, buf2, 500) == 0) + result = listboxselectfunc(tmp->window, index, tmp->data); + + if(buf2) + free(buf2); + } + else + result = listboxselectfunc(tmp->window, index, tmp->data); + + tmp = NULL; + } + } + break; + } + } + break; + } + } + if(tmp) + tmp = tmp->next; + + } + + return (MRESULT)result; +} +#endif + +/* Handles control messages sent to the box (owner). */ +MRESULT EXPENTRY _controlproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + Box *blah = WinQueryWindowPtr(hWnd, QWP_USER); + + switch(msg) + { + case WM_CONTROL: + _run_event(hWnd, msg, mp1, mp2); + break; + } + if(blah && blah->oldproc) + { + return blah->oldproc(hWnd, msg, mp1, mp2); + } + + return WinDefWindowProc(hWnd, msg, mp1, mp2); +} + +/* The main window procedure for Dynamic Windows, all the resizing code is done here. */ +MRESULT EXPENTRY _wndproc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + int result = -1; + static int command_active = 0; + void (* windowfunc)(PVOID) = 0L; + + if(filterfunc) + result = filterfunc(hWnd, msg, mp1, mp2); + +#ifndef NO_SIGNALS + if(result == -1 && !command_active) + { + /* Make sure we don't end up in infinite recursion */ + command_active = 1; + + result = (int)_run_event(hWnd, msg, mp1, mp2); + + command_active = 0; + } +#endif + + /* Now that any handlers are done... do normal processing */ + switch( msg ) + { + case WM_ERASEBACKGROUND: + return 0; + + case WM_PAINT: + { + HPS hps; + RECTL rc; + + hps = WinBeginPaint( hWnd, 0L, &rc ); + WinEndPaint( hps ); + break; + } + + case WM_SIZE: + { + Box *mybox = (Box *)WinQueryWindowPtr(hWnd, QWP_USER); + + if(!SHORT1FROMMP(mp2) && !SHORT2FROMMP(mp2)) + return (MPARAM)TRUE; + + if(mybox) + { + /* Hide the window when recalculating to reduce + * CPU load. + */ + WinShowWindow(hWnd, FALSE); + + _do_resize(mybox, SHORT1FROMMP(mp2), SHORT2FROMMP(mp2)); + + WinShowWindow(hWnd, TRUE); + } + } + break; + case WM_MINMAXFRAME: + { + Box *mybox = (Box *)WinQueryWindowPtr(hWnd, QWP_USER); + SWP *swp = (SWP *)mp1; + + if(mybox && (swp->fl & SWP_MAXIMIZE)) + { + int z; + + /* Hide the window when recalculating to reduce + * CPU load. + */ + WinShowWindow(hWnd, FALSE); + + _do_resize(mybox, swp->cx, swp->cy); + + if(mybox->count == 1 && mybox->items[0].type == TYPEBOX) + { + mybox = (Box *)WinQueryWindowPtr(mybox->items[0].hwnd, QWP_USER); + + for(z=0;z<mybox->count;z++) + { + char tmpbuf[100]; + + WinQueryClassName(mybox->items[z].hwnd, 99, tmpbuf); + + /* If we have a notebook we resize the page again. */ + if(strncmp(tmpbuf, "#40", 3)==0) + { + unsigned long x, y, width, height; + int page = dw_notebook_page_query(mybox->items[z].hwnd); + HWND pagehwnd = (HWND)WinSendMsg(mybox->items[z].hwnd, BKM_QUERYPAGEWINDOWHWND, MPFROMLONG(page), 0); + RECTL rc; + + Box *pagebox = (Box *)WinQueryWindowPtr(pagehwnd, QWP_USER); + if(pagebox) + { + dw_window_get_pos_size(mybox->items[z].hwnd, &x, &y, &width, &height); + + rc.xLeft = x; + rc.yBottom = y; + rc.xRight = x + width; + rc.yTop = y + height; + + WinSendMsg(mybox->items[z].hwnd, BKM_CALCPAGERECT, (MPARAM)&rc, (MPARAM)TRUE); + + _do_resize(pagebox, rc.xRight - rc.xLeft, rc.yTop - rc.yBottom); + } + + } + } + + } + + WinShowWindow(hWnd, TRUE); + } + } + break; + case WM_CLOSE: + dw_window_destroy(WinQueryWindow(hWnd, QW_PARENT)); + return (MRESULT)TRUE; + case WM_USER: + windowfunc = (void (*)(void *))mp1; + + if(windowfunc) + windowfunc((void *)mp2); + break; + case WM_CHAR: + if(SHORT1FROMMP(mp2) == '\t') + { + _shift_focus(hWnd); + return FALSE; + } + break; + case WM_DESTROY: + /* Free memory before destroying */ + _free_window_memory(hWnd); + break; + } + if(filterfunc && result != -1) + return (MRESULT)result; + else + return WinDefWindowProc(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 = WinQueryWindowPtr(thisbox->items[z].hwnd, QWP_USER); + _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) */ +MRESULT EXPENTRY _splitwndproc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + HWND hwndFrame = 0; + Box *thisbox = 0; + + hwndFrame = WinQueryWindow(hwnd, QW_PARENT); + if(hwndFrame) + thisbox = WinQueryWindowPtr(hwndFrame, QWL_USER); + + switch (msg) + { + case WM_ACTIVATE: + case WM_SETFOCUS: + return (MRESULT)(FALSE); + + case WM_PAINT: + { + HPS hpsPaint; + RECTL rclPaint; + POINTL ptlStart[SPLITBAR_WIDTH]; + POINTL ptlEnd[SPLITBAR_WIDTH]; + USHORT i; + + hpsPaint = WinBeginPaint(hwnd, 0, 0); + WinQueryWindowRect(hwnd, &rclPaint); + + if(thisbox->type == BOXHORZ) + { + for(i = 0; i < SPLITBAR_WIDTH; i++) + { + ptlStart[i].x = rclPaint.xLeft + i; + ptlStart[i].y = rclPaint.yTop; + + ptlEnd[i].x = rclPaint.xLeft + i; + ptlEnd[i].y = rclPaint.yBottom; + } + } + else + { + for(i = 0; i < SPLITBAR_WIDTH; i++) + { + ptlStart[i].x = rclPaint.xLeft; + ptlStart[i].y = rclPaint.yBottom + i; + + ptlEnd[i].x = rclPaint.xRight; + ptlEnd[i].y = rclPaint.yBottom + i; + } + } + + for(i = 0; i < SPLITBAR_WIDTH; i++) + { + GpiSetColor( hpsPaint, lColor[i]); + GpiMove(hpsPaint, &ptlStart[i]); + GpiLine(hpsPaint, &ptlEnd[i]); + } + WinEndPaint(hpsPaint); + } + return MRFROMSHORT(FALSE); + + case WM_MOUSEMOVE: + { + if(thisbox->type == BOXHORZ) + WinSetPointer(HWND_DESKTOP, + WinQuerySysPointer(HWND_DESKTOP, + SPTR_SIZEWE, + FALSE)); + else + WinSetPointer(HWND_DESKTOP, + WinQuerySysPointer(HWND_DESKTOP, + SPTR_SIZENS, + FALSE)); + } + return MRFROMSHORT(FALSE); + case WM_BUTTON1DOWN: + { + APIRET rc; + RECTL rclFrame; + RECTL rclBounds; + RECTL rclStart; + USHORT startSize, orig, actual; + + WinQueryWindowRect(hwnd, &rclFrame); + WinQueryWindowRect(hwnd, &rclStart); + + WinQueryWindowRect(hwndFrame, &rclBounds); + + WinMapWindowPoints(hwndFrame, HWND_DESKTOP, + (PPOINTL)&rclBounds, 2); + WinMapWindowPoints(hwnd, HWND_DESKTOP, + (PPOINTL)&rclStart, 2); + + { + int z, pastsplitbar = FALSE, found = FALSE; + orig = actual = 0; + + for(z=0;z<thisbox->count;z++) + { + if(thisbox->items[z].hwnd == hwnd) + pastsplitbar = TRUE; + else + { + if(thisbox->type == BOXHORZ) + { + int tmpwidth, tmporigwidth; + + if(thisbox->items[z].type == TYPEBOX) + _count_size(thisbox->items[z].hwnd, BOXHORZ, &tmpwidth, &tmporigwidth); + else + { + tmpwidth = thisbox->items[z].width; + tmporigwidth = thisbox->items[z].origwidth; + } + + if(thisbox->items[z].hsize != SIZESTATIC && tmpwidth > actual && tmporigwidth) + { + found = pastsplitbar; + orig = tmporigwidth; + actual = tmpwidth; + } + } + else + { + int tmpheight, tmporigheight; + + if(thisbox->items[z].type == TYPEBOX) + _count_size(thisbox->items[z].hwnd, BOXVERT, &tmpheight, &tmporigheight); + else + { + tmpheight = thisbox->items[z].height; + tmporigheight = thisbox->items[z].origheight; + } + + if(thisbox->items[z].vsize != SIZESTATIC && tmpheight > actual && tmporigheight) + { + found = pastsplitbar; + orig = tmporigheight; + actual = tmpheight; + } + } + } + } + + /* If we couldn't determine a valid scale... then abort */ + if(!orig || !actual) + return MRFROMSHORT(FALSE); + + if(thisbox->type == BOXHORZ) + { + if(found) + startSize = (rclStart.xLeft - rclBounds.xLeft) + * (((float)actual)/((float)orig)); + else + startSize = (rclStart.xLeft - rclBounds.xLeft) + * (((float)orig)/((float)actual)); + } + else + { + if(found) + startSize = (rclStart.yBottom - rclBounds.yBottom) + * (((float)actual)/((float)orig)); + else + startSize = (rclStart.yBottom - rclBounds.yBottom) + * (((float)orig)/((float)actual)); + } + } + + rc = _TrackRectangle(hwnd, &rclFrame, &rclBounds); + + if(rc == TRUE) + { + USHORT usNewRB; + USHORT percent; + int z; + + if(thisbox->type == BOXHORZ) + { + usNewRB = rclFrame.xLeft + - rclBounds.xLeft; + } + else + { + usNewRB = rclFrame.yBottom + - rclBounds.yBottom; + } + + /* We don't want the item to disappear completely */ + if(!usNewRB) + usNewRB++; + + if(!startSize) + startSize++; + + percent = (usNewRB*100)/startSize; + + for(z=0;z<thisbox->count;z++) + { + if(thisbox->items[z].type == TYPEBOX) + { + Box *tmp = WinQueryWindowPtr(thisbox->items[z].hwnd, QWP_USER); + _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(WinQueryWindow(hwnd, QW_OWNER)); + } + } + return MRFROMSHORT(FALSE); + } + return WinDefWindowProc(hwnd, msg, mp1, mp2); +} + +/* Function: BubbleProc + * Abstract: Subclass procedure for bubble help + */ +MRESULT EXPENTRY _BubbleProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + MRESULT res; + PFNWP proc = (PFNWP)WinQueryWindowPtr(hwnd, QWL_USER); + + if(proc) + res = proc(hwnd, msg, mp1, mp2); + else + res = WinDefWindowProc(hwnd, msg, mp1, mp2); + + if(msg == WM_PAINT) + { + POINTL ptl; + HPS hpsTemp; + RECTL rcl; + int height, width; + + WinQueryWindowRect(hwnd, &rcl); + height = rcl.yTop - rcl.yBottom - 1; + width = rcl.xRight - rcl.xLeft - 1; + + /* Draw a border around the bubble help */ + hpsTemp = WinGetPS(hwnd); + GpiSetColor(hpsTemp, DW_CLR_BLACK); + ptl.x = ptl.y = 0; + GpiMove(hpsTemp, &ptl); + ptl.x = 0; + ptl.y = height; + GpiLine(hpsTemp, &ptl); + ptl.x = ptl.y = 0; + GpiMove(hpsTemp, &ptl); + ptl.y = 0; + ptl.x = width; + GpiLine(hpsTemp, &ptl); + ptl.x = width; + ptl.y = height; + GpiMove(hpsTemp, &ptl); + ptl.x = 0; + ptl.y = height; + GpiLine(hpsTemp, &ptl); + ptl.x = width; + ptl.y = height; + GpiMove(hpsTemp, &ptl); + ptl.y = 0; + ptl.x = width; + GpiLine(hpsTemp, &ptl); + WinReleasePS(hpsTemp); + } + return res; +} + +/* Function: BtProc + * Abstract: Subclass procedure for buttons + */ + +MRESULT EXPENTRY _BtProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + BubbleButton *bubble; + + bubble = (BubbleButton *)WinQueryWindowPtr(hwnd, QWL_USER); + + if(!bubble) + return WinDefWindowProc(hwnd, msg, mp1, mp2); + + switch(msg) + { +#ifndef NO_SIGNALS + case WM_BUTTON1UP: + { + SignalHandler *tmp = Root; + + if(WinIsWindowEnabled(hwnd)) + { + /* Find any callbacks for this function */ + while(tmp) + { + if(tmp->message == WM_COMMAND) + { + /* Make sure it's the right window, and the right ID */ + if(tmp->window == hwnd) + { + /* Due to the fact that if we run the function + * here, finishing actions on the button will occur + * after we run the signal handler. So we post the + * message so the button can finish what it needs to + * do before we run our handler. + */ + WinPostMsg(hwnd, WM_USER, (MPARAM)tmp, 0); + tmp = NULL; + } + } + if(tmp) + tmp= tmp->next; + } + } + } + break; + case WM_USER: + { + SignalHandler *tmp = (SignalHandler *)mp1; + int (*clickfunc)(HWND, void *) = NULL; + + if(tmp) + { + clickfunc = (int (*)(HWND, void *))tmp->signalfunction; + + clickfunc(tmp->window, tmp->data); + } + } + 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(SHORT1FROMMP(mp2) == '\r' || SHORT1FROMMP(mp2) == ' ') + { + SignalHandler *tmp = Root; + + /* Find any callbacks for this function */ + while(tmp) + { + if(tmp->message == WM_COMMAND) + { + /* Make sure it's the right window, and the right ID */ + if(tmp->window == hwnd) + { + WinPostMsg(hwnd, WM_USER, (MPARAM)tmp, 0); + tmp = NULL; + } + } + if(tmp) + tmp= tmp->next; + } + } +#endif + if(SHORT1FROMMP(mp2) == '\t') + { + _shift_focus(hwnd); + return FALSE; + } + } + break; + case 0x041f: + if (hwndBubble) + { + WinDestroyWindow(hwndBubble); + hwndBubble = 0; + } + break; + + case 0x041e: + + if(!*bubble->bubbletext) + break; + + + if(hwndBubble) + { + WinDestroyWindow(hwndBubble); + hwndBubble = 0; + } + + if(!hwndBubble) + { + HPS hpsTemp = 0; + LONG lHight; + LONG lWidth; + POINTL txtPointl[TXTBOX_COUNT]; + POINTL ptlWork = {0,0}; + ULONG ulColor = DW_CLR_YELLOW; + void *blah; + + hwndBubbleLast = hwnd; + hwndBubble = WinCreateWindow(HWND_DESKTOP, + WC_STATIC, + "", + SS_TEXT | + DT_CENTER | + DT_VCENTER, + 0,0,0,0, + HWND_DESKTOP, + HWND_TOP, + 0, + NULL, + NULL); + + WinSetPresParam(hwndBubble, + PP_FONTNAMESIZE, + sizeof(DefaultFont), + DefaultFont); + + + WinSetPresParam(hwndBubble, + PP_BACKGROUNDCOLORINDEX, + sizeof(ulColor), + &ulColor); + + WinSetWindowText(hwndBubble, + bubble->bubbletext); + + WinMapWindowPoints(hwnd, HWND_DESKTOP, &ptlWork, 1); + + hpsTemp = WinGetPS(hwndBubble); + GpiQueryTextBox(hpsTemp, + strlen(bubble->bubbletext), + bubble->bubbletext, + TXTBOX_COUNT, + txtPointl); + WinReleasePS(hpsTemp); + + lWidth = txtPointl[TXTBOX_TOPRIGHT].x - + txtPointl[TXTBOX_TOPLEFT ].x + 8; + + lHight = txtPointl[TXTBOX_TOPLEFT].y - + txtPointl[TXTBOX_BOTTOMLEFT].y + 8; + + ptlWork.y -= lHight; + + blah = (void *)WinSubclassWindow(hwndBubble, _BubbleProc); + + if(blah) + WinSetWindowPtr(hwndBubble, QWP_USER, blah); + + WinSetWindowPos(hwndBubble, + HWND_TOP, + ptlWork.x, + ptlWork.y, + lWidth, + lHight, + SWP_SIZE | SWP_MOVE | SWP_SHOW); + } + break; + } + + if(!bubble->pOldProc) + return WinDefWindowProc(hwnd, msg, mp1, mp2); + return bubble->pOldProc(hwnd, msg, mp1, mp2); +} + +MRESULT EXPENTRY _RendProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + int res = 0; +#ifndef NO_SIGNALS + res = (int)_run_event(hwnd, msg, mp1, mp2); +#endif + switch(msg) + { + case WM_BUTTON1DOWN: + case WM_BUTTON2DOWN: + case WM_BUTTON3DOWN: + if(!res) + WinSetFocus(HWND_DESKTOP, hwnd); + return (MPARAM)TRUE; + } + return WinDefWindowProc(hwnd, msg, mp1, mp2); +} + +/* + * 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) +{ + APIRET rc; + + if(newthread) + { + dwhab = WinInitialize(0); + dwhmq = WinCreateMsgQueue(dwhab, 0); + } + + rc = WinRegisterClass(dwhab, ClassName, _wndproc, CS_SIZEREDRAW | CS_CLIPCHILDREN, 32); + rc = WinRegisterClass(dwhab, SplitbarClassName, _splitwndproc, 0L, 32); + +#ifdef DWDEBUG + f = fopen("dw.log", "wt"); +#endif + return rc; +} + +/* + * 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) +{ + QMSG qmsg; + HAB habtouse; + + if(!currenthab) + habtouse = dwhab; + else + habtouse = currenthab; + + /* Setup the filter function */ + filterfunc = (int (* EXPENTRY)(HWND, ULONG, MPARAM, MPARAM))func; + + _dwtid = dw_thread_id(); + + while (WinGetMsg(habtouse, &qmsg, 0, 0, 0)) + WinDispatchMsg(habtouse, &qmsg); + +#ifdef DWDEBUG + fclose(f); +#endif + + if(!currenthab) + { + WinDestroyMsgQueue(dwhmq); + WinTerminate(dwhab); + } +} + +/* + * 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) +{ + QMSG qmsg; + void *tmp; + + while (WinGetMsg(dwhab, &qmsg, 0, 0, 0)) + { + WinDispatchMsg(dwhab, &qmsg); + 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[1024]; + + va_start(args, format); + vsprintf(outbuf, format, args); + va_end(args); + + WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, outbuf, title, 0, MB_OK | MB_INFORMATION | MB_MOVEABLE); + + 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(WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, text, title, 0, MB_YESNO | MB_INFORMATION | MB_MOVEABLE | MB_SYSTEMMODAL)==MBID_YES) + return TRUE; + return FALSE; +} + +/* + * Makes the window visible. + * Parameters: + * handle: The window handle to make visible. + */ +int dw_window_show(HWND handle) +{ + int rc = WinSetWindowPos(handle, NULLHANDLE, 0, 0, 0, 0, SWP_SHOW); + HSWITCH hswitch; + SWCNTRL swcntrl; + + WinSetFocus(HWND_DESKTOP, handle); + _initial_focus(handle); + + /* If this window has a switch list entry make sure it is visible */ + hswitch = WinQuerySwitchHandle(handle, 0); + if(hswitch) + { + WinQuerySwitchEntry(hswitch, &swcntrl); + swcntrl.uchVisibility = SWL_VISIBLE; + WinChangeSwitchEntry(hswitch, &swcntrl); + } + return rc; + +} + +/* + * Makes the window invisible. + * Parameters: + * handle: The window handle to make visible. + */ +int dw_window_hide(HWND handle) +{ + HSWITCH hswitch; + SWCNTRL swcntrl; + + /* If this window has a switch list entry make sure it is invisible */ + hswitch = WinQuerySwitchHandle(handle, 0); + if(hswitch) + { + WinQuerySwitchEntry(hswitch, &swcntrl); + swcntrl.uchVisibility = SWL_INVISIBLE; + WinChangeSwitchEntry(hswitch, &swcntrl); + } + return WinShowWindow(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 WinDestroyWindow(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) +{ + HWND blah = WinWindowFromID(newparent, FID_CLIENT); + WinSetParent(handle, blah ? blah : newparent, TRUE); +} + +/* + * 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) +{ + return WinSetPresParam(handle, PP_FONTNAMESIZE, strlen(fontname)+1, fontname); +} + +/* + * Sets the colors used by a specified window (widget) handle. + * Parameters: + * handle: The window (widget) handle. + * fore: Foreground color in DW_RGB format or a default color index. + * back: Background color in DW_RGB format or a default color index. + */ +int dw_window_set_color(HWND handle, ULONG fore, ULONG back) +{ + if((fore & DW_RGB_COLOR) == DW_RGB_COLOR) + { + RGB2 rgb2; + + rgb2.bBlue = DW_BLUE_VALUE(fore); + rgb2.bGreen = DW_GREEN_VALUE(fore); + rgb2.bRed = DW_RED_VALUE(fore); + rgb2.fcOptions = 0; + + WinSetPresParam(handle, PP_FOREGROUNDCOLOR, sizeof(RGB2), &rgb2); + + } + if((back & DW_RGB_COLOR) == DW_RGB_COLOR) + { + RGB2 rgb2; + + rgb2.bBlue = DW_BLUE_VALUE(back); + rgb2.bGreen = DW_GREEN_VALUE(back); + rgb2.bRed = DW_RED_VALUE(back); + rgb2.fcOptions = 0; + + WinSetPresParam(handle, PP_BACKGROUNDCOLOR, sizeof(RGB2), &rgb2); + return 0; + } + if((fore & DW_RGB_COLOR) == DW_RGB_COLOR) + return 0; + + /* Slight conversion */ + if(fore == DW_CLR_BLACK) + fore = CLR_BLACK; + if(fore == DW_CLR_WHITE) + fore = CLR_WHITE; + + if(back == DW_CLR_BLACK) + back = CLR_BLACK; + if(back == DW_CLR_WHITE) + back = CLR_WHITE; + + return (WinSetPresParam(handle, PP_FOREGROUNDCOLORINDEX, sizeof(ULONG), &fore) | + WinSetPresParam(handle, PP_BACKGROUNDCOLORINDEX, sizeof(ULONG), &back)); +} + +/* + * 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) +{ + WinSendMsg(handle, WM_SETBORDERSIZE, MPFROMSHORT(border), MPFROMSHORT(border)); + return 0; +} + +/* + * Captures the mouse input to this window. + * Parameters: + * handle: Handle to receive mouse input. + */ +void dw_window_capture(HWND handle) +{ + WinSetCapture(HWND_DESKTOP, handle); +} + +/* + * Releases previous mouse capture. + */ +void dw_window_release(void) +{ + WinSetCapture(HWND_DESKTOP, NULLHANDLE); +} + +/* + * Tracks this window movement. + * Parameters: + * handle: Handle to frame to be tracked. + */ +void dw_window_track(HWND handle) +{ + WinSendMsg(handle, WM_TRACKFRAME, MPFROMSHORT(TF_MOVE), 0); +} + +/* + * Create a new Window Frame. + * Parameters: + * owner: The Owner's window handle or HWND_DESKTOP. + * title: The Window title. + * flStyle: Style flags, see the PM reference. + */ +HWND dw_window_new(HWND hwndOwner, char *title, ULONG flStyle) +{ + HWND hwndclient = 0, hwndframe; + Box *newbox = malloc(sizeof(Box)); + PFNWP *blah = malloc(sizeof(PFNWP)); + + newbox->pad = 0; + newbox->type = BOXVERT; + newbox->count = 0; + + flStyle |= FCF_NOBYTEALIGN; + + hwndframe = WinCreateStdWindow(hwndOwner, 0L, &flStyle, ClassName, title, 0L, NULLHANDLE, 0L, &hwndclient); + *blah = WinSubclassWindow(hwndframe, _sizeproc); + WinSetWindowPtr(hwndframe, QWP_USER, blah); + WinSetWindowPtr(hwndclient, QWP_USER, 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 = NULLHANDLE; + + hwndframe = WinCreateWindow(HWND_OBJECT, + WC_FRAME, + NULL, + WS_VISIBLE | WS_CLIPCHILDREN, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + 0L, + NULL, + NULL); + + newbox->oldproc = WinSubclassWindow(hwndframe, _controlproc); + WinSetWindowPtr(hwndframe, QWP_USER, newbox); + dw_window_set_color(hwndframe, DW_CLR_PALEGRAY, DW_CLR_PALEGRAY); + 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 = WinCreateWindow(HWND_OBJECT, + WC_FRAME, + NULL, + WS_VISIBLE, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + 0L, + NULL, + NULL); + + newbox->grouphwnd = WinCreateWindow(hwndframe, + WC_STATIC, + title, + WS_VISIBLE | SS_GROUPBOX | + WS_GROUP, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + 0L, + NULL, + NULL); + + WinSetWindowPtr(hwndframe, QWP_USER, newbox); + dw_window_set_color(hwndframe, DW_CLR_PALEGRAY, DW_CLR_PALEGRAY); + dw_window_set_color(newbox->grouphwnd, DW_CLR_BLACK, DW_CLR_PALEGRAY); + 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 WinCreateWindow(HWND_OBJECT, + WC_STATIC, + NULL, + WS_VISIBLE | SS_TEXT, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + 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; + HWND tmp; + + if(top) + flags = BKS_MAJORTABTOP; + else + flags = BKS_MAJORTABBOTTOM; + + tmp = WinCreateWindow(HWND_OBJECT, + WC_NOTEBOOK, + NULL, + WS_VISIBLE | + BKS_TABBEDDIALOG | + flags, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + NULL, + NULL); + + 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 = WinCreateWindow(HWND_OBJECT, + WC_MENU, + NULL, + WS_VISIBLE, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + NULL, + 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 = WinCreateWindow(location, + WC_MENU, + NULL, + WS_VISIBLE | MS_ACTIONBAR, + 0,0,2000,1000, + location, + HWND_TOP, + FID_MENU, + NULL, + NULL); + 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) + { + WinDestroyWindow((*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. + * flags: Extended attributes to set on the menu. + * end: If TRUE memu is positioned at the end of the menu. + * check: If TRUE menu is "check"able. + * 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) +{ + MENUITEM miSubMenu; + HWND menu; + + if(!menux) + return NULLHANDLE; + + menu = menux->menu; + + if(end) + miSubMenu.iPosition=MIT_END; + else + miSubMenu.iPosition=0; + + if(strlen(title) == 0) + miSubMenu.afStyle=MIS_SEPARATOR | flags; + else + miSubMenu.afStyle=MIS_TEXT | flags; + miSubMenu.afAttribute=0; + miSubMenu.id=id; + miSubMenu.hwndSubMenu = submenu ? submenu->menu : 0; + miSubMenu.hItem=NULLHANDLE; + + WinSendMsg(menu, + MM_INSERTITEM, + MPFROMP(&miSubMenu), + MPFROMP(title)); + 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) +{ + HWND menu; + + if(!menux) + return; + + menu = menux->menu; + + if(check) + WinSendMsg(menu, MM_SETITEMATTR, MPFROM2SHORT(id, TRUE), + MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED)); + else + WinSendMsg(menu, MM_SETITEMATTR, MPFROM2SHORT(id, TRUE), + MPFROM2SHORT(MIA_CHECKED, 0)); +} + +/* + * 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) + { + WinPopupMenu(HWND_DESKTOP, parent, (*menu)->menu, x, dw_screen_height() - y, 0, PU_KEYBOARD | PU_MOUSEBUTTON1 | PU_VCONSTRAIN | PU_HCONSTRAIN); + free(*menu); + *menu = NULL; + } +} + +/* + * 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) +{ + POINTL ptl; + + WinQueryPointerPos(HWND_DESKTOP, &ptl); + if(x && y) + { + *x = ptl.x; + *y = dw_screen_height() - 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) +{ + WinSetPointerPos(HWND_DESKTOP, x, dw_screen_height() - y); +} + +/* + * 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 = WinCreateWindow(HWND_OBJECT, + WC_CONTAINER, + NULL, + WS_VISIBLE | CCS_READONLY | + CCS_SINGLESEL | CCS_AUTOPOSITION, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + NULL, + NULL); + dw_window_set_font(tmp, DefaultFont); + return tmp; +} + +/* + * 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 = WinCreateWindow(HWND_OBJECT, + WC_STATIC, + text, + WS_VISIBLE | SS_TEXT, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + NULL, + NULL); + dw_window_set_font(tmp, DefaultFont); + dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_PALEGRAY); + 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 = WinCreateWindow(HWND_OBJECT, + WC_MLE, + "", + WS_VISIBLE | + MLS_BORDER | MLS_IGNORETAB | + MLS_READONLY | MLS_VSCROLL, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + NULL, + NULL); + dw_window_set_font(tmp, DefaultFont); + 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) +{ + PFNWP *blah = malloc(sizeof(PFNWP)); + HWND tmp = WinCreateWindow(HWND_OBJECT, + WC_ENTRYFIELD, + text, + WS_VISIBLE | ES_MARGIN | + ES_AUTOSCROLL | WS_TABSTOP, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + NULL, + NULL); + dw_window_set_font(tmp, DefaultFont); + *blah = WinSubclassWindow(tmp, _entryproc); + WinSetWindowPtr(tmp, QWP_USER, blah); + return tmp; +} + +/* + * Create a new Entryfield (password) 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) +{ + PFNWP *blah = malloc(sizeof(PFNWP)); + HWND tmp = WinCreateWindow(HWND_OBJECT, + WC_ENTRYFIELD, + text, + WS_VISIBLE | ES_MARGIN | ES_UNREADABLE | + ES_AUTOSCROLL | WS_TABSTOP, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + NULL, + NULL); + dw_window_set_font(tmp, DefaultFont); + *blah = WinSubclassWindow(tmp, _entryproc); + WinSetWindowPtr(tmp, QWP_USER, blah); + 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) +{ + PFNWP *blah = malloc(sizeof(PFNWP)); + HWND tmp = WinCreateWindow(HWND_OBJECT, + WC_COMBOBOX, + text, + WS_VISIBLE | CBS_DROPDOWN | WS_GROUP, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + NULL, + NULL); + dw_window_set_font(tmp, DefaultFont); + dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_WHITE); + *blah = WinSubclassWindow(tmp, _comboproc); + WinSetWindowPtr(tmp, QWP_USER, blah); + 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 = WinCreateWindow(HWND_OBJECT, + WC_BUTTON, + text, + WS_VISIBLE, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + NULL, + NULL); + + bubble->id = id; + bubble->bubbletext[0] = '\0'; + bubble->pOldProc = WinSubclassWindow(tmp, _BtProc); + + WinSetWindowPtr(tmp, QWP_USER, bubble); + dw_window_set_font(tmp, DefaultFont); + return tmp; +} + +/* Function: GenResIDStr +** Abstract: Generate string '#nnnn' for a given ID for using with Button +** controls +*/ + +void _GenResIDStr(CHAR *buff, ULONG ulID) +{ + char *str; + int slen = 0; + + *buff++ = '#'; + + str = buff; + + do + { + *str++ = (ulID % 10) + '0'; + ulID /= 10; + slen++; + } + while(ulID); + + *str-- = 0; + + for(; str > buff; str--, buff++) + { + *buff ^= *str; + *str ^= *buff; + *buff ^= *str; + } +} + + +/* + * 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) +{ + char idbuf[256]; + HWND tmp; + BubbleButton *bubble = malloc(sizeof(BubbleButton)); + + _GenResIDStr(idbuf, id); + + tmp = WinCreateWindow(HWND_OBJECT, + WC_BUTTON, + idbuf, + WS_VISIBLE | BS_PUSHBUTTON | + BS_BITMAP | BS_AUTOSIZE | + BS_NOPOINTERFOCUS, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + NULL, + NULL); + + bubble->id = id; + strncpy(bubble->bubbletext, text, BUBBLE_HELP_MAX - 1); + bubble->bubbletext[BUBBLE_HELP_MAX - 1] = '\0'; + bubble->pOldProc = WinSubclassWindow(tmp, _BtProc); + + WinSetWindowPtr(tmp, QWP_USER, bubble); + 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) +{ + PFNWP *blah = malloc(sizeof(PFNWP)); + HWND tmp = WinCreateWindow(HWND_OBJECT, + WC_SPINBUTTON, + text, + WS_VISIBLE | SPBS_MASTER, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + NULL, + NULL); + dw_window_set_font(tmp, DefaultFont); + *blah = WinSubclassWindow(tmp, _entryproc); + WinSetWindowPtr(tmp, QWP_USER, blah); + 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) +{ + PFNWP *blah = malloc(sizeof(PFNWP)); + HWND tmp = WinCreateWindow(HWND_OBJECT, + WC_BUTTON, + text, + WS_VISIBLE | + BS_AUTORADIOBUTTON, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + NULL, + NULL); + dw_window_set_font(tmp, DefaultFont); + dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_PALEGRAY); + *blah = WinSubclassWindow(tmp, _entryproc); + WinSetWindowPtr(tmp, QWP_USER, blah); + 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 WinCreateWindow(HWND_OBJECT, + WC_SLIDER, + NULL, + WS_VISIBLE, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + 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) +{ + PFNWP *blah = malloc(sizeof(PFNWP)); + HWND tmp = WinCreateWindow(HWND_OBJECT, + WC_BUTTON, + text, + WS_VISIBLE | BS_AUTOCHECKBOX, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + NULL, + NULL); + dw_window_set_font(tmp, DefaultFont); + dw_window_set_color(tmp, DW_CLR_BLACK, DW_CLR_PALEGRAY); + *blah = WinSubclassWindow(tmp, _entryproc); + WinSetWindowPtr(tmp, QWP_USER, blah); + 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) +{ + PFNWP *blah = malloc(sizeof(PFNWP)); + HWND tmp = WinCreateWindow(HWND_OBJECT, + WC_LISTBOX, + NULL, + WS_VISIBLE | LS_NOADJUSTPOS | + (multi ? LS_MULTIPLESEL : 0), + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + NULL, + NULL); + dw_window_set_font(tmp, DefaultFont); + *blah = WinSubclassWindow(tmp, _entryproc); + WinSetWindowPtr(tmp, QWP_USER, blah); + 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) +{ + HPOINTER icon; + + icon = WinLoadPointer(HWND_DESKTOP,NULLHANDLE,id); + WinSendMsg(handle, WM_SETICON, (MPARAM)icon, 0); +} + +/* + * 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 hbm; + HPS hps = WinGetPS(handle); + + hbm = GpiLoadBitmap(hps, NULLHANDLE, id, 0, 0); + WinSetWindowBits(handle,QWL_STYLE,SS_BITMAP,SS_BITMAP | 0x7f); + WinSendMsg( handle, SM_SETHANDLE, MPFROMP(hbm), NULL ); + /*WinSetWindowULong( hwndDlg, QWL_USER, (ULONG) hbm );*/ + WinReleasePS(hps); +} + +/* + * 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) +{ + WinSetWindowText(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] = ""; + + WinQueryWindowText(handle, 4095, tempbuf); + tempbuf[4095] = 0; + + return strdup(tempbuf); +} + +/* + * Disables given window (widget). + * Parameters: + * handle: Handle to the window. + */ +void dw_window_disable(HWND handle) +{ + WinEnableWindow(handle, FALSE); +} + +/* + * Enables given window (widget). + * Parameters: + * handle: Handle to the window. + */ +void dw_window_enable(HWND handle) +{ + WinEnableWindow(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) +{ + HENUM henum; + HWND child; + char tmpbuf[100]; + + henum = WinBeginEnumWindows(handle); + while((child = WinGetNextWindow(henum)) != NULLHANDLE) + { + int windowid = WinQueryWindowUShort(child, QWS_ID); + HWND found; + + WinQueryClassName(child, 99, tmpbuf); + + /* If the child is a box (frame) then recurse into it */ + if(strncmp(tmpbuf, "#1", 2)==0) + if((found = dw_window_from_id(child, id)) != NULLHANDLE) + return found; + + if(windowid && windowid == id) + { + WinEndEnumWindows(henum); + return child; + } + } + WinEndEnumWindows(henum); + return NULLHANDLE; +} + +/* + * 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; + + if(WinWindowFromID(box, FID_CLIENT)) + { + box = WinWindowFromID(box, FID_CLIENT); + thisbox = WinQueryWindowPtr(box, QWP_USER); + } + else + thisbox = WinQueryWindowPtr(box, QWP_USER); + if(thisbox) + { + if(thisbox->type == BOXHORZ) + dw_box_pack_start_stub(box, item, width, height, hsize, vsize, pad); + else + dw_box_pack_end_stub(box, item, width, height, hsize, vsize, pad); + } +} + +void dw_box_pack_end_stub(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad) +{ + HWND boxowner = NULLHANDLE; + Box *thisbox; + + if(WinWindowFromID(box, FID_CLIENT)) + { + box = WinWindowFromID(box, FID_CLIENT); + thisbox = WinQueryWindowPtr(box, QWP_USER); + hsize = TRUE; + vsize = TRUE; + } + else + thisbox = WinQueryWindowPtr(box, QWP_USER); + if(!thisbox) + { + box = WinWindowFromID(box, FID_CLIENT); + if(box) + { + thisbox = WinQueryWindowPtr(box, QWP_USER); + hsize = TRUE; + vsize = TRUE; + } + } + 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]; + } + + WinQueryClassName(item, 99, tmpbuf); + + if(strncmp(tmpbuf, "#1", 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++; + + /* Don't set the ownership if it's an entryfield or combobox */ + WinQueryClassName(item, 99, tmpbuf); + if(strncmp(tmpbuf, "#6", 2)!=0 /*&& strncmp(tmpbuf, "#2", 2)!=0*/) + { + if((boxowner = WinQueryWindow(box, QW_OWNER)) != 0) + WinSetOwner(item, boxowner); + else + WinSetOwner(item, box); + } + WinSetParent(item, box, FALSE); + } +} + +/* + * 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) +{ + WinSetWindowPos(handle, NULLHANDLE, 0, 0, width, height, SWP_SHOW | SWP_SIZE); +} + +/* + * Returns the width of the screen. + */ +int dw_screen_width(void) +{ + return WinQuerySysValue(HWND_DESKTOP,SV_CXSCREEN); +} + +/* + * Returns the height of the screen. + */ +int dw_screen_height(void) +{ + return WinQuerySysValue(HWND_DESKTOP,SV_CYSCREEN); +} + +/* This should return the current color depth */ +unsigned long dw_color_depth(void) +{ + HDC hdc = WinOpenWindowDC(HWND_DESKTOP); + long colors; + + DevQueryCaps(hdc, CAPS_COLOR_BITCOUNT, 1, &colors); + DevCloseDC(hdc); + return colors; +} + + +/* + * 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) +{ + int myy = _get_frame_height(handle) - (y + _get_height(handle)); + + WinSetWindowPos(handle, NULLHANDLE, x, myy, 0, 0, SWP_MOVE); +} + +/* + * 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) +{ + int myy = _get_frame_height(handle) - (y + height); + + WinSetWindowPos(handle, NULLHANDLE, x, myy, width, height, SWP_MOVE | SWP_SIZE | SWP_SHOW); +} + +/* + * 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) +{ + SWP swp; + WinQueryWindowPos(handle, &swp); + if(x) + *x = swp.x; + if(y) + *y = _get_frame_height(handle) - (swp.y + swp.cy); + if(width) + *width = swp.cx; + if(height) + *height = swp.cy; +} + +/* + * 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) +{ + WinSetWindowBits(handle, QWL_STYLE, style, mask); +} + +/* + * 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) +{ + if(front) + return (ULONG)WinSendMsg(handle, BKM_INSERTPAGE, 0L, + MPFROM2SHORT((BKA_STATUSTEXTON | BKA_AUTOPAGESIZE | BKA_MAJOR | flags), BKA_FIRST)); + return (ULONG)WinSendMsg(handle, BKM_INSERTPAGE, 0L, + MPFROM2SHORT((BKA_STATUSTEXTON | BKA_AUTOPAGESIZE | BKA_MAJOR | flags), BKA_LAST)); +} + +/* + * 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 pageid) +{ + WinSendMsg(handle, BKM_DELETEPAGE, + MPFROMLONG(pageid), (MPARAM)BKA_SINGLE); +} + +/* + * Queries the currently visible page ID. + * Parameters: + * handle: Handle to the notebook widget. + */ +unsigned int dw_notebook_page_query(HWND handle) +{ + return (int)WinSendMsg(handle, BKM_QUERYPAGEID,0L, MPFROM2SHORT(BKA_TOP, BKA_MAJOR)); +} + +/* + * Sets the currently visibale 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 pageid) +{ + WinSendMsg(handle, BKM_TURNTOPAGE, MPFROMLONG(pageid), 0L); +} + +/* + * 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 pageid, char *text) +{ + WinSendMsg(handle, BKM_SETTABTEXT, + MPFROMLONG(pageid), MPFROMP(text)); +} + +/* + * 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) +{ + WinSendMsg(handle, BKM_SETSTATUSLINETEXT, + MPFROMLONG(pageid), MPFROMP(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 pageid, HWND page) +{ + HWND tmpbox = dw_box_new(BOXVERT, 0); + + dw_box_pack_start(tmpbox, page, 0, 0, TRUE, TRUE, 0); + WinSubclassWindow(tmpbox, _wndproc); + WinSendMsg(handle, BKM_SETPAGEWINDOWHWND, + MPFROMLONG(pageid), MPFROMHWND(tmpbox)); +} + +/* + * 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) +{ + WinSendMsg(handle, + LM_INSERTITEM, + MPFROMSHORT(LIT_END), + MPFROMP(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) +{ + WinSendMsg(handle, + LM_DELETEALL, 0L, 0L); +} + +/* + * Returns the listbox's item count. + * Parameters: + * handle: Handle to the listbox to be cleared. + */ +int dw_listbox_count(HWND handle) +{ + return (int)WinSendMsg(handle, + LM_QUERYITEMCOUNT,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) +{ + WinSendMsg(handle, + LM_SETTOPINDEX, + MPFROMSHORT(top), + 0L); +} + +/* + * 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) +{ + WinSendMsg(handle, LM_QUERYITEMTEXT, MPFROM2SHORT(index, length), (MPARAM)buffer); +} + +/* + * 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) +{ + WinSendMsg(handle, LM_SETITEMTEXT, MPFROMSHORT(index), (MPARAM)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) +{ + return (unsigned int)WinSendMsg(handle, + LM_QUERYSELECTION, + MPFROMSHORT(LIT_CURSOR), + 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 place = where; + + if(where == -1) + place = LIT_FIRST; + + place = (int)WinSendMsg(handle, + LM_QUERYSELECTION, + MPFROMSHORT(place),0L); + if(place == LIT_NONE) + return -1; + return place; +} + +/* + * 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) +{ + WinSendMsg(handle, LM_SELECTITEM, MPFROMSHORT(index), (MPARAM)state); + _run_event(handle, WM_CONTROL, MPFROM2SHORT(0, LN_SELECT), (MPARAM)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) +{ + WinSendMsg(handle, LM_DELETEITEM, MPFROMSHORT(index), 0); +} + +/* + * 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) +{ + unsigned long point = startpoint; + PBYTE mlebuf; + + /* Work around 64K limit */ + if(!DosAllocMem((PPVOID) &mlebuf, 65536, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_TILE)) + { + int amount, len = strlen(buffer), written = 0; + + while(written < len) + { + if((len - written) > 65535) + amount = 65535; + else + amount = len - written; + + memcpy(mlebuf, &buffer[written], amount); + mlebuf[amount] = '\0'; + + WinSendMsg(handle, MLM_SETIMPORTEXPORT, MPFROMP(mlebuf), MPFROMLONG(amount+1)); + WinSendMsg(handle, MLM_IMPORT, MPFROMP(&point), MPFROMLONG(amount + 1)); + dw_mle_delete(handle, point, 1); + + written += amount; + } + DosFreeMem(mlebuf); + } + return point - 1; +} + +/* + * 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) +{ + PBYTE mlebuf; + + /* Work around 64K limit */ + if(!DosAllocMem((PPVOID) &mlebuf, 65535, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_TILE)) + { + int amount, copied, written = 0; + + while(written < length) + { + if((length - written) > 65535) + amount = 65535; + else + amount = length - written; + + WinSendMsg(handle, MLM_SETIMPORTEXPORT, MPFROMP(mlebuf), MPFROMLONG(amount)); + copied = (int)WinSendMsg(handle, MLM_EXPORT, MPFROMP(&startpoint), MPFROMLONG(&amount)); + + if(copied) + { + memcpy(&buffer[written], mlebuf, copied); + + written += copied; + } + else + break; + } + DosFreeMem(mlebuf); + } +} + +/* + * 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) +{ + if(bytes) + *bytes = (unsigned long)WinSendMsg(handle, MLM_QUERYTEXTLENGTH, 0, 0); + if(lines) + *lines = (unsigned long)WinSendMsg(handle, MLM_QUERYLINECOUNT, 0, 0); +} + +/* + * 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 *buf = malloc(length+1); + int z, dellen = length; + + dw_mle_export(handle, buf, startpoint, length); + + for(z=0;z<length-1;z++) + { + if(strncmp(&buf[z], "\r\n", 2) == 0) + dellen--; + } + WinSendMsg(handle, MLM_DELETE, MPFROMLONG(startpoint), MPFROMLONG(dellen)); + free(buf); +} + +/* + * Clears all text from an MLE box. + * Parameters: + * handle: Handle to the MLE to be cleared. + */ +void dw_mle_clear(HWND handle) +{ + unsigned long bytes; + + dw_mle_query(handle, &bytes, NULL); + + WinSendMsg(handle, MLM_DELETE, MPFROMLONG(0), MPFROMLONG(bytes)); +} + +/* + * Sets the visible line of an MLE box. + * Parameters: + * handle: Handle to the MLE to be positioned. + * line: Line to be visible. + */ +void dw_mle_set_visible(HWND handle, int line) +{ + int tmppnt; + + if(line > 10) + { + tmppnt = (int)WinSendMsg(handle, MLM_CHARFROMLINE, MPFROMLONG(line - 10), 0); + WinSendMsg(handle, MLM_SETFIRSTCHAR, MPFROMLONG(tmppnt), 0); + } +} + +/* + * 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) +{ + WinSendMsg(handle, MLM_SETSEL, MPFROMLONG(point), MPFROMLONG(point)); +} + +/* + * 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) +{ + MLE_SEARCHDATA msd; + + msd.cb = sizeof(msd); + msd.pchFind = text; + msd.pchReplace = NULL; + msd.cchFind = strlen(text); + msd.cchReplace = 0; + msd.iptStart = point; + msd.iptStop = -1; + + if(WinSendMsg(handle, MLM_SEARCH, MPFROMLONG(MLFSEARCH_SELECTMATCH | flags), (MPARAM)&msd)) + return (int)WinSendMsg(handle, MLM_QUERYSEL,(MPARAM)MLFQS_MAXSEL, 0); + return 0; +} + +/* + * Stops redrawing of an MLE box. + * Parameters: + * handle: Handle to the MLE to freeze. + */ +void dw_mle_freeze(HWND handle) +{ + WinSendMsg(handle, MLM_DISABLEREFRESH, 0, 0); +} + +/* + * Resumes redrawing of an MLE box. + * Parameters: + * handle: Handle to the MLE to thaw. + */ +void dw_mle_thaw(HWND handle) +{ + WinSendMsg(handle, MLM_ENABLEREFRESH, 0, 0); +} + +/* + * Returns the range of the slider. + * Parameters: + * handle: Handle to the slider to be queried. + */ +unsigned int dw_slider_query_range(HWND handle) +{ + return SHORT2FROMMP(WinSendMsg(handle, SLM_QUERYSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION,SMA_RANGEVALUE), 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) +{ + WinSendMsg(handle, SLM_SETSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION,SMA_RANGEVALUE), (MPARAM)position); +} + +/* + * 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) +{ + WinSendMsg(handle, SPBM_SETCURRENTVALUE, MPFROMLONG((long)position), 0L); +} + +/* + * Sets the spinbutton limits. + * Parameters: + * handle: Handle to the spinbutton to be set. + * upper: Upper limit. + * lower: Lower limit. + */ +void dw_spinbutton_set_limits(HWND handle, long upper, long lower) +{ + WinSendMsg(handle, SPBM_SETLIMITS, MPFROMLONG(upper), MPFROMLONG(lower)); +} + +/* + * 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) +{ + WinSendMsg(handle, EM_SETTEXTLIMIT, (MPARAM)limit, (MPARAM)0); +} + + +/* + * Returns the current value of the spinbutton. + * Parameters: + * handle: Handle to the spinbutton to be queried. + */ +long dw_spinbutton_query(HWND handle) +{ + long tmpval = 0L; + + WinSendMsg(handle, SPBM_QUERYVALUE, (MPARAM)&tmpval,0L); + return tmpval; +} + +/* + * Returns the state of the checkbox. + * Parameters: + * handle: Handle to the checkbox to be queried. + */ +int dw_checkbox_query(HWND handle) +{ + return (int)WinSendMsg(handle,BM_QUERYCHECK,0,0); +} + +/* + * 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) +{ + WinSendMsg(handle,BM_SETCHECK,MPFROMSHORT(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. + * (this item may only be used in OS/2) + */ +int dw_container_setup(HWND handle, unsigned long *flags, char **titles, int count, int separator) +{ + PFIELDINFO details, first, left = NULL; + FIELDINFOINSERT detin; + CNRINFO cnri; + int z; + ULONG size = sizeof(RECORDCORE); + ULONG *offStruct = malloc(count * sizeof(ULONG)); + ULONG *tempflags = malloc((count+1) * sizeof(ULONG)); + ULONG *oldflags = (ULONG *)WinQueryWindowPtr(handle, 0); + + if(!offStruct || !tempflags) + return FALSE; + + memcpy(tempflags, flags, count * sizeof(ULONG)); + tempflags[count] = 0; + + WinSetWindowPtr(handle, 0, tempflags); + + if(oldflags) + free(oldflags); + + while((first = (PFIELDINFO)WinSendMsg(handle, CM_QUERYDETAILFIELDINFO, 0, MPFROMSHORT(CMA_FIRST))) != NULL) + { + WinSendMsg(handle, CM_REMOVEDETAILFIELDINFO, (MPARAM)&first, MPFROM2SHORT(1, CMA_FREE)); + } + + /* Figure out the offsets to the items in the struct */ + for(z=0;z<count;z++) + { + offStruct[z] = size; + if(flags[z] & DW_CFA_BITMAPORICON) + size += sizeof(HPOINTER); + else if(flags[z] & DW_CFA_STRING) + size += sizeof(char *); + else if(flags[z] & DW_CFA_ULONG) + size += sizeof(ULONG); + else if(flags[z] & DW_CFA_DATE) + size += sizeof(CDATE); + else if(flags[z] & DW_CFA_TIME) + size += sizeof(CTIME); + } + + first = details = (PFIELDINFO)WinSendMsg(handle, CM_ALLOCDETAILFIELDINFO, MPFROMLONG(count), 0L); + + if(!first) + { + free(offStruct); + return FALSE; + } + + for(z=0;z<count;z++) + { + if(z==separator-1) + left=details; + details->cb = sizeof(FIELDINFO); + details->flData = flags[z]; + details->flTitle = CFA_FITITLEREADONLY; + details->pTitleData = titles[z]; + details->offStruct = offStruct[z]; + details = details->pNextFieldInfo; + } + + detin.cb = sizeof(FIELDINFOINSERT); + detin.fInvalidateFieldInfo = FALSE; + detin.pFieldInfoOrder = (PFIELDINFO) CMA_FIRST; + detin.cFieldInfoInsert = (ULONG)count; + + WinSendMsg(handle, CM_INSERTDETAILFIELDINFO, MPFROMP(first), MPFROMP(&detin)); + + if(count > separator) + { + cnri.cb = sizeof(CNRINFO); + cnri.pFieldInfoLast = left; + cnri.xVertSplitbar = 150; + + WinSendMsg(handle, CM_SETCNRINFO, MPFROMP(&cnri), MPFROMLONG(CMA_PFIELDINFOLAST | CMA_XVERTSPLITBAR)); + } + + free(offStruct); + 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) +{ + char **newtitles = malloc(sizeof(char *) * (count + 2)); + unsigned long *newflags = malloc(sizeof(unsigned long) * (count + 2)); + + newtitles[0] = "Icon"; + newtitles[1] = "Filename"; + + newflags[0] = DW_CFA_BITMAPORICON | DW_CFA_CENTER | DW_CFA_HORZSEPARATOR | DW_CFA_SEPARATOR; + newflags[1] = DW_CFA_STRING | DW_CFA_LEFT | DW_CFA_HORZSEPARATOR; + + memcpy(&newtitles[2], titles, sizeof(char *) * count); + memcpy(&newflags[2], flags, sizeof(unsigned long) * count); + + dw_container_setup(handle, newflags, newtitles, count + 2, 2); + + free(newtitles); + free(newflags); + 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 WinLoadPointer(HWND_DESKTOP,module,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) +{ + WinDestroyPointer(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) +{ + ULONG *flags = (ULONG *)WinQueryWindowPtr(handle, 0); + int z, size = 0, totalsize, count = 0; + PRECORDCORE temp; + void *blah; + + if(!flags) + return NULL; + + while(flags[count]) + count++; + + /* Figure out the offsets to the items in the struct */ + for(z=0;z<count;z++) + { + if(flags[z] & DW_CFA_BITMAPORICON) + size += sizeof(HPOINTER); + else if(flags[z] & DW_CFA_STRING) + size += sizeof(char *); + else if(flags[z] & DW_CFA_ULONG) + size += sizeof(ULONG); + else if(flags[z] & DW_CFA_DATE) + size += sizeof(CDATE); + else if(flags[z] & DW_CFA_TIME) + size += sizeof(CTIME); + } + + totalsize = size + sizeof(RECORDCORE); + + blah = (void *)WinSendMsg(handle, CM_ALLOCRECORD, MPFROMLONG(size), MPFROMLONG(rowcount)); + + if(!blah) + return NULL; + + temp = (PRECORDCORE)blah; + + for(z=0;z<rowcount;z++) + { + temp->cb = totalsize; + temp = temp->preccNextRecord; + } + + return blah; +} + +/* + * 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) +{ + ULONG totalsize, size = 0, *flags = (ULONG *)WinQueryWindowPtr(handle, 0); + int z; + PRECORDCORE temp = (PRECORDCORE)pointer; + void *dest; + + if(!flags) + return; + + /* Figure out the offsets to the items in the struct */ + for(z=0;z<column;z++) + { + if(flags[z] & DW_CFA_BITMAPORICON) + size += sizeof(HPOINTER); + else if(flags[z] & DW_CFA_STRING) + size += sizeof(char *); + else if(flags[z] & DW_CFA_ULONG) + size += sizeof(ULONG); + else if(flags[z] & DW_CFA_DATE) + size += sizeof(CDATE); + else if(flags[z] & DW_CFA_TIME) + size += sizeof(CTIME); + } + + totalsize = size + sizeof(RECORDCORE); + + for(z=0;z<row;z++) + temp = temp->preccNextRecord; + + dest = (void *)(((ULONG)temp)+((ULONG)totalsize)); + + if(flags[column] & DW_CFA_BITMAPORICON) + memcpy(dest, data, sizeof(HPOINTER)); + else if(flags[column] & DW_CFA_STRING) + memcpy(dest, data, sizeof(char *)); + else if(flags[column] & DW_CFA_ULONG) + memcpy(dest, data, sizeof(ULONG)); + else if(flags[column] & DW_CFA_DATE) + memcpy(dest, data, sizeof(CDATE)); + else if(flags[column] & DW_CFA_TIME) + memcpy(dest, data, sizeof(CTIME)); +} + +/* + * 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) +{ + dw_container_set_item(handle, pointer, 0, row, (void *)&icon); + dw_container_set_item(handle, pointer, 1, row, (void *)&filename); +} + +/* + * 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 + 2, row, data); +} + +/* + * 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) +{ + PRECORDCORE temp = (PRECORDCORE)pointer; + int z; + + for(z=0;z<row;z++) + temp = temp->preccNextRecord; + + temp->pszIcon = title; + temp->pszName = title; + temp->pszText = title; +} + +/* + * 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) +{ + RECORDINSERT recin; + + recin.cb = sizeof(RECORDINSERT); + recin.pRecordOrder = (PRECORDCORE)CMA_END; + recin.pRecordParent = NULL; + recin.zOrder = CMA_TOP; + recin.fInvalidateRecord = TRUE; + recin.cRecordsInsert = rowcount; + + WinSendMsg(handle, CM_INSERTRECORD, MPFROMP(pointer), MPFROMP(&recin)); +} + +/* + * Removes all rows from a container. + * Parameters: + * handle: Handle to the window (widget) to be cleared. + */ +void dw_container_clear(HWND handle) +{ + WinSendMsg(handle, CM_REMOVERECORD, (MPARAM)0L, MPFROM2SHORT(0, CMA_INVALIDATE | CMA_FREE)); +} + +/* + * 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) +{ + CNRINFO cnrinfo; + + cnrinfo.flWindowAttr = flags; + cnrinfo.slBitmapOrIcon.cx = iconwidth; + cnrinfo.slBitmapOrIcon.cy = iconheight; + + WinSendMsg(handle, CM_SETCNRINFO, &cnrinfo, MPFROMLONG(CMA_FLWINDOWATTR | CMA_SLBITMAPORICON)); +} + +/* + * 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) +{ + pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)0L, MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER)); + if(pCore) + { + if(flags) + { + while(pCore) + { + if(pCore->flRecordAttr & CRA_SELECTED) + return pCore->pszIcon; + pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)pCore, MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)); + } + } + else + return pCore->pszIcon; + } + return NULL; +} + +/* + * 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) +{ + pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)pCore, MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)); + if(pCore) + { + if(flags) + { + while(pCore) + { + if(pCore->flRecordAttr & CRA_SELECTED) + return pCore->pszIcon; + + pCore = WinSendMsg(handle, CM_QUERYRECORD, (MPARAM)pCore, MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)); + } + } + else + return pCore->pszIcon; + } + return NULL; +} + +/* + * 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 hwndframe = WinCreateWindow(HWND_OBJECT, + WC_FRAME, + NULL, + WS_VISIBLE, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + id, + NULL, + NULL); + WinSubclassWindow(hwndframe, _RendProc); + return hwndframe; +} + +/* Sets the current foreground drawing color. + * Parameters: + * red: red value. + * green: green value. + * blue: blue value. + */ +void dw_color_foreground_set(unsigned long value) +{ + _foreground = DW_RED_VALUE(value) << 16 | DW_GREEN_VALUE(value) << 8 | DW_BLUE_VALUE(value); +} + +/* 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 = DW_RED_VALUE(value) << 16 | DW_GREEN_VALUE(value) << 8 | DW_BLUE_VALUE(value); +} + +HPS _set_hps(HPS hps) +{ + LONG alTable[18]; + + GpiQueryLogColorTable(hps, 0L, 0L, 18L, alTable); + + alTable[16] = _foreground; + alTable[17] = _background; + + GpiCreateLogColorTable(hps, + 0L, + LCOLF_CONSECRGB, + 0L, + 18, + alTable); + GpiSetColor(hps, 16); + GpiSetBackColor(hps, 17); + return hps; +} + +HPS _set_colors(HWND handle) +{ + HPS hps = WinGetPS(handle); + + _set_hps(hps); + return hps; +} + +/* 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) +{ + HPS hps; + int height; + POINTL ptl; + + if(handle) + { + hps = _set_colors(handle); + height = _get_height(handle); + } + else if(pixmap) + { + hps = _set_hps(pixmap->hps); + height = pixmap->height; + } + else + return; + + ptl.x = x; + ptl.y = height - y - 1; + + GpiSetPel(hps, &ptl); + if(!pixmap) + WinReleasePS(hps); +} + +/* 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) +{ + HPS hps; + int height; + POINTL ptl[2]; + + if(handle) + { + hps = _set_colors(handle); + height = _get_height(handle); + } + else if(pixmap) + { + hps = _set_hps(pixmap->hps); + height = pixmap->height; + } + else + return; + + ptl[0].x = x1; + ptl[0].y = height - y1 - 1; + ptl[1].x = x2; + ptl[1].y = height - y2 - 1; + + GpiMove(hps, &ptl[0]); + GpiLine(hps, &ptl[1]); + + if(!pixmap) + WinReleasePS(hps); +} + + +/* 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) +{ + HPS hps; + int size = 9, z, l, height; + POINTL ptl; + FATTRS fat; + SIZEF sizfCharBox; + FONTMETRICS *fm; + LONG lHorzRes, lVertRes, lRequestFonts, lNumberFonts; + HDC hdc; + char fontname[128]; + + if(handle) + { + hps = _set_colors(handle); + height = _get_height(handle); + _GetPPFont(handle, fontname); + } + else if(pixmap) + { + hps = _set_hps(pixmap->hps); + height = pixmap->height; + _GetPPFont(pixmap->handle, fontname); + } + else + return; + + ptl.x = x; + ptl.y = height - y - 2; + + for(z=0;z<strlen(fontname);z++) + { + if(fontname[z]=='.') + break; + } + size = atoi(fontname); + + ptl.y -= size; + + hdc = GpiQueryDevice(hps); + + DevQueryCaps(hdc, CAPS_HORIZONTAL_FONT_RES, 1L, &lHorzRes); + DevQueryCaps(hdc, CAPS_VERTICAL_FONT_RES, 1L, &lVertRes); + + lNumberFonts = GpiQueryFonts(hps, QF_PUBLIC | QF_PRIVATE, &fontname[z+1], &lRequestFonts, 0, NULL); + + fm = malloc(lNumberFonts * sizeof(FONTMETRICS)); + + GpiQueryFonts(hps, QF_PUBLIC | QF_PRIVATE, &fontname[z+1], &lNumberFonts, sizeof(FONTMETRICS), fm); + + fat.lMatch = 0L; + + for(l=0;l<lNumberFonts;l++) + { + if(fm[l].sXDeviceRes == (SHORT)lHorzRes && + fm[l].sYDeviceRes == (SHORT)lVertRes && + (fm[l].fsDefn & 1) == 0 && + fm[l].sNominalPointSize == (size*10)) + { + fat.lMatch = fm[l].lMatch; + break; + } + } + + fat.usRecordLength = sizeof(FATTRS); + fat.fsSelection = 0; + fat.idRegistry = 0; + fat.usCodePage = GpiQueryCp(hps); + fat.lMaxBaselineExt = 0; + fat.lAveCharWidth = 0; + fat.fsType = 0; + fat.fsFontUse = 0; + + strcpy(fat.szFacename , &fontname[z+1]); + + GpiCreateLogFont(hps, NULL, 1L, &fat); + + GpiSetCharSet(hps, 1L); + + if(fm) + free(fm); + else + { + sizfCharBox.cx = MAKEFIXED(size,0); + sizfCharBox.cy = MAKEFIXED(size,0); + GpiSetCharBox(hps, &sizfCharBox); + } + + GpiCharStringAt(hps, &ptl, strlen(text), text); + + if(!pixmap) + WinReleasePS(hps); +} + + + + +/* 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) + * fill: Fill box TRUE or FALSE. + * 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) +{ + HPS hps; + int thisheight; + POINTL ptl[2]; + + if(handle) + { + hps = _set_colors(handle); + thisheight = _get_height(handle); + } + else if(pixmap) + { + hps = _set_hps(pixmap->hps); + thisheight = pixmap->height; + } + else + return; + + ptl[0].x = x; + ptl[0].y = thisheight - y - 1; + ptl[1].x = x + width - 1; + ptl[1].y = thisheight - y - height; + + GpiMove(hps, &ptl[0]); + GpiBox(hps, fill ? DRO_OUTLINEFILL : DRO_OUTLINE, &ptl[1], 0, 0); + + if(!pixmap) + WinReleasePS(hps); +} + +/* 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) +{ + BITMAPINFOHEADER bmih; + SIZEL sizl = { 0, 0 }; + HPIXMAP pixmap; + HDC hdc; + HPS hps; + ULONG ulFlags; + LONG cPlanes, cBitCount; + + if (!(pixmap = calloc(1,sizeof(struct _hpixmap)))) + return NULL; + + hps = WinGetPS(handle); + + hdc = GpiQueryDevice(hps); + ulFlags = GpiQueryPS(hps, &sizl); + + pixmap->handle = handle; + pixmap->hdc = DevOpenDC(dwhab, OD_MEMORY, "*", 0L, NULL, hdc); + pixmap->hps = GpiCreatePS (dwhab, pixmap->hdc, &sizl, ulFlags | GPIA_ASSOC); + + DevQueryCaps(hdc, CAPS_COLOR_PLANES , 1L, &cPlanes); + if (!depth) + { + DevQueryCaps(hdc, CAPS_COLOR_BITCOUNT, 1L, &cBitCount); + depth = cBitCount; + } + + memset(&bmih, 0, sizeof(BITMAPINFOHEADER)); + bmih.cbFix = sizeof(BITMAPINFOHEADER); + bmih.cx = (SHORT)width; + bmih.cy = (SHORT)height; + bmih.cPlanes = (SHORT)cPlanes; + bmih.cBitCount = (SHORT)depth; + + pixmap->width = width; pixmap->height = height; + + pixmap->hbm = GpiCreateBitmap(pixmap->hps, (PBITMAPINFOHEADER2)&bmih, 0L, NULL, NULL); + + GpiSetBitmap(pixmap->hps, pixmap->hbm); + + if (depth>8) + GpiCreateLogColorTable(pixmap->hps, LCOL_PURECOLOR, LCOLF_RGB, 0, 0, NULL ); + + WinReleasePS(hps); + + 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) +{ + BITMAPINFOHEADER bmih; + SIZEL sizl = { 0, 0 }; + HPIXMAP pixmap; + HDC hdc; + HPS hps; + ULONG ulFlags; + + if (!(pixmap = calloc(1,sizeof(struct _hpixmap)))) + return NULL; + + hps = WinGetPS(handle); + + hdc = GpiQueryDevice(hps); + ulFlags = GpiQueryPS(hps, &sizl); + + pixmap->hdc = DevOpenDC(dwhab, OD_MEMORY, "*", 0L, NULL, hdc); + pixmap->hps = GpiCreatePS (dwhab, pixmap->hdc, &sizl, ulFlags | GPIA_ASSOC); + + pixmap->hbm = GpiLoadBitmap(pixmap->hps, NULLHANDLE, id, 0, 0); + + GpiQueryBitmapParameters(pixmap->hbm, &bmih); + + GpiSetBitmap(pixmap->hps, pixmap->hbm); + + pixmap->width = bmih.cx; pixmap->height = bmih.cy; + + WinReleasePS(hps); + + return pixmap; +} + +/* + * Destroys an allocated pixmap. + * Parameters: + * pixmap: Handle to a pixmap returned by + * dw_pixmap_new.. + */ +void dw_pixmap_destroy(HPIXMAP pixmap) +{ + GpiSetBitmap(pixmap->hps, NULLHANDLE); + GpiDeleteBitmap(pixmap->hbm); + GpiAssociate(pixmap->hps, NULLHANDLE); + GpiDestroyPS(pixmap->hps); + DevCloseDC(pixmap->hdc); + 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) +{ + HPS hpsdest; + HPS hpssrc; + POINTL ptl[4]; + int destheight, srcheight; + + if(dest) + { + hpsdest = WinGetPS(dest); + destheight = _get_height(dest); + } + else if(destp) + { + hpsdest = destp->hps; + destheight = destp->height; + } + else + return; + + if(src) + { + hpssrc = WinGetPS(src); + srcheight = _get_height(src); + } + else if(srcp) + { + hpssrc = srcp->hps; + srcheight = srcp->height; + } + else + { + if(!destp) + WinReleasePS(hpsdest); + return; + } + + ptl[0].x = xdest; + ptl[0].y = (destheight - ydest) - height; + ptl[1].x = ptl[0].x + width; + ptl[1].y = destheight - ydest; + ptl[2].x = xsrc; + ptl[2].y = srcheight - (ysrc + height); + ptl[3].x = ptl[2].x + width; + ptl[3].y = ptl[2].y + height; + + GpiBitBlt(hpsdest, hpssrc, 4, ptl, ROP_SRCCOPY, BBO_IGNORE); + + if(!destp) + WinReleasePS(hpsdest); + if(!srcp) + WinReleasePS(hpssrc); +} + +/* + * Emits a beep. + * Parameters: + * freq: Frequency. + * dur: Duration. + */ +void dw_beep(int freq, int dur) +{ + DosBeep(freq, dur); +} + +/* + * Returns the handle to an unnamed mutex semaphore. + */ +HMTX dw_mutex_new(void) +{ + HMTX mutex; + + DosCreateMutexSem(NULL, &mutex, 0, FALSE); + return mutex; +} + +/* + * 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) +{ + DosCloseMutexSem(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) +{ + DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT); +} + +/* + * Reliquishes the access to the semaphore. + * Parameters: + * mutex: The handle to the mutex returned by dw_mutex_new(). + */ +void dw_mutex_unlock(HMTX mutex) +{ + DosReleaseMutexSem(mutex); +} + +/* + * Returns the handle to an unnamed event semaphore. + */ +HEV dw_event_new(void) +{ + HEV blah; + + if(DosCreateEventSem (NULL, &blah, 0L, FALSE)) + return 0; + + return blah; +} + +/* + * 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) +{ + ULONG count; + + if(DosResetEventSem(eve, &count)) + return FALSE; + return TRUE; +} + +/* + * 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) +{ + if(DosPostEventSem(eve)) + return FALSE; + return TRUE; +} + + +/* + * 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 = DosWaitEventSem(eve, timeout); + if(!rc) + return 1; + if(rc == ERROR_TIMEOUT) + 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 || ~DosCloseEventSem(*eve)) + return FALSE; + return TRUE; +} + +/* + * Encapsulate the message queues on OS/2. + */ +void _dwthreadstart(void *data) +{ + HAB thishab = WinInitialize(0); + HMQ thishmq = WinCreateMsgQueue(dwhab, 0); + void (*threadfunc)(void *) = NULL; + void **tmp = (void **)data; + + threadfunc = (void (*)(void *))tmp[0]; + threadfunc(tmp[1]); + + free(tmp); + + WinDestroyMsgQueue(thishmq); + WinTerminate(thishab); +} + +/* + * 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) +{ + void **tmp = malloc(sizeof(void *) * 2); + + tmp[0] = func; + tmp[1] = data; + + return (DWTID)_beginthread((void (*)(void *))_dwthreadstart, NULL, stack, (void *)tmp); +} + +/* + * Ends execution of current thread immediately. + */ +void dw_thread_end(void) +{ + _endthread(); +} + +/* + * Returns the current thread's ID. + */ +DWTID dw_thread_id(void) +{ + return (DWTID)_threadid; +} + +/* + * Cleanly terminates a DW session, should be signal handler safe. + * Parameters: + * exitcode: Exit code reported to the operating system. + */ +void dw_exit(int exitcode) +{ + /* In case we are in a signal handler, don't + * try to free memory that could possibly be + * free()'d by the runtime already. + */ +#ifndef NO_SIGNALS + Root = NULL; +#endif + 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; + + if(WinWindowFromID(box, FID_CLIENT)) + { + box = WinWindowFromID(box, FID_CLIENT); + thisbox = WinQueryWindowPtr(box, QWP_USER); + } + else + thisbox = WinQueryWindowPtr(box, QWP_USER); + if(thisbox) + { + HWND tmp = WinCreateWindow(HWND_OBJECT, + SplitbarClassName, + NULL, + WS_VISIBLE, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + 0L, + 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; + + if(WinWindowFromID(box, FID_CLIENT)) + { + box = WinWindowFromID(box, FID_CLIENT); + thisbox = WinQueryWindowPtr(box, QWP_USER); + } + else + thisbox = WinQueryWindowPtr(box, QWP_USER); + if(thisbox) + { + HWND tmp = WinCreateWindow(HWND_OBJECT, + SplitbarClassName, + NULL, + WS_VISIBLE, + 0,0,2000,1000, + NULLHANDLE, + HWND_TOP, + 0L, + 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 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; + + if(WinWindowFromID(box, FID_CLIENT)) + { + box = WinWindowFromID(box, FID_CLIENT); + thisbox = WinQueryWindowPtr(box, QWP_USER); + } + else + thisbox = WinQueryWindowPtr(box, QWP_USER); + if(thisbox) + { + if(thisbox->type == BOXHORZ) + dw_box_pack_end_stub(box, item, width, height, hsize, vsize, pad); + else + dw_box_pack_start_stub(box, item, width, height, hsize, vsize, pad); + } +} + +void dw_box_pack_start_stub(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad) +{ + HWND boxowner = NULLHANDLE; + Box *thisbox; + + if(WinWindowFromID(box, FID_CLIENT)) + { + box = WinWindowFromID(box, FID_CLIENT); + thisbox = WinQueryWindowPtr(box, QWP_USER); + hsize = TRUE; + vsize = TRUE; + } + else + thisbox = WinQueryWindowPtr(box, QWP_USER); + 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]; + } + + WinQueryClassName(item, 99, tmpbuf); + + if(strncmp(tmpbuf, "#1", 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++; + + WinQueryClassName(item, 99, tmpbuf); + /* Don't set the ownership if it's an entryfield or combobox */ + if(strncmp(tmpbuf, "#6", 2)!=0 /*&& strncmp(tmpbuf, "#2", 2)!=0*/) + { + if((boxowner = WinQueryWindow(box, QW_OWNER)) != 0) + WinSetOwner(item, boxowner); + else + WinSetOwner(item, box); + } + WinSetParent(item, box, FALSE); + } +} + +/* The following two functions graciously contributed by Peter Nielsen. */ +static ULONG _ParseBuildLevel (char* pchBuffer, ULONG ulSize) { + char* pchStart = pchBuffer; + char* pchEnd = pchStart + ulSize - 2; + + while (pchEnd >= pchStart) + { + if ((pchEnd[0] == '#') && (pchEnd[1] == '@')) + { + *pchEnd-- = '\0'; + while (pchEnd >= pchStart) + { + if ((pchEnd[0] == '@') && (pchEnd[1] == '#')) + { + ULONG ulMajor = 0; + ULONG ulMinor = 0; + + char* pch = pchEnd + 2; + while (!isdigit (*pch) && *pch) + pch++; + + while (isdigit (*pch)) + ulMajor = ulMajor * 10 + *pch++ - '0'; + + if (*pch == '.') + { + while (isdigit (*++pch)) + ulMinor = ulMinor * 10 + *pch - '0'; + } + return ((ulMajor << 16) | ulMinor); + } + pchEnd--; + } + } + pchEnd--; + } + return (0); +} + +ULONG _GetSystemBuildLevel(void) { + /* The build level info is normally available in the end of the OS2KRNL file. However, this is not the case in some beta versions of OS/2. + * We first try to find the info in the 256 last bytes of the file. If that fails, we load the entire file and search it completely. + */ + ULONG ulBootDrive = 0; + ULONG ulBuild = 0; + if (DosQuerySysInfo (QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, &ulBootDrive, sizeof (ulBootDrive)) == NO_ERROR) + { + char achFileName[11] = { (char)('A'+ulBootDrive-1),':','\\','O','S','2','K','R','N','L','\0' }; + HFILE hfile; + ULONG ulResult; + if (DosOpen (achFileName, &hfile, &ulResult, 0, 0, OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, NULL) == NO_ERROR) + { + ULONG ulFileSize = 0; + if (DosSetFilePtr (hfile, 0, FILE_END, &ulFileSize) == NO_ERROR) + { + const ULONG ulFirstTry = min (256, ulFileSize); + if (DosSetFilePtr (hfile, -(LONG)ulFirstTry, FILE_END, &ulResult) == NO_ERROR) + { + char *pchBuffer = malloc(ulFirstTry); + if (DosRead (hfile, pchBuffer, ulFirstTry, &ulResult) == NO_ERROR) + { + ulBuild = _ParseBuildLevel (pchBuffer, ulFirstTry); + if (ulBuild == 0) + { + if (DosSetFilePtr (hfile, 0, FILE_BEGIN, &ulResult) == NO_ERROR) + { + free(pchBuffer); + pchBuffer = malloc(ulFileSize); + + if (DosRead (hfile, pchBuffer, ulFileSize, &ulResult) == NO_ERROR) + ulBuild = _ParseBuildLevel (pchBuffer, ulFileSize); + } + } + } + free(pchBuffer); + } + } + DosClose (hfile); + } + } + return (ulBuild); +} + + +/* + * Returns some information about the current operating environment. + * Parameters: + * env: Pointer to a DWEnv struct. + */ +void dw_environment_query(DWEnv *env) +{ + ULONG aulBuffer[4]; + ULONG Build; + + if(!env) + return; + + /* Get the OS/2 version. */ + + DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_MS_COUNT,(void *)aulBuffer, 4*sizeof(ULONG)); + + /* The default is OS/2 2.0 */ + strcpy(env->osName,"OS/2"); + env->MajorVersion = 2; + env->MinorVersion = 0; + + Build = _GetSystemBuildLevel(); + env->MinorBuild = Build & 0xFFFF; + env->MajorBuild = Build >> 16; + + if (aulBuffer[0] == 20) + { + int i = (unsigned int)aulBuffer[1]; + if (i > 20) + { + strcpy(env->osName,"Warp"); + env->MajorVersion = (int)i/10; + env->MinorVersion = i-(((int)i/10)*10); + } + else if (i == 10) + env->MinorVersion = 1; + } +} + +/* + * 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) +{ + FILEDLG fild; + HWND hwndFile; + int len; + + if(defpath) + strcpy(fild.szFullFile, defpath); + else + strcpy(fild.szFullFile, ""); + + len = strlen(fild.szFullFile); + + if(len) + { + if(fild.szFullFile[len-1] != '\\') + strcat(fild.szFullFile, "\\"); + } + strcat(fild.szFullFile, "*"); + + if(ext) + { + strcat(fild.szFullFile, "."); + strcat(fild.szFullFile, ext); + } + + fild.cbSize = sizeof(FILEDLG); + fild.fl = /*FDS_HELPBUTTON |*/ FDS_CENTER | FDS_OPEN_DIALOG; + fild.pszTitle = title; + fild.pszOKButton = ((flags & DW_FILE_SAVE) ? "Save" : "Open"); + fild.ulUser = 0L; + fild.pfnDlgProc = (PFNWP)WinDefFileDlgProc; + fild.lReturn = 0L; + fild.lSRC = 0L; + fild.hMod = 0; + fild.x = 0; + fild.y = 0; + fild.pszIType = (PSZ)NULL; + fild.papszITypeList = (PAPSZ)NULL; + fild.pszIDrive = (PSZ)NULL; + fild.papszIDriveList= (PAPSZ)NULL; + fild.sEAType = (SHORT)0; + fild.papszFQFilename= (PAPSZ)NULL; + fild.ulFQFCount = 0L; + + hwndFile = WinFileDlg(HWND_DESKTOP, HWND_DESKTOP, &fild); + if(hwndFile) + { + switch(fild.lReturn) + { + case DID_OK: + return strdup(fild.szFullFile); + case DID_CANCEL: + return NULL; + } + } + 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) +{ + return spawnvp(P_NOWAIT, program, params); +} + +/* + * Loads a web browser pointed at the given URL. + * Parameters: + * url: Uniform resource locator. + */ +int dw_browse(char *url) +{ + /* Is there a way to find the webbrowser in Unix? */ + char *execargs[3], browser[1024]; + + PrfQueryProfileString(HINI_USERPROFILE, "WPURLDEFAULTSETTINGS", + "DefaultBrowserExe", NULL, browser, 1024); + + execargs[0] = browser; + execargs[1] = url; + execargs[2] = NULL; + + return dw_exec(browser, DW_EXEC_GUI, execargs); +} + +/* + * 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]) + { + 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) +{ + WinSendMsg(handle, WM_USER, (MPARAM)function, (MPARAM)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 main(void) +{ + 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 |= FCF_MINMAX | 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