Bladeren bron

Initial Import.
64-bit OS X support.

woollybah 11 jaren geleden
bovenliggende
commit
60eceb2f02
84 gewijzigde bestanden met toevoegingen van 12008 en 0 verwijderingen
  1. 8 0
      .gitignore
  2. 4519 0
      cocoamaxgui.mod/cocoa.macos.m
  3. 1030 0
      cocoamaxgui.mod/cocoagui.bmx
  4. 232 0
      cocoamaxgui.mod/cocoamaxgui.bmx
  5. 40 0
      drivers.mod/drivers.bmx
  6. 47 0
      localization.mod/doc/createlanguage.bmx
  7. 10 0
      localization.mod/doc/intro.bbdoc
  8. 377 0
      localization.mod/language.bmx
  9. 430 0
      localization.mod/localization.bmx
  10. 36 0
      maxgui.mod/doc/canvasbeginpaint.bmx
  11. 38 0
      maxgui.mod/doc/createbutton.bmx
  12. 49 0
      maxgui.mod/doc/createcanvas.bmx
  13. 51 0
      maxgui.mod/doc/createcombobox.bmx
  14. 23 0
      maxgui.mod/doc/createhtmlview.bmx
  15. 17 0
      maxgui.mod/doc/createlabel.bmx
  16. 36 0
      maxgui.mod/doc/createlistbox.bmx
  17. 64 0
      maxgui.mod/doc/createmenu.bmx
  18. 34 0
      maxgui.mod/doc/createpanel.bmx
  19. 24 0
      maxgui.mod/doc/createprogbar.bmx
  20. 42 0
      maxgui.mod/doc/createslider.bmx
  21. 65 0
      maxgui.mod/doc/createtabber.bmx
  22. 29 0
      maxgui.mod/doc/createtextarea.bmx
  23. 35 0
      maxgui.mod/doc/createtextfield.bmx
  24. 23 0
      maxgui.mod/doc/createtimer.bmx
  25. 37 0
      maxgui.mod/doc/createtoolbar.bmx
  26. 30 0
      maxgui.mod/doc/createtreeview.bmx
  27. 36 0
      maxgui.mod/doc/createwindow.bmx
  28. BIN
      maxgui.mod/doc/fltkbuttons.png
  29. BIN
      maxgui.mod/doc/fltkcombobox.png
  30. BIN
      maxgui.mod/doc/fltklistbox.png
  31. BIN
      maxgui.mod/doc/fltkmenu.png
  32. BIN
      maxgui.mod/doc/fltkpanels.png
  33. BIN
      maxgui.mod/doc/fltkprogbar.png
  34. BIN
      maxgui.mod/doc/fltksliders.png
  35. BIN
      maxgui.mod/doc/fltktabber.png
  36. BIN
      maxgui.mod/doc/fltktextarea.png
  37. BIN
      maxgui.mod/doc/fltktextfield.png
  38. BIN
      maxgui.mod/doc/fltktreeview.png
  39. BIN
      maxgui.mod/doc/fltkwindow.png
  40. 37 0
      maxgui.mod/doc/gadgetclass.bmx
  41. 207 0
      maxgui.mod/doc/intro.bbdoc
  42. 38 0
      maxgui.mod/doc/lookupguicolor.bmx
  43. 50 0
      maxgui.mod/doc/lookupguifont.bmx
  44. BIN
      maxgui.mod/doc/osxbuttons.png
  45. BIN
      maxgui.mod/doc/osxcombobox.png
  46. BIN
      maxgui.mod/doc/osxlistbox.png
  47. BIN
      maxgui.mod/doc/osxmenu.png
  48. BIN
      maxgui.mod/doc/osxpanels.png
  49. BIN
      maxgui.mod/doc/osxprogbar.png
  50. BIN
      maxgui.mod/doc/osxsliders.png
  51. BIN
      maxgui.mod/doc/osxtabber.png
  52. BIN
      maxgui.mod/doc/osxtextarea.png
  53. BIN
      maxgui.mod/doc/osxtextfield.png
  54. BIN
      maxgui.mod/doc/osxtreeview.png
  55. BIN
      maxgui.mod/doc/osxwindow.png
  56. 30 0
      maxgui.mod/doc/popupwindowmenu.bmx
  57. 89 0
      maxgui.mod/doc/redrawgadget.bmx
  58. 28 0
      maxgui.mod/doc/requestcolor.bmx
  59. 33 0
      maxgui.mod/doc/requestfont.bmx
  60. 40 0
      maxgui.mod/doc/setgadgetfilter.bmx
  61. 41 0
      maxgui.mod/doc/setpointer.bmx
  62. BIN
      maxgui.mod/doc/toolbar.png
  63. BIN
      maxgui.mod/doc/win32buttons.png
  64. BIN
      maxgui.mod/doc/win32combobox.png
  65. BIN
      maxgui.mod/doc/win32htmlview.png
  66. BIN
      maxgui.mod/doc/win32listbox.png
  67. BIN
      maxgui.mod/doc/win32menu.png
  68. BIN
      maxgui.mod/doc/win32panels.png
  69. BIN
      maxgui.mod/doc/win32progbar.png
  70. BIN
      maxgui.mod/doc/win32sliders.png
  71. BIN
      maxgui.mod/doc/win32tabber.png
  72. BIN
      maxgui.mod/doc/win32textarea.png
  73. BIN
      maxgui.mod/doc/win32textfield.png
  74. BIN
      maxgui.mod/doc/win32toolbar.png
  75. BIN
      maxgui.mod/doc/win32treeview.png
  76. BIN
      maxgui.mod/doc/win32window.png
  77. 192 0
      maxgui.mod/driver.bmx
  78. 43 0
      maxgui.mod/event.bmx
  79. 1095 0
      maxgui.mod/gadget.bmx
  80. 18 0
      maxgui.mod/gadgetitem.bmx
  81. 23 0
      maxgui.mod/guifont.bmx
  82. 16 0
      maxgui.mod/iconstrip.bmx
  83. 2492 0
      maxgui.mod/maxgui.bmx
  84. 174 0
      maxgui.mod/maxgui.h

+ 8 - 0
.gitignore

@@ -0,0 +1,8 @@
+
+*.x86.a
+*.x86.i
+*.bak
+*.x64.a
+*.x64.i
+
+.bmx/

+ 4519 - 0
cocoamaxgui.mod/cocoa.macos.m

@@ -0,0 +1,4519 @@
+// cocoa.macos.m
+// blitzmax cocoa interface 
+// by [email protected]
+
+#include <AppKit/AppKit.h>
+#include <WebKit/WebView.h>
+#include <WebKit/WebFrame.h>a
+#include <WebKit/WebPolicyDelegate.h>
+#include <WebKit/WebFrameLoadDelegate.h>
+#include <WebKit/WebDataSource.h>
+#include <ApplicationServices/ApplicationServices.h>
+
+#include <brl.mod/blitz.mod/blitz.h>
+#include <maxgui.mod/maxgui.mod/maxgui.h>
+#include <pub.mod/macos.mod/macos.h>
+
+#define STATUSBARHEIGHT 18
+
+// Custom Cursor Stuff
+
+const int curNoEntry = 0;
+const int curHelp = 1;
+const int curSizeAll = 2;
+const int curNESW = 3;
+const int curNWSE = 4;
+
+typedef struct { short bits[16]; short mask[16]; short hitpoint[2]; } ArrayCursor;
+
+ArrayCursor arrCursors[5] =
+{{{0x0000, 0x07E0, 0x1FF0, 0x3838, 0x3C0C, 0x6E0E, 0x6706, 0x6386, 0x61C6, 0x60E6, 0x7076, 0x303C, 0x1C1C, 0x0FF8, 0x07E0, 0x0000},
+{0x0540, 0x0FF0, 0x3FF8, 0x3C3C, 0x7E0E, 0xFF0F, 0x6F86, 0xE7C7, 0x63E6, 0xE1F7, 0x70FE, 0x707E, 0x3C3C, 0x1FFC, 0x0FF0, 0x0540},
+{0x0007, 0x0007}},
+{{0x0000, 0x4078, 0x60FC, 0x71CE, 0x7986, 0x7C06, 0x7E0E, 0x7F1C, 0x7FB8, 0x7C30, 0x6C30, 0x4600, 0x0630, 0x0330, 0x0300, 0x0000},
+{0xC078, 0xE0FC, 0xF1FE, 0xFBFF, 0xFFCF, 0xFF8F, 0xFF1F, 0xFFBE, 0xFFFC, 0xFE78, 0xFF78, 0xEFF8, 0xCFF8, 0x87F8, 0x07F8, 0x0300},
+{0x0001, 0x0001}},
+{{0x0000, 0x0080, 0x01C0, 0x03E0, 0x0080, 0x0888, 0x188C, 0x3FFE, 0x188C, 0x0888, 0x0080, 0x03E0, 0x01C0, 0x0080, 0x0000, 0x0000},
+{0x0080, 0x01C0, 0x03E0, 0x07F0, 0x0BE8, 0x1DDC, 0x3FFE, 0x7FFF, 0x3FFE, 0x1DDC, 0x0BE8, 0x07F0, 0x03E0, 0x01C0, 0x0080, 0x0000},
+{0x0007, 0x0008}},
+{{0x0000, 0x001E, 0x000E, 0x060E, 0x0712, 0x03A0, 0x01C0, 0x00E0, 0x0170, 0x1238, 0x1C18, 0x1C00, 0x1E00, 0x0000, 0x0000, 0x0000},
+{0x007F, 0x003F, 0x0E1F, 0x0F0F, 0x0F97, 0x07E3, 0x03E1, 0x21F0, 0x31F8, 0x3A7C, 0x3C3C, 0x3E1C, 0x3F00, 0x3F80, 0x0000, 0x0000},
+{0x0006, 0x0009}},
+{{0x0000, 0x7800, 0x7000, 0x7060, 0x48E0, 0x05C0, 0x0380, 0x0700, 0x0E80, 0x1C48, 0x1838, 0x0038, 0x0078, 0x0000, 0x0000, 0x0000},
+{0xFE00, 0xFC00, 0xF870, 0xF0F0, 0xE9F0, 0xC7E0, 0x87C0, 0x0F84, 0x1F8C, 0x3E5C, 0x3C3C, 0x387C, 0x00FC, 0x01FC, 0x0000, 0x0000},
+{0x0006, 0x0006}}};
+
+// End of Cursor Stuff
+
+
+void brl_event_EmitEvent( BBObject *event );
+BBObject *maxgui_maxgui_HotKeyEvent( int key,int mods );
+void maxgui_maxgui_event_DispatchGuiEvents();
+void maxgui_cocoamaxgui_cocoagui_EmitCocoaOSEvent( NSEvent *event,void *handle,BBObject *gadget );
+int maxgui_cocoamaxgui_cocoagui_EmitCocoaMouseEvent( NSEvent *event,void *handle );
+int maxgui_cocoamaxgui_cocoagui_EmitCocoaKeyEvent( NSEvent *event,void *handle );
+#ifdef __x86_64
+void maxgui_cocoamaxgui_cocoagui_PostCocoaGuiEvent( int ev,void *handle,BBInt64 data,int mods,int x,int y,BBObject *extra );
+#else
+void maxgui_cocoamaxgui_cocoagui_PostCocoaGuiEvent( int ev,void *handle,int data,int mods,int x,int y,BBObject *extra );
+#endif
+
+int maxgui_cocoamaxgui_cocoagui_FilterChar( void *handle,int key,int mods );
+int maxgui_cocoamaxgui_cocoagui_FilterKeyDown( void *handle,int key,int mods );
+
+static void EmitOSEvent( NSEvent *event,void *handle ){
+//printf("EmitOSEvent\n");fflush(stdout);
+	maxgui_cocoamaxgui_cocoagui_EmitCocoaOSEvent( event,handle,&bbNullObject );
+}
+
+int HaltMouseEvents;
+
+static int EmitMouseEvent( NSEvent *event,void *handle ){
+	if(([event type] == NSScrollWheel) && ([event deltaY] == 0)) return 0;
+	if(!HaltMouseEvents) return maxgui_cocoamaxgui_cocoagui_EmitCocoaMouseEvent( event,handle );
+}
+
+static int EmitKeyEvent( NSEvent *event,void *handle ){
+	return maxgui_cocoamaxgui_cocoagui_EmitCocoaKeyEvent( event,handle );
+}
+
+#ifdef __x86_64
+static void PostGuiEvent( int ev,void *handle,BBInt64 data,int mods,int x,int y,BBObject *extra ){
+#else
+static void PostGuiEvent( int ev,void *handle,int data,int mods,int x,int y,BBObject *extra ){
+#endif
+//printf("PostGuiEvent\n");fflush(stdout);
+	if (extra==0) extra=&bbNullObject;
+	maxgui_cocoamaxgui_cocoagui_PostCocoaGuiEvent( ev,handle,data,mods,x,y,extra );
+}
+
+static int filterKeyDownEvent( NSEvent *event,id source ){
+	int i,sz,res,key,mods;
+	NSString *ch;
+	key=bbSystemTranslateKey( [event keyCode] );
+	mods=bbSystemTranslateMods( [event modifierFlags] );
+	res=maxgui_cocoamaxgui_cocoagui_FilterKeyDown( source,key,mods );
+	if (res==0) return 0;
+	ch=[event characters];
+	sz=[ch length];
+	for( i=0;i<sz;++i ){
+		key=[ch characterAtIndex:i];
+		switch( key ){
+			case 3:key=13;break;	//Brucey's numberpad enter-key hack
+			case 127:key=8;break;
+			case 63272:key=127;break;
+		}
+		res=maxgui_cocoamaxgui_cocoagui_FilterChar( source,key,mods );
+		if (res==0) return 0;
+	}
+	return 1;
+}
+
+void NSRelease( NSObject *obj ){[obj release];}
+
+typedef struct nsgadget nsgadget;
+
+void NSClearItems(nsgadget *gadget);
+
+struct nsgadget{
+// BBObject
+	BBClass*	clas;
+	//int			refs;
+// gadget
+	BBObject	*target;	
+	nsgadget	*group;
+	BBObject	*kidlist;
+	int			x,y,w,h;
+	BBString		*textarg;
+	void			*extra;
+	int			style, sensitivity;
+	int			visible,total;
+	int			lockl,lockr,lockt,lockb;
+	int			lockx,locky,lockw,lockh,lockcw,lockch;
+	void			*filter,*context;
+	void			*items;
+	int			*arrPrevSelection;
+	BBObject		*datasource;
+	void			*datakeys;//$[]
+// nsGadget
+	int			internalclass, origclass;
+	id			handle;		
+	NSView		*view;
+	NSColor		*textcolor;
+	int 			intFontStyle;
+};
+
+// prototypes
+
+void NSSetSelection(nsgadget *gadget,int pos,int length,int units);
+
+@class CocoaApp;
+@class FlippedView;
+@class PanelView;
+@class CanvasView;
+@class ListView;
+@class TreeView;
+@class NodeItem;
+@class TextView;
+@class TabView;
+@class WindowView;
+@class ImageString;
+@class TableView;
+@class ToolView;
+@class Scroller;
+
+@interface CocoaApp:NSObject{
+	NSMutableDictionary	*toolbaritems;
+	NSMutableArray		*menuitems;
+}
+-(id)init;
++(void)delayedGadgetAction:(NSNotification*)n;
++(void)dispatchGuiEvents;
+-(BOOL)windowShouldClose:(id)sender;
+-(void)windowDidResize:(NSNotification *)aNotification;
+-(void)windowDidMove:(NSNotification *)aNotification;
+-(BOOL)windowShouldZoom:(NSWindow *)sender toFrame:(NSRect)newFrame;
+-(void)windowDidBecomeKey:(NSNotification *)aNotification;
+-(void)menuSelect:(id)sender;
+-(void)iconSelect:(id)sender;
+-(void)sliderSelect:(id)sender;
+-(void)scrollerSelect:(id)sender;
+-(void)buttonPush:(id)sender;
+-(void)textEdit:(id)sender;
+-(void)comboBoxSelectionDidChange:(NSNotification *)notification;
+-(void)addToolbarItem:(NSToolbarItem *)item;
+-(NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag;
+-(NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar;
+-(NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar;
+-(BOOL)validateToolbarItem:(NSToolbarItem *)theItem;
+-(void)addMenuItem:(NSMenuItem *)item;
+-(void)removeMenuItem:(NSMenuItem *)item;
+@end
+
+void ScheduleEventDispatch(){
+	[CocoaApp performSelector:@selector(dispatchGuiEvents) withObject:nil afterDelay:0.0];
+}
+
+@interface Scroller:NSScroller{
+}
+-(id)init;
+//-(id)initWithFrame:(NSRect)rect;
+//-(void)drawParts;
+//-(void)drawKnob;
+//-(void)drawKnobSlotInRect:(NSRect)slotRect highlight:(BOOL)flag;
+//-(void)drawArrow:(NSScrollerArrow)arrow highlight:(BOOL)flag;
+//-(void)highlight:(BOOL)flag;
+@end
+
+@interface FlippedView:NSView{
+}
+-(BOOL)isFlipped;
+-(BOOL)mouseDownCanMoveWindow;
+@end
+
+@interface PanelView:NSBox{
+	int			style;
+	int			enabled;
+	nsgadget		*gadget;
+}
+-(BOOL)isFlipped;
+-(BOOL)mouseDownCanMoveWindow;
+-(void)setColor:(NSColor*)rgb;
+-(void)setAlpha:(float)alpha;
+-(void)setGadget:(nsgadget*)_gadget;
+-(void)setStyle:(int)s;
+-(void)setImage:(NSImage *)image withFlags:(int)flags;
+-(BOOL)acceptsFirstResponder;
+-(BOOL)becomeFirstResponder;
+
+-(void)setEnabled:(BOOL)flag;
+-(BOOL)isEnabled;
+@end
+
+@interface PanelViewContent:NSView{
+	NSColor		*color;
+	NSImage		*image;
+	int			imageflags;
+	float		alpha;
+}
+-(BOOL)isFlipped;
+-(BOOL)mouseDownCanMoveWindow;
+-(void)setColor:(NSColor*)rgb;
+-(void)setAlpha:(float)alpha;
+-(void)setImage:(NSImage *)image withFlags:(int)flags;
+-(void)drawRect:(NSRect)rect;
+@end
+
+@interface CanvasView:PanelView{
+}
+-(void)drawRect:(NSRect)rect;
+-(BOOL)acceptsFirstResponder;
+-(BOOL)becomeFirstResponder;
+@end
+
+@interface ListView:NSScrollView{
+	TableView *table;
+	NSTableColumn *column;
+	NSBrowserCell *cell;
+	NSMutableArray *items;
+	NSDictionary	*textstyle;
+}
+-(id)initWithFrame:(NSRect)rect;
+-(id)table;
+-(id)items;
+-(void)removeItemAtIndex:(int)index;
+-(void)setColor:(NSColor*)color;
+-(void)setTextColor:(NSColor*)color;
+-(int)numberOfRowsInTableView:(NSTableView *)aTableView;
+-(id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex;
+-(BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)tableColumn row:(int)rowIndex;
+-(void)clear;
+-(void)addItem:(NSString*)text atIndex:(unsigned)index withImage:(NSImage*)image withTip:(NSString*)tip withExtra:(BBObject*)extra;
+-(void)setItem:(NSString*)text atIndex:(unsigned)index withImage:(NSImage*)image withTip:(NSString*)tip withExtra:(BBObject*)extra;
+-(void)selectItem:(unsigned)index;
+-(void)deselectItem:(unsigned)index;
+-(void)tableViewSelectionDidChange:(NSNotification *)aNotification;
+-(void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex;
+-(void)setEnabled:(BOOL)flag;
+-(BOOL)isEnabled;
+-(void)updateWidthForString:(ImageString *) string;
+-(void)updateWidth;
+-(void)queueWidthUpdate;
+-(void)dealloc;
+-(void)setFont:(NSFont*)font;
+-(NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:( void  *)data;
+@end
+
+@interface TableView:NSTableView{
+}
+-(NSMenu*)menuForEvent:(NSEvent *)theEvent;
+@end
+
+@interface OutlineView:NSOutlineView{
+}
+-(NSMenu*)menuForEvent:(NSEvent *)theEvent;
+@end
+
+@interface NodeItem:NSObject{
+	TreeView		*owner;
+	NodeItem		*parent;
+	NSMutableArray *kids;
+	NSString		*title;
+	NSImage		*icon;
+}
+-(void)dealloc;
+-(id)initWithTitle:(NSString*)text;
+-(void)updateWidth;
+-(void)setOwner:(TreeView*)treeview;
+-(id)getOwner;
+-(void)show;
+-(void)attach:(NodeItem*)parent_ atIndex:(unsigned)index_;
+-(void)remove;
+-(BOOL)canExpand;
+-(NSMutableArray*)kids;
+-(NSString *)value;
+-(NSImage *)icon;
+-(void)setTitle:(NSString*)text;
+-(void)setIcon:(NSImage*)image;
+-(unsigned)count;
+@end
+
+@interface TreeView:NSScrollView{
+@public
+	NSOutlineView	*outline;
+	NSTableColumn	*column,*colin;
+	NSBrowserCell	*cell;
+	NodeItem		*rootNode;
+	NSDictionary	*textstyle;
+}
+-(id)initWithFrame:(NSRect)rect;
+-(void)reloadItem:(id)item;
+-(void)refresh;
+-(int)outlineView:(NSOutlineView*)outlineView numberOfChildrenOfItem:(id)item;
+-(id)outlineView:(NSOutlineView*)outlineView child:(int)index ofItem:(id)item;
+-(BOOL)outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item;
+-(id)outlineView:(NSOutlineView*)outlineView objectValueForTableColumn:(NSTableColumn*)tableColumn byItem:(id)item;
+-(unsigned)count;
+-(id)rootNode;
+-(id)selectedNode;
+-(void)selectNode:(id)node;
+-(void)expandNode:(id)node;
+-(void)collapseNode:(id)node;
+-(void)outlineViewItemDidExpand:(NSNotification *)notification;
+-(void)outlineViewItemDidCollapse:(NSNotification *)notification;
+-(void)outlineViewSelectionDidChange:(NSNotification *)notification;
+-(BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item;
+-(void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)dcell forTableColumn:(NSTableColumn *)tableColumn item:(id)item;
+-(void)setColor:(NSColor*)color;
+-(void)setTextColor:(NSColor*)color;
+-(void)setFont:(NSFont*)font;
+-(void)setEnabled:(BOOL)e;
+-(BOOL)isEnabled;
+-(void)dealloc;
+@end
+
+@interface TextView:NSTextView{
+	@public
+	NSScrollView	*scroll;
+	NSMutableParagraphStyle *style;
+	NSMutableDictionary *styles;
+	NSTextStorage *storage;
+	
+	int lockedNest;
+	NSRange lockedRange;
+}
+-(NSSize)contentSize;
+-(id)storage;
+-(id)initWithFrame:(NSRect)rect;
+-(id)getScroll;
+-(void)setHidden:(BOOL)flag;
+-(void)setWordWrap:(BOOL)flag;
+-(void)setTabs:(int)tabs;
+-(void)setMargins:(int)leftmargin;
+-(void)setText:(NSString*)text;
+-(void)addText:(NSString*)text;
+-(void)setScrollFrame:(NSRect)rect;
+-(void)setTextColor:(NSColor*)color;
+-(void)setColor:(NSColor*)color;
+-(void)setFont:(NSFont*)font;
+-(NSMenu *)menuForEvent:(NSEvent*)theEvent;
+-(void)textDidChange:(NSNotification*)aNotification;
+-(void)textDidEndEditing:(NSNotification*)aNotification;
+-(void)textViewDidChangeSelection:(NSNotification *)aNotification;
+-(void)textStorageDidProcessEditing:(NSNotification *)aNotification;
+-(void)textStorageWillProcessEditing:(NSNotification *)aNotification;
+-(void)updateDragTypeRegistration;
+-(NSArray *)acceptableDragTypes;
+-(void)free;
+@end
+
+@interface TabView:NSTabView{
+	id		client;
+	int		user;
+}
+-(id)initWithFrame:(NSRect)rect;
+-(id)clientView;
+-(void)setFrame:(NSRect)frameRect;
+-(void)selectTabViewItemAtIndex:(int)index;
+-(BOOL)tabView:(NSTabView *)tabView shouldSelectTabViewItem:(NSTabViewItem *)tabViewItem;
+-(void)dealloc;
+@end
+
+@interface WindowView:NSWindow{
+	id	view;
+	id	label[3];
+	nsgadget *gadget;
+	int enabled;
+	int zooming;
+	NSView *dragging;
+}
+-(id)textFirstResponder;
+-(id)initWithContentRect:(NSRect)rect styleMask:(unsigned int)mask backing:(NSBackingStoreType)backing defer:(BOOL)flag withGadget:(nsgadget*)_gadget ;
+-(id)clientView;
+-(void)setStatus:(NSString*)text align:(int)pos;
+-(void)sendEvent:(NSEvent*)event;
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
+-(BOOL)performDragOperation:(id <NSDraggingInfo>)sender;
+-(void)didResize;
+-(void)didMove;
+-(void)zoom;
+-(NSRect)localRect;
+-(BOOL)canBecomeKeyWindow;
+-(BOOL)canBecomeMainWindow;
+-(BOOL)becomeFirstResponder;
+-(void)setEnabled:(BOOL)flag;
+-(BOOL)isEnabled;
+-(void)dealloc;
+@end
+
+@interface ToolView:NSPanel{
+	id	view;
+	id	label[3];
+	nsgadget *gadget;
+	int enabled;
+	int zooming;
+	NSView *dragging;
+}
+-(id)textFirstResponder;
+-(id)initWithContentRect:(NSRect)rect styleMask:(unsigned int)mask backing:(NSBackingStoreType)backing defer:(BOOL)flag withGadget:(nsgadget*)_gadget ;
+-(id)clientView;
+-(void)setStatus:(NSString*)text align:(int)pos;
+-(void)sendEvent:(NSEvent*)event;
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
+-(BOOL)performDragOperation:(id <NSDraggingInfo>)sender;
+-(void)didResize;
+-(void)didMove;
+-(void)zoom;
+-(NSRect)localRect;
+-(BOOL)canBecomeKeyWindow;
+-(BOOL)canBecomeMainWindow;
+-(BOOL)becomeFirstResponder;
+-(void)setEnabled:(BOOL)flag;
+-(BOOL)isEnabled;
+-(void)dealloc;
+@end
+
+static CocoaApp *GlobalApp;
+
+@class HTMLView;
+@interface HTMLView:WebView{
+	int		_state, _style;
+}
+-(id)initWithFrame:(NSRect)rect;
+-(int)loaded;
+-(void)setStyle:(int)style;
+-(void)setAddress:(NSString*)address;
+-(NSString*)address;
+@end
+@implementation HTMLView
+-(id)initWithFrame:(NSRect)rect{
+	self=[super initWithFrame:rect];
+	[self setAutoresizingMask:NSViewNotSizable];
+	[self setPolicyDelegate:self];
+	[self setFrameLoadDelegate:self];
+	[self setUIDelegate:self];
+	[self unregisterDraggedTypes];
+	_state=0;
+	return self;
+}
+-(int)loaded{
+	return _state;
+}
+-(void)setStyle:(int)style{
+	_style = style;
+}
+-(NSString*)address{
+	WebDataSource		*datasource;
+	datasource = [[self mainFrame] provisionalDataSource];
+	if(datasource==nil) datasource = [[self mainFrame] dataSource];
+	if(datasource==nil) return [[NSString alloc] initWithString:@""];
+	return [[[datasource request] URL] absoluteString];
+}
+-(void)setAddress:(NSString*)address{
+	NSURL			*url;
+	NSURLRequest		*request;
+	WebFrame			*frame;
+		
+	url=[NSURL URLWithString:address];
+	if (url==nil) url=[NSURL fileURLWithPath:address];
+	if (url==nil) return;
+	_state=1;
+	request=[NSURLRequest requestWithURL:url];
+	frame=[self mainFrame];
+	[frame loadRequest:request];
+}
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame{
+	int oldstate = _state;
+	NSURLRequest *url;
+	BBString*text;
+	
+	_state=0;
+	
+	url=[[frame dataSource]initialRequest];
+	text=bbStringFromCString((char*)[[[url URL] relativePath] cString]);
+	
+	if(oldstate)
+		PostGuiEvent( BBEVENT_GADGETDONE,sender,0,0,0,0,(BBObject*)text );
+}
+- (void)webView:(WebView *)sender didChangeLocationWithinPageForFrame:(WebFrame *)frame{
+	int oldstate = _state;
+	NSURLRequest *url;
+	BBString*text;
+	
+	_state=0;
+	
+	url=[[frame dataSource]initialRequest];
+	text=bbStringFromCString((char*)[[[url URL] relativePath] cString]);
+	
+	if(oldstate)
+		PostGuiEvent( BBEVENT_GADGETDONE,sender,0,0,0,0,(BBObject*)text );
+}
+- (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)url frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener{
+	BBString*text;
+	int	key;
+	key=(int)[[actionInformation objectForKey:WebActionNavigationTypeKey] intValue];
+	switch (key){
+	case WebNavigationTypeOther:
+	case WebNavigationTypeLinkClicked:
+		if ((_state==0) && (_style & HTMLVIEW_NONAVIGATE)) {
+			[listener ignore];
+			text=bbStringFromCString((char*)[[[url URL] absoluteString] cString]);
+			PostGuiEvent( BBEVENT_GADGETACTION,sender,0,0,0,0,(BBObject*)text );
+		}else{
+			[listener use];
+		}
+	default:
+		[listener use];
+	}
+}
+- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems{
+	if(_style&HTMLVIEW_NOCONTEXTMENU)
+		return [NSArray array];
+	else
+		return defaultMenuItems;
+}
+@end
+
+
+//Toolbar
+
+@class Toolbar;
+@interface Toolbar:NSToolbar{
+	NSMutableDictionary	*items;
+}
+-(id)initWithIdentifier:(NSString *)string;
+-(void)addToolbarItem:(NSToolbarItem *)item;
+-(NSArray *)toolbarAllowedItemIdentifiers;
+-(NSArray *)toolbarDefaultItemIdentifiers;
+@end
+@implementation Toolbar
+-(id)initWithIdentifier:(NSString *)string{
+	self=[super initWithIdentifier:string];
+	items=[[NSMutableDictionary dictionaryWithCapacity:10] retain];
+	return self;
+}
+-(void)addToolbarItem:(NSToolbarItem *)item{
+	[items setObject:item forKey:[item itemIdentifier]];
+}
+-(NSArray *)toolbarAllowedItemIdentifiers{
+	return [items allValues];
+}
+-(NSArray *)toolbarDefaultItemIdentifiers{
+	return [items allValues];
+}
+@end
+
+
+// CocoaApp
+@implementation CocoaApp
++(void)dispatchGuiEvents{
+	maxgui_maxgui_event_DispatchGuiEvents();
+}
++(void)delayedGadgetAction:(NSObject*)o{  // See controlTextDidChange
+	PostGuiEvent( BBEVENT_GADGETACTION, 
+	              o, 
+	              [o respondsToSelector:@selector(indexOfSelectedItem)] ? [o indexOfSelectedItem] : 0,
+	              0,0,0,0 );
+}
+-(void)controlTextDidEndEditing:(NSNotification*)n{
+	PostGuiEvent( BBEVENT_GADGETLOSTFOCUS,[n object],0,0,0,0,0 );
+}
+-(void)controlTextDidChange:(NSNotification*)n{
+	NSObject *o = [n object];
+	[CocoaApp performSelector:@selector(delayedGadgetAction:) withObject:o afterDelay:0.0];
+}
+
+-(id)init{
+	toolbaritems=[[NSMutableDictionary dictionaryWithCapacity:10] retain];
+	menuitems=[[NSMutableArray arrayWithCapacity:10] retain];
+	return self;
+}
+-(BOOL)windowShouldClose:(id)sender{
+	PostGuiEvent( BBEVENT_WINDOWCLOSE,sender,0,0,0,0,0 );
+	return NO;
+}
+-(void)windowDidResize:(NSNotification *)aNotification{
+	WindowView *window;
+	ToolView * panel;
+	if ([[aNotification object] isKindOfClass:[WindowView class]]) {
+		window=(WindowView*)[aNotification object];
+		[window didResize];
+	} else {
+		panel =(ToolView*)[aNotification object];
+		[panel didResize];
+	}
+}
+-(void)windowDidMove:(NSNotification *)aNotification{
+	WindowView *window;
+	ToolView * panel;
+	if ([[aNotification object] isKindOfClass:[WindowView class]]) {
+		window=(WindowView*)[aNotification object];
+		[window didMove];
+	} else {
+		panel =(ToolView*)[aNotification object];
+		[panel didMove];
+	}
+}
+-(BOOL)windowShouldZoom:(NSWindow *)sender toFrame:(NSRect)newFrame{
+	[(WindowView*)sender zoom];
+	return YES;
+}
+-(void)windowDidBecomeKey:(NSNotification *)aNotification{
+	NSWindow *window;
+	window=(NSWindow*)[aNotification object];
+	PostGuiEvent( BBEVENT_WINDOWACTIVATE,window,0,0,0,0,0 );
+}
+-(void)menuSelect:(id)sender{
+	PostGuiEvent( BBEVENT_MENUACTION,sender,[sender tag],0,0,0,0 );
+}
+-(void)iconSelect:(id)sender{
+	NSToolbar	*toolbar;
+	int			index;
+	toolbar=[sender toolbar];
+	index=[[toolbar items] indexOfObject:sender];
+	PostGuiEvent( BBEVENT_GADGETACTION,toolbar,index,0,0,0,0 );
+}
+-(void)sliderSelect:(id)sender{
+	PostGuiEvent( BBEVENT_GADGETACTION,sender,0,0,0,0,0 );
+}
+-(void)scrollerSelect:(id)sender{
+	NSScroller *scroller;
+	int delta=0;
+	scroller=(NSScroller *)sender;
+	switch([scroller hitPart]){
+	case NSScrollerDecrementLine:
+		delta=-1;
+		break;
+	case NSScrollerDecrementPage:
+		delta=-2;
+		break;
+	case NSScrollerIncrementLine:
+		delta=1;
+		break;
+	case NSScrollerIncrementPage:
+		delta=2;
+		break;	
+	}
+	PostGuiEvent( BBEVENT_GADGETACTION,sender,delta,0,0,0,0 );
+}
+-(void)buttonPush:(id)sender{
+	if([sender allowsMixedState]) [sender setAllowsMixedState:NO];
+	PostGuiEvent( BBEVENT_GADGETACTION,sender,0,0,0,0,0 );
+}
+-(void)textEdit:(id)sender{
+	PostGuiEvent( BBEVENT_GADGETACTION,sender,0,0,0,0,0 );
+}
+-(void)comboBoxSelectionDidChange:(NSNotification *)notification{
+	NSControl *o=(NSComboBox*)[notification object];
+	[CocoaApp performSelector:@selector(delayedGadgetAction:) withObject:o afterDelay:0.0];
+}
+-(void)comboBoxSelectionIsChanging:(NSNotification *)notification{
+	
+}
+-(void)comboBoxWillPopUp:(NSNotification *)notification{
+	HaltMouseEvents = 1;
+}
+-(void)comboBoxWillDismiss:(NSNotification *)notification{
+	HaltMouseEvents = 0;
+}
+-(void)addToolbarItem:(NSToolbarItem *)item{
+	[toolbaritems setObject:item forKey:[item itemIdentifier]];
+}
+-(NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag{
+	return [toolbaritems objectForKey:itemIdentifier];
+}
+-(NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar{
+	Toolbar *mytoolbar=(Toolbar*)toolbar;
+	return [mytoolbar toolbarAllowedItemIdentifiers];
+}
+-(NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar{
+	Toolbar *mytoolbar=(Toolbar*)toolbar;
+	return [mytoolbar toolbarDefaultItemIdentifiers];
+}
+-(BOOL)validateToolbarItem:(NSToolbarItem *)item{
+	return [item isEnabled];
+}
+-(void)addMenuItem:(NSMenuItem *)item{
+	[menuitems addObject:item];
+}
+-(void)removeMenuItem:(NSMenuItem *)item{
+	[menuitems removeObject:item];
+}
+
+@end
+
+// Scroller
+
+@implementation Scroller
+-(id)init{
+	[super init];
+	[self setAlphaValue:.5f];		
+	return self;
+}
+//-(void)drawKnob{}
+//-(void)drawParts{}
+//-(void)drawKnobSlotInRect:(NSRect)slotRect highlight:(BOOL)flag{}
+//-(void)drawArrow:(NSScrollerArrow)arrow highlight:(BOOL)flag{}
+//-(void)highlight:(BOOL)flag{}
+@end
+
+// FlippedView
+
+@implementation FlippedView
+-(BOOL)isFlipped{
+	return YES;
+}
+-(BOOL)mouseDownCanMoveWindow{
+	return YES;
+}
+@end
+
+// PanelView
+
+@implementation PanelView
+- (BOOL)acceptsFirstResponder{
+	return YES;
+}
+-(BOOL)becomeFirstResponder{
+	return [self isEnabled];
+}
+-(void)setColor:(NSColor *)rgb{
+	[[self contentView] setColor:rgb];
+}
+-(void)setAlpha:(float)al{
+	[[self contentView] setAlpha:al];
+}
+-(void)setImage:(NSImage *)img withFlags:(int)flags{
+	[[self contentView] setImage:img withFlags:flags];
+}
+-(void)setEnabled:(BOOL)e{
+	enabled=e;
+}
+-(BOOL)isEnabled{
+	return (enabled)?YES:NO;
+}
+-(void)setStyle:(int)s{
+	
+	gadget->sensitivity |= (s & PANEL_ACTIVE) ? (SENSITIZE_MOUSE|SENSITIZE_KEYS) : 0;
+	
+	switch ( s & (PANEL_SUNKEN|PANEL_RAISED|PANEL_GROUP) ){
+		case PANEL_GROUP:
+			[self setContentViewMargins: NSMakeSize(4.0,4.0)];
+			[self setBoxType:NSBoxPrimary];
+			[self setBorderType: NSBezelBorder];
+			[self setTitlePosition: NSAtTop];
+			break;
+		case PANEL_RAISED:
+		case PANEL_SUNKEN:
+			[self setContentViewMargins: NSMakeSize(0.0,0.0)];
+			[self setBoxType: NSBoxOldStyle];
+			[self setBorderType: NSLineBorder];
+			[self setTitlePosition: NSNoTitle];
+			break;
+		default:
+			[self setContentViewMargins: NSMakeSize(0.0,0.0)];
+			[self setBorderType: NSNoBorder];
+			[self setTitlePosition: NSNoTitle];
+	}
+	
+	style=s;
+}
+-(void)setGadget:(nsgadget*)_gadget{
+	gadget=_gadget;
+}
+-(BOOL)mouseDownCanMoveWindow{
+	return NO;
+}
+@end
+
+//PanelViewContent
+@implementation PanelViewContent
+-(BOOL)isFlipped{
+	return YES;
+}
+-(BOOL)mouseDownCanMoveWindow{
+	return NO;
+}
+-(void)setColor:(NSColor *)rgb{
+	if (color){
+		[color release];
+		color=0;
+	}
+	if(rgb){
+		color=[rgb colorWithAlphaComponent:1.0];
+		[color retain];
+	}
+	[self setNeedsDisplay:YES];
+}
+-(void)setImage:(NSImage *)img withFlags:(int)flags{
+	if (img) [img retain];
+	if (image) [image release];
+	image=img;
+	imageflags=flags;
+	[self setNeedsDisplay:YES];
+}
+-(void)setAlpha:(float)al{
+	alpha=al;
+	if (color){
+		[color release];
+		color=[color colorWithAlphaComponent:alpha];
+		[color retain];
+	}
+	[self setNeedsDisplay:YES];
+}
+-(void)drawRect:(NSRect)rect{
+	
+	NSRect dest = NSUnionRect(rect,[self frame]);
+	
+	if (color){
+		[color set];
+		if (alpha<1.0)
+			NSRectFillUsingOperation( dest,NSCompositeSourceOver );
+		else
+			NSRectFill( dest );
+	}
+	
+	if (image){
+		int		op,x,y,w,h;
+		float	a;
+		float	m,mm;
+		NSRect	src,tile;
+
+		a=alpha;
+		op=NSCompositeSourceOver;
+		src.origin.x=0;
+		src.origin.y=0;
+		src.size=[image size];
+		[image setFlipped:YES];
+
+		switch (imageflags&(GADGETPIXMAP_ICON-1)){
+		case PANELPIXMAP_TILE:
+			tile.size=[image size];
+			for (y=0;y<dest.size.height;y+=src.size.height){
+				tile.origin.y=y;
+				for (x=0;x<dest.size.width;x+=src.size.width){
+					tile.origin.x=x;
+					[image drawInRect:tile fromRect:src operation:op fraction:a];
+				}
+			}					
+			break;
+		case PANELPIXMAP_CENTER:
+			dest.origin.x=(dest.size.width-src.size.width)/2;
+			dest.origin.y=(dest.size.height-src.size.height)/2;
+			dest.size=src.size;
+			[image drawInRect:dest fromRect:src operation:op fraction:a];
+			break;
+		case PANELPIXMAP_FIT:
+			m=dest.size.width/src.size.width;
+			mm=dest.size.height/src.size.height;
+			if (m>mm) m=mm;
+			dest.origin.x+=(dest.size.width-src.size.width*m)/2;
+			dest.origin.y+=(dest.size.height-src.size.height*m)/2;
+			dest.size.width=src.size.width*m;
+			dest.size.height=src.size.height*m;
+			[image drawInRect:dest fromRect:src operation:op fraction:a];
+			break;
+		case PANELPIXMAP_STRETCH:
+			[image drawInRect:dest fromRect:src operation:op fraction:a];
+			break;
+		case PANELPIXMAP_FIT2:
+			m = dest.size.width/dest.size.height;
+			
+			if ((dest.size.width/src.size.width)<(dest.size.height/src.size.height)){
+				src.origin.x = (src.size.width-(src.size.height*m))/2;
+				src.size.width = src.size.height*m;
+			} else {
+				src.origin.y = (src.size.height-(src.size.width/m))/2;
+				src.size.height = src.size.width/m;
+			}
+			
+			[image drawInRect:dest fromRect:src operation:op fraction:a];
+			break;
+		}
+		[image setFlipped:NO];
+	}
+	
+	[super drawRect:rect];
+} 
+@end
+
+// CanvasView
+@implementation CanvasView
+-(void)drawRect:(NSRect)rect{
+	[super drawRect:rect];
+	PostGuiEvent( BBEVENT_GADGETPAINT,self,0,0,0,0,0 );
+} 
+- (BOOL)acceptsFirstResponder{
+	return YES;
+}
+-(BOOL)becomeFirstResponder{
+	return [self isEnabled];
+}
+@end
+
+// ImageString
+
+@class ImageString;
+@interface ImageString:NSObject{
+	NSString	*_string;
+	NSImage	*_image;
+	NSString	*_tip;
+	BBObject	*_extra;
+}
+-(id)initWithString:(NSString *)text image:(NSImage *)image tip:(NSString *)tip extra:(BBObject*)extra;
+-(void)dealloc;
+-(id)copyWithZone:(NSZone *)zone;
+-(NSString*)string;
+-(NSImage*)image;
+-(NSString*)description;
+-(BBObject*)extra;
+@end
+@implementation ImageString
+-(id)initWithString:(NSString *)string image:(NSImage *)image tip:(NSString*)tip extra:(BBObject*)extra{
+	_string=string;
+	_image=image;
+	_tip=tip;
+	_extra=extra;
+	if (string) [string retain];
+	if (image) [image retain];
+	if (tip) [tip retain];
+	return self;
+}
+-(void)dealloc{
+	if (_string) [_string release];
+	if (_image) [_image release];
+	if (_tip) [_tip release];
+	[super dealloc];
+}
+-(id)copyWithZone:(NSZone *)zone{
+	ImageString *copy=[[[self class] allocWithZone:zone] initWithString:_string image:_image tip:_tip extra:_extra];
+	return copy;
+}
+-(NSString*)string{return _string;}
+-(NSImage*)image{return _image;}
+-(NSString*)description{return _tip;}
+-(BBObject*)extra{return _extra;}
+@end
+
+// ListView
+
+@implementation ListView
+-(id)initWithFrame:(NSRect)rect{
+	[super initWithFrame:rect];
+	[self setBorderType:NSNoBorder];
+	[self setHasVerticalScroller:YES];
+	[self setHasHorizontalScroller:YES];
+	[self setAutohidesScrollers:YES];
+	column=[[NSTableColumn alloc] init];
+	cell=[[NSBrowserCell alloc] init];
+	[cell setLeaf:YES];
+	[column setDataCell:cell];
+	NSSize contentSize = [self contentSize];	
+	table=[[TableView alloc] initWithFrame:NSMakeRect(0, 0,contentSize.width, contentSize.height)];
+	[table setAutoresizingMask:(NSViewWidthSizable|NSViewHeightSizable)];
+	items=[[NSMutableArray alloc] initWithCapacity:10];
+	[table setHeaderView:nil];	
+	[table setDataSource:self];
+	[table setDelegate:self];
+	[self setDocumentView:table];
+	[table addTableColumn:column];
+	[table sizeLastColumnToFit];
+	return self;
+}
+-(id)table{
+	return table;
+}
+-(id)items{
+	return items;
+}
+-(void)removeItemAtIndex:(int)index{
+	ImageString *item=(ImageString*)[items objectAtIndex:index];
+	[items removeObjectAtIndex:index];
+	[item release];
+	[table reloadData];
+	[self queueWidthUpdate];
+}
+-(void)setColor:(NSColor*)color{
+	[table setBackgroundColor:color];
+}
+-(void)setEnabled:(BOOL)e{
+	[table setEnabled:e];
+}
+-(BOOL)isEnabled{
+	return [table isEnabled];
+}
+-(void)setTextColor:(NSColor*)color{
+	if (textstyle) {[textstyle release];textstyle=nil;}
+	if (color){
+		textstyle=[NSDictionary dictionaryWithObjectsAndKeys:color,NSForegroundColorAttributeName,nil];
+		[textstyle retain];	
+	}
+}
+-(int)numberOfRowsInTableView:(NSTableView *)aTableView{
+	return [items count];
+}
+-(id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex{
+	return [items objectAtIndex:rowIndex];
+}
+-(BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)tableColumn row:(int)rowIndex{ /*new from BAH*/
+	PostGuiEvent( BBEVENT_GADGETACTION,self,rowIndex,0,0,0,0 );
+	return NO;
+}
+-(void)clear{
+	[table setDelegate:nil];
+
+	ImageString *item;
+	int count,i;
+	count=[items count];
+	for (i=0;i<count;i++){
+		item=(ImageString*)[items objectAtIndex:i];
+		[item release];
+	}
+
+	[items removeAllObjects];
+	[table reloadData];
+	[table setDelegate:self];
+	[self queueWidthUpdate];
+}
+-(void)addItem:(NSString*)text atIndex:(unsigned)index withImage:(NSImage*)image withTip:(NSString*)tip withExtra:(BBObject*)extra{
+	ImageString *item;
+	item=[[ImageString alloc] initWithString:text image:image tip:tip extra:extra];
+	[items insertObject:item atIndex:index];
+	[self updateWidthForString:item];
+	[table noteNumberOfRowsChanged];
+}
+-(void)setItem:(NSString*)text atIndex:(unsigned)index withImage:(NSImage*)image withTip:(NSString*)tip withExtra:(BBObject*)extra{
+	ImageString *item;
+	item=(ImageString*)[items objectAtIndex:index];
+	[item release];
+	item=[[ImageString alloc] initWithString:text image:image tip:tip extra:extra];
+	[items replaceObjectAtIndex:index withObject:item];
+	[table reloadData];
+	[self queueWidthUpdate];
+}
+-(void)selectItem:(unsigned)index{
+	[table setDelegate:nil];
+	[table selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO];
+	[table setDelegate:self];
+}
+-(void)deselectItem:(unsigned)index{
+	[table setDelegate:nil];
+	[table deselectRow:index];
+	[table setDelegate:self];
+}
+-(void)tableViewSelectionDidChange:(NSNotification *)aNotification{/*new from BAH*/
+        int index=[table selectedRow];
+        ImageString *item=nil;
+        if (index>=0) item=(ImageString*)[items objectAtIndex:index]; else index=-1;
+        if (item){
+                PostGuiEvent( BBEVENT_GADGETSELECT,self,index,0,0,0,[item extra]);
+        }else{
+                PostGuiEvent( BBEVENT_GADGETSELECT,self,-1,0,0,0,&bbNullObject);
+        }
+}
+-(void)tableView:(NSTableView *)table willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex{
+	NSString *text=[[items objectAtIndex:rowIndex] string];
+	if (textstyle){
+		NSAttributedString *atext=[[[NSAttributedString alloc] initWithString:text attributes:textstyle] autorelease];
+		[aCell setAttributedStringValue:atext];
+	}else{
+		[aCell setStringValue:text];
+	}
+	[aCell setImage:[[items objectAtIndex:rowIndex] image]];
+}
+-(void)updateWidthForString:(ImageString *) imgstring{
+	
+	NSCell*	dcell;
+	float	cellWidth;
+	
+	dcell = [column dataCell];
+	[dcell setStringValue:[imgstring string]];
+	[dcell setImage:[imgstring image]];
+	cellWidth = ((NSSize)[dcell cellSize]).width;
+
+	if([column minWidth] < cellWidth){
+		[column setMinWidth:cellWidth];
+		[column setWidth:cellWidth];
+		[table setNeedsDisplay:YES];
+	}
+	
+}
+-(void)updateWidth{
+	int i, count;
+	count = [items count];
+	[column setMinWidth:0];
+	for (i=0;i<count;i++)
+		[self updateWidthForString:(ImageString*)[items objectAtIndex:i]];
+}
+-(void)queueWidthUpdate{
+	[NSObject cancelPreviousPerformRequestsWithTarget: self selector:@selector(updateWidth) object:nil];
+	[self performSelector:@selector(updateWidth) withObject:nil afterDelay:0.0];
+}
+-(void)dealloc{
+	ImageString *item;
+	int count,i;
+	count=[items count];
+	for (i=0;i<count;i++){
+		item=(ImageString*)[items objectAtIndex:i];
+		[item release];
+	}
+
+	[table release];
+	[column release];
+	[cell release];
+	[items release];
+	if (textstyle) {
+		[textstyle release];
+	}
+	[super dealloc];
+}
+-(void)setFont:(NSFont*)font{
+	if (font) {
+		NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
+		[table setRowHeight:[layoutManager defaultLineHeightForFont:font]+2];
+		[layoutManager release];
+		[[column dataCell] setFont:font];
+		[table reloadData];
+		[self updateWidth];
+	}
+}
+
+- (NSString *)tableView:(NSTableView *)aTableView toolTipForCell:(NSCell *)aCell rect:(NSRectPointer)rect 
+tableColumn:(NSTableColumn *)aTableColumn row:(int)row mouseLocation:(NSPoint)mouseLocation{
+	
+	return [[items objectAtIndex:row] description];
+}
+
+@end
+
+// TableView
+
+@implementation TableView
+-(NSMenu*)menuForEvent:(NSEvent *)theEvent{
+	int		row = -1;
+	NSPoint p=[self convertPoint:[theEvent locationInWindow] fromView:nil];
+	row = [self rowAtPoint:p];
+
+	if (row < [self numberOfRows]) {
+		[self selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
+		PostGuiEvent( BBEVENT_GADGETMENU,[self dataSource],row,0,0,0,0 );
+	}
+
+	return nil;
+}
+@end
+
+// OutlineView
+
+@implementation OutlineView
+-(NSMenu*)menuForEvent:(NSEvent *)theEvent{
+	id		node;
+	NSPoint p=[self convertPoint:[theEvent locationInWindow] fromView:nil];
+	int i=[self rowAtPoint:p];
+	if (i>-1 && i<[self numberOfRows]){
+		node=[self itemAtRow:i];
+#ifdef __x86_64
+		PostGuiEvent( BBEVENT_GADGETMENU,[self dataSource],(BBInt64)node,0,0,0,0 );	//[self superview]
+#else
+		PostGuiEvent( BBEVENT_GADGETMENU,[self dataSource],(int)node,0,0,0,0 );	//[self superview]
+#endif
+	}
+	return nil;
+}
+@end
+
+// TreeView
+
+@implementation TreeView
+-(id)initWithFrame:(NSRect)rect{
+	[super initWithFrame:rect];
+	[self setBorderType:NSNoBorder];
+	[self setHasVerticalScroller:YES];
+	[self setHasHorizontalScroller:YES];
+	[self setAutohidesScrollers:YES];
+	rootNode=[[NodeItem alloc] initWithTitle:@"root"];
+	[rootNode setOwner:self];
+	NSSize contentSize = [self contentSize];	
+	outline=[[OutlineView alloc] initWithFrame:NSMakeRect(0, 0,contentSize.width, contentSize.height)];
+	[outline setHeaderView:nil];	
+	[outline setAutoresizingMask:(NSViewWidthSizable|NSViewHeightSizable)];
+	[outline setDataSource:self];
+	[outline setDelegate:self];
+	column=[[NSTableColumn alloc] init];
+	[outline addTableColumn:column];
+	[outline setOutlineTableColumn:column];
+	cell=[[NSBrowserCell alloc] init];
+	[cell setLeaf:YES];
+	[cell setScrollable:YES];
+	[column setDataCell:cell];		
+	[self setDocumentView:outline];
+	[outline sizeLastColumnToFit];
+	return self;
+}
+-(void)dealloc{
+	[outline autorelease];
+	[column autorelease];
+	[cell autorelease];
+	if (textstyle) {
+		[textstyle release];
+	}
+	[super dealloc];
+}
+-(void)refresh{
+	[rootNode updateWidth];
+	[outline reloadData];
+}
+-(int)outlineView:(NSOutlineView*)outlineView numberOfChildrenOfItem:(id)item{
+	if( !item ) item=rootNode;
+	return [[item kids] count];
+}
+-(id)outlineView:(NSOutlineView*)outlineView child:(int)index ofItem:(id)item{
+	if( !item ) item=rootNode;
+	if (index>=[[item kids] count]) return 0;
+	return [[item kids] objectAtIndex:index];
+}
+-(BOOL)outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item{
+	if( !item ) item=rootNode;
+	return [item canExpand];
+}
+-(id)outlineView:(NSOutlineView*)outlineView objectValueForTableColumn:(NSTableColumn*)tableColumn byItem:(id)item{
+	if (tableColumn==colin) return @"";	
+	if( !item ) item=rootNode;
+	return [item value];
+}
+-(unsigned)count{
+	return [rootNode count];
+}
+-(id)rootNode{
+	return rootNode;
+}
+-(id)selectedNode{
+	int		index;
+	index=[outline selectedRow];
+	if (index==-1) return nil;
+	return [outline itemAtRow:index];
+}
+-(void)selectNode:(id)node{
+	int index;
+	[node show];
+	[outline setDelegate:nil];
+	index = [outline rowForItem:node];
+	[outline selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO];
+	[outline setDelegate:self];
+	[outline scrollRowToVisible:index];	
+}
+-(void)expandNode:(id)node{
+	[outline setDelegate:nil];
+	[outline expandItem:node];
+	[outline tile];
+	[outline setDelegate:self];
+	[node queueWidthUpdate];
+}
+-(void)collapseNode:(id)node{
+	[outline setDelegate:nil];
+	[outline collapseItem:node];
+	[outline tile];
+	[outline setDelegate:self];
+	[column setMinWidth:0];
+	[rootNode queueWidthUpdate];
+}
+-(void)outlineViewItemDidExpand:(NSNotification *)notification{
+	id		node;
+	node=[[notification userInfo] objectForKey:@"NSObject"];
+	[node queueWidthUpdate];
+#ifdef __x86_64
+	PostGuiEvent( BBEVENT_GADGETOPEN,self,(BBInt64)node,0,0,0,0 );
+#else
+	PostGuiEvent( BBEVENT_GADGETOPEN,self,(int)node,0,0,0,0 );
+#endif
+}
+-(void)outlineViewItemDidCollapse:(NSNotification *)notification{
+	id		node;
+	node=[[notification userInfo] objectForKey:@"NSObject"];
+	[column setMinWidth:0];
+	[rootNode queueWidthUpdate];
+#ifdef __x86_64
+	PostGuiEvent( BBEVENT_GADGETCLOSE,self,(BBInt64)node,0,0,0,0 );
+#else
+	PostGuiEvent( BBEVENT_GADGETCLOSE,self,(int)node,0,0,0,0 );
+#endif
+}
+-(void)outlineViewSelectionDidChange:(NSNotification *)notification{
+	id		node;
+	node=[self selectedNode];
+#ifdef __x86_64
+	PostGuiEvent( BBEVENT_GADGETSELECT,self,(BBInt64)node,0,0,0,0 );
+#else
+	PostGuiEvent( BBEVENT_GADGETSELECT,self,(int)node,0,0,0,0 );
+#endif
+}
+-(BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item{
+#ifdef __x86_64
+	PostGuiEvent( BBEVENT_GADGETACTION,self,(BBInt64)item,0,0,0,0 );
+#else
+	PostGuiEvent( BBEVENT_GADGETACTION,self,(int)item,0,0,0,0 );
+#endif
+	return NO;
+}
+-(void)setColor:(NSColor*)color{
+	[outline setBackgroundColor:color];
+}
+-(void)setTextColor:(NSColor*)color{
+	if (textstyle) {[textstyle release];textstyle=nil;}
+	if (color){
+		textstyle=[NSDictionary dictionaryWithObjectsAndKeys:color,NSForegroundColorAttributeName,nil];
+		[textstyle retain];	
+	}
+}
+- (void)setFont:(NSFont*)font{
+	if (font) {
+		NSLayoutManager* layoutManager = [[[NSLayoutManager alloc] init] autorelease];
+		int i;
+		NSArray *columnsArray = [outline tableColumns];
+		for (i= 0; i < [columnsArray count]; i++)
+		[[[columnsArray objectAtIndex:i] dataCell] setFont:font];
+		[outline setRowHeight: [layoutManager defaultLineHeightForFont:font]+1];
+		[rootNode queueWidthUpdate];
+	}
+}
+- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)dcell forTableColumn:(NSTableColumn *)tableColumn item:(id)node{
+	if (textstyle){
+		NSAttributedString *atext=[[[NSAttributedString alloc] initWithString:[node value] attributes:textstyle] autorelease];
+		[dcell setAttributedStringValue:atext];
+	}
+	else{
+		[dcell setStringValue:[node value]];
+	}
+	[dcell setImage:[node icon]];
+}
+-(void)setEnabled:(BOOL)e{
+	[outline setEnabled:e];
+}
+-(BOOL)isEnabled{
+	return [outline isEnabled];
+}
+@end
+
+// NodeItem
+
+@implementation NodeItem
+-(void)dealloc{}
+-(id)initWithTitle:(NSString*)text{
+	owner=nil;
+	parent=nil;
+	title=text;
+	icon=nil;
+	[title retain];
+	kids=[[NSMutableArray alloc] initWithCapacity:10];
+	[kids retain];
+	return self;
+}
+-(void)updateWidth{
+	int 		i;
+	float       cellWidth;
+	float       indentationWidth;
+	
+	NSCell*	dcell;
+	NSArray*	columnsArray;
+	
+	if(owner==nil) return;
+	
+	NSOutlineView*	outline = owner->outline;
+	NSTableColumn*	tableColumn = owner->column;
+	
+	if(tableColumn!=nil){
+		dcell = [tableColumn dataCell];
+		[dcell setStringValue:title];
+		[dcell setImage:icon];
+		cellWidth = ((NSSize)[dcell cellSize]).width;
+		indentationWidth = [outline levelForItem: self];
+		if(isnan(indentationWidth)) indentationWidth = 0; else indentationWidth=([outline indentationPerLevel]*(indentationWidth+1));
+		if((owner->rootNode == self) || [outline isItemExpanded:self])
+			for (i= 0; i < [kids count]; i++) [[kids objectAtIndex:i] updateWidth];
+		if([tableColumn minWidth] < (cellWidth+indentationWidth)){
+			[tableColumn setMinWidth:(cellWidth+indentationWidth)];
+			[tableColumn setWidth:(cellWidth+indentationWidth)];
+		}
+	}
+}
+-(void)queueWidthUpdate{
+	[NSObject cancelPreviousPerformRequestsWithTarget: self selector:@selector(updateWidth) object:nil];
+	[self performSelector:@selector(updateWidth) withObject:nil afterDelay:0.0];
+}
+-(void)setOwner:(TreeView*)treeview{
+	owner=treeview;
+}
+-(id)getOwner{
+	return owner;
+}
+-(void)show{
+	if (parent){
+		[parent show];
+		[owner expandNode:parent];
+	}
+}
+-(void)attach:(NodeItem*)parent_ atIndex:(unsigned)index_{
+	parent=parent_;
+	if( parent ){
+		owner=parent->owner;
+		[[parent kids] insertObject:self atIndex:index_];
+		[self release];
+	}
+	if (owner) [owner refresh];
+}
+-(void)remove{
+	if( parent ) [[parent kids] removeObject:self];
+	if (owner) [owner refresh];
+}
+-(BOOL)canExpand{
+	return [kids count]>0;
+}
+-(NSMutableArray*)kids{
+	return kids;
+}
+-(NSString *)value{return title;}
+-(NSImage *)icon{return icon;}
+-(void)setTitle:(NSString*)text{
+	[title release];
+	title=text;
+	[title retain];
+	if (owner){
+		[owner->outline reloadItem:self];
+		[owner->rootNode queueWidthUpdate];
+	}
+}
+-(void)setIcon:(NSImage*)image{
+	if (icon) [icon release];
+	icon=image;
+	if (icon) [icon retain];
+	if (owner){
+		[owner->outline reloadItem:self];
+		[(icon ? self : owner->rootNode) queueWidthUpdate];
+	}
+}
+-(unsigned)count{
+	return [kids count];
+}
+@end
+
+// TextView
+
+@implementation TextView
+-(id)initWithFrame:(NSRect)rect{
+	
+	scroll=[[NSScrollView alloc] initWithFrame:rect];
+
+//	[scroll setVerticalScroller:[[Scroller alloc] init]];
+//	[scroll setHorizontalScroller:[[Scroller alloc] init]];
+
+	[scroll setHasVerticalScroller:YES];
+	[scroll setHasHorizontalScroller:YES];
+
+	[scroll setDrawsBackground:NO];
+	[scroll setRulersVisible:NO];
+	[scroll setBorderType:NSNoBorder];
+	[scroll setAutohidesScrollers:YES];
+				
+	NSSize contentSize = [scroll contentSize];	
+
+	self=[super initWithFrame:NSMakeRect(0, 0,contentSize.width,contentSize.height)];
+	[self setMinSize:NSMakeSize(contentSize.width, contentSize.height)];
+	[self setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
+	[self setVerticallyResizable:YES];
+	[self setHorizontallyResizable:YES];
+	[self setAutoresizingMask:(NSViewWidthSizable|NSViewHeightSizable)];
+	[[self textContainer] setContainerSize:NSMakeSize(FLT_MAX,FLT_MAX)];
+	[[self textContainer] setWidthTracksTextView:NO];	
+	[self setDelegate:self];
+	[self setUsesRuler:NO];
+
+	[scroll setDocumentView:self];
+
+	style=[[NSParagraphStyle defaultParagraphStyle] mutableCopy];
+	[style setLineBreakMode:NSLineBreakByClipping];
+	
+	styles=[NSMutableDictionary dictionaryWithObject:style forKey:NSParagraphStyleAttributeName];
+	[styles retain];
+	storage=[self textStorage];
+	[storage setDelegate:self];
+	
+	lockedNest=0;
+	
+	[self setTabs: 4];
+	if ([self respondsToSelector: @selector(setDefaultParagraphStyle)])
+		[self setDefaultParagraphStyle: style];
+	
+	if ([self respondsToSelector: @selector(setAutomaticLinkDetectionEnabled)])
+		[self setAutomaticLinkDetectionEnabled: NO];
+	if ([self respondsToSelector: @selector(setAutomaticQuoteSubstitutionEnabled)])
+		[self setAutomaticQuoteSubstitutionEnabled: NO];
+	if ([self respondsToSelector: @selector(setAutomaticSpellingCorrectionEnabled)])
+		[self setAutomaticSpellingCorrectionEnabled: NO];
+	if ([self respondsToSelector: @selector(setAutomaticTextReplacementEnabled)])
+		[self setAutomaticTextReplacementEnabled: NO];
+	if ([self respondsToSelector: @selector(setAutomaticDataDetectionEnabled)])
+		[self setAutomaticDataDetectionEnabled: NO];
+	
+	return self;
+}
+-(void)free{
+	[scroll setDocumentView:nil];
+	[scroll release];
+	[style release];
+	[styles release];
+	[storage release];
+}
+-(void)setHidden:(BOOL)flag{
+	[scroll setHidden:flag];
+}
+-(id)storage{
+	return storage;
+}
+-(NSSize)contentSize{
+	return [scroll contentSize];
+}
+-(id)getScroll{
+	return scroll;
+}
+-(void)setWordWrap:(BOOL)flag{
+	NSSize contentSize=[self contentSize];
+	if (flag){
+		[scroll setHasHorizontalScroller:NO];
+		[self setHorizontallyResizable:NO];
+		[self setAutoresizingMask:NSViewWidthSizable];
+		[[self textContainer] setContainerSize:NSMakeSize(contentSize.width, FLT_MAX)];
+		[[self textContainer] setWidthTracksTextView:YES];
+		[style setLineBreakMode:NSLineBreakByWordWrapping];
+	}
+	else{
+		[scroll setHasHorizontalScroller:YES];
+		[self setHorizontallyResizable:YES];
+		[self setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
+		[[self textContainer] setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)];
+		[[self textContainer] setWidthTracksTextView:NO];
+		[style setLineBreakMode:NSLineBreakByClipping];
+	}
+	[storage addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0,[storage length])];	
+}
+
+-(void)setTabs:(int)tabs{	
+	[style setTabStops:[NSArray array]];	//Clear any TabStops
+	[style setDefaultTabInterval: tabs];	//Set recurring TabStops remembering to convert from twips->pixels
+	[storage addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0,[storage length])];
+}
+
+-(void)setMargins:(int)leftmargin{
+
+	[self setTextContainerInset:NSMakeSize( leftmargin, 0) ];
+//	[style setFirstLineHeadIndent: leftmargin*8];
+//	[style setHeadIndent: leftmargin*8];
+//	[storage addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0,[storage length])];	
+}
+
+-(void)setText:(NSString*)text{
+	NSAttributedString	*astring;
+	astring=[[NSAttributedString alloc] initWithString:text attributes:styles];
+	if (lockedNest) [storage endEditing];
+	[storage setAttributedString:astring];
+	if (lockedNest) [storage beginEditing]; else [self setSelectedRange:NSMakeRange(0,0)];
+}
+-(void)addText:(NSString*)text{
+	NSAttributedString	*astring;
+	astring=[[NSAttributedString alloc] initWithString:text attributes:styles];
+	if (lockedNest) [storage endEditing];
+	[storage appendAttributedString:astring];
+	if (lockedNest) [storage beginEditing];
+}
+-(void)setScrollFrame:(NSRect)rect{
+	[scroll setFrame:rect];
+}
+-(void)setTextColor:(NSColor*)color{
+	[styles setObject:color forKey:NSForegroundColorAttributeName];
+	[storage addAttribute:NSForegroundColorAttributeName value:color range:NSMakeRange(0,[storage length])];
+	[self setInsertionPointColor:color];	
+}
+-(void)setColor:(NSColor*)color{
+	if(color){
+		[self setBackgroundColor:color];	
+		[self setDrawsBackground:true];
+		[scroll setBackgroundColor:color];
+		[scroll setDrawsBackground:true];
+	}else{
+		[self setDrawsBackground:false];
+		[scroll setDrawsBackground:false];
+	}
+}
+-(void)setFont:(NSFont*)font{
+	[styles setObject:font forKey:NSFontAttributeName];
+	[storage setFont:font];	
+	[super setFont:font];	
+}
+-(NSMenu *)menuForEvent:(NSEvent *)event{
+	NSPoint	p;
+	int		x,y;
+	p=[event locationInWindow];	
+	x=(int)p.x;y=(int)p.y;
+	PostGuiEvent( BBEVENT_GADGETMENU,self,0,0,x,y,0 );
+	return nil;
+}
+-(void)updateDragTypeRegistration{
+}
+-(NSArray *)acceptableDragTypes{
+	return nil;
+}
+-(void)textDidBeginEditing:(NSNotification*)n{
+//	printf( "textDidBeginEditing:%p\n",_textEditor );fflush(stdout);
+}
+-(void)textDidChange:(NSNotification*)n{
+	PostGuiEvent( BBEVENT_GADGETACTION,self,0,0,0,0,0 );
+}
+-(void)textDidEndEditing:(NSNotification*)n{
+//	printf( "textDidEndEditing:%p\n",_textEditor );fflush(stdout);
+	PostGuiEvent( BBEVENT_GADGETLOSTFOCUS,[n object],0,0,0,0,0 );
+}
+-(void)textViewDidChangeSelection:(NSNotification *)aNotification{
+	PostGuiEvent( BBEVENT_GADGETSELECT,self,0,0,0,0,0 );
+}
+-(void)textStorageDidProcessEditing:(NSNotification *)aNotification{
+
+}
+-(void)textStorageWillProcessEditing:(NSNotification *)aNotification{
+	[storage removeAttribute:NSLinkAttributeName range:[storage editedRange]];
+}
+@end
+
+
+// TabViewItem
+
+@class TabViewItem;
+@interface TabViewItem:NSTabViewItem{
+	NSImage	*_image;
+}
+-(id)initWithIdentifier:(NSString *)text;
+-(void)setImage:(NSImage*)image;
+-(id)copyWithZone:(NSZone *)zone;
+-(NSImage*)image;
+-(NSSize)sizeOfLabel:(BOOL)shouldTruncateLabel;
+-(void)drawLabel:(BOOL)shouldTruncateLabel inRect:(NSRect)tabRect;
+@end
+@implementation TabViewItem
+-(id)initWithIdentifier:(NSString *)string{
+	self=[super initWithIdentifier:string];
+	_image=nil;
+	return self;
+}
+-(void)setImage:(NSImage*)image{
+	_image=image;
+	if (_image) [_image setScalesWhenResized:YES];
+}
+-(id)copyWithZone:(NSZone *)zone{
+	TabViewItem *copy=[[[self class] allocWithZone:zone] initWithIdentifier:[self identifier]];
+	return copy;
+}
+-(NSImage*)image{
+	return _image;
+}
+-(NSSize)sizeOfLabel:(BOOL)shouldTruncateLabel{
+	NSSize	size;
+	NSSize	imageDimensions;
+	float		ratio;
+	size=[super sizeOfLabel:shouldTruncateLabel];
+	
+	if (_image) {
+		imageDimensions = [_image size];
+		if (imageDimensions.height > size.height){
+			ratio = size.height/imageDimensions.height;
+			imageDimensions.width*=ratio;imageDimensions.height*=ratio;
+			[_image setSize: imageDimensions];
+		}
+		size.width += imageDimensions.height;
+	}
+	return size;
+}
+-(void)drawLabel:(BOOL)shouldTruncateLabel inRect:(NSRect)content{
+	NSSize	imageDimensions;
+	NSPoint	point;
+	if (_image){
+		imageDimensions = [_image size];
+		point = NSMakePoint(content.origin.x,content.origin.y+imageDimensions.height);
+		[_image compositeToPoint:point operation:NSCompositeSourceOver];
+		content.origin.x+=imageDimensions.width;content.size.width-=imageDimensions.width;		
+	}
+	[super drawLabel:shouldTruncateLabel inRect:content];
+}
+@end
+
+// TabView
+
+@implementation TabView
+-(id)initWithFrame:(NSRect)rect{
+	rect.size.height+=8;
+	self=[super initWithFrame:rect];
+	[super setControlSize:NSSmallControlSize];
+	[super setFont:[NSFont labelFontOfSize:[NSFont smallSystemFontSize]]];	
+	client=[[FlippedView alloc] initWithFrame:[self contentRect]];
+	[client setAutoresizingMask:(NSViewWidthSizable|NSViewHeightSizable)];	
+	[client retain];
+	user=1;	
+	[self setDelegate:self];
+	return self;
+}
+-(id)clientView{
+	return client;
+}
+-(void)selectTabViewItemAtIndex:(int)index{
+	user=0;
+	[super selectTabViewItemAtIndex:index];
+	user=1;
+} 
+-(void)setFrame:(NSRect)rect{
+	rect.size.height+=8;
+	[super setFrame:rect];
+}
+-(BOOL)tabView:(NSTabView *)tabView shouldSelectTabViewItem:(NSTabViewItem *)tabViewItem{
+	int		index;
+	[tabViewItem setView:client];
+	[client setFrame:[self contentRect]];
+	if (user){
+		index=[self indexOfTabViewItem:tabViewItem];
+		PostGuiEvent( BBEVENT_GADGETACTION,self,index,0,0,0,0);
+	}
+	return YES;
+}
+-(void)dealloc{
+	NSArray			*items;
+	int				i,n;
+	
+	items=[self tabViewItems];
+	n=[items count];
+	for (i=0;i<n;i++) [self removeTabViewItem:[items objectAtIndex:0]];
+
+	[client release];
+	[super dealloc];
+}
+-(NSMenu *)menuForEvent:(NSEvent *)event{
+	int	index;
+	NSTabViewItem*	tabItem;
+	tabItem = [self tabViewItemAtPoint:[self convertPoint:[event locationInWindow] fromView:nil]];
+	if (tabItem) index = [self indexOfTabViewItem:tabItem]; else index = -1;
+	PostGuiEvent( BBEVENT_GADGETMENU,self,index,0,0,0,0);
+	return [super menuForEvent:event];
+}
+@end
+
+// WindowView
+
+@implementation WindowView
+-(id)textFirstResponder{
+	id r=[self firstResponder];
+	//if ([r isKindOfClass:[PanelView class]]) return r;
+	if ([r isKindOfClass:[NSTextView class]]){
+		id d=[r delegate];
+		if( [d isKindOfClass:[NSTextField class]] ) return d;
+	}
+	return r;
+}
+-(id)initWithContentRect:(NSRect)rect styleMask:(unsigned int)mask backing:(NSBackingStoreType)backing defer:(BOOL)flag withGadget:(nsgadget*)_gadget{
+//withStatus:(BOOL)status{
+	id		client;
+	int		i;
+	NSText	*l;
+	NSBox	*box;
+	dragging = nil;
+	self=[super initWithContentRect:rect styleMask:mask backing:backing defer:flag];
+	gadget=_gadget;
+	view=[[FlippedView alloc] init];
+	enabled=true;
+	[self setContentView:view];
+	[self setAcceptsMouseMovedEvents:YES];
+	[self disableCursorRects];	//Fixes NSSetPointer not sticking.
+	if (gadget->style&WINDOW_STATUS){
+		rect.origin.x=rect.origin.y=0;
+		rect.size.height-=STATUSBARHEIGHT;
+		client=[[FlippedView alloc] initWithFrame:rect];
+		[client setAutoresizingMask:(NSViewWidthSizable|NSViewHeightSizable)];	
+		[view addSubview:client];
+// label for window status
+		rect.origin.y=rect.size.height+3;
+		rect.size.height=STATUSBARHEIGHT-4;		
+		rect.size.width-=[NSScroller scrollerWidth];
+		for (i=0;i<3;i++){
+			l=[[NSText alloc] initWithFrame:rect];
+			[l setDrawsBackground:NO];
+			[l setEditable:NO];
+			[l setSelectable:NO];
+			[l setAutoresizingMask:NSViewWidthSizable|NSViewMinYMargin];
+			switch (i){
+				case 0:[l setAlignment:NSLeftTextAlignment];break;
+				case 1:[l setAlignment:NSCenterTextAlignment];break;
+				case 2:[l setAlignment:NSRightTextAlignment];break;
+			}
+			if (view) [view addSubview:l];
+			label[i]=l;
+		}
+		
+		rect.origin.y-=3;
+		rect.size.height=2;
+		rect.size.width+=[NSScroller scrollerWidth];
+		
+		box=[[NSBox alloc] initWithFrame:rect];
+		[box setBoxType:NSBoxSeparator];
+		[box setTitlePosition:NSNoTitle];
+		[box setAutoresizingMask:NSViewWidthSizable|NSViewMinYMargin];
+		if (view) [view addSubview:box];
+		
+// set clientview to inner view
+		view=client;		
+	}
+	return self;
+}
+-(id)clientView{
+	return view;
+}
+-(void)setStatus:(NSString*)text align:(int)pos{
+	if (label[pos]) [label[pos] setString:text];
+}
+-(void)sendEvent:(NSEvent*)event{
+	
+	static int lastHotKey;
+	int key;
+	id source;
+	
+	// Handling of Generic Key/Mouse Events
+	
+	switch( [event type] ){
+	case NSMouseEntered:
+		[self disableCursorRects];
+	case NSLeftMouseDown:
+	case NSRightMouseDown:
+	case NSOtherMouseDown:
+		if( [event type] != NSMouseEntered ){
+			dragging = [[self contentView] hitTest:[event locationInWindow]];
+			[self makeFirstResponder:dragging];
+		}
+	case NSMouseMoved:
+	case NSMouseExited:
+	case NSScrollWheel:
+	{
+		NSView *hitView = [[self contentView] hitTest:[event locationInWindow]];
+		if (hitView) EmitMouseEvent( event, hitView );
+		if(![self isEnabled]) return;
+		break;
+	}
+	case NSLeftMouseUp:
+	case NSRightMouseUp:
+	case NSOtherMouseUp:
+	{
+		//fire event for the dragged view
+		if (dragging) {
+			EmitMouseEvent( event, dragging );
+			dragging = nil;
+		} else {
+			//fire the event for the recieving view (if it exists)
+			NSView *hitView = [[self contentView] hitTest:[event locationInWindow]];
+			if (hitView) EmitMouseEvent( event, hitView );
+		}
+		
+		if(![self isEnabled]) return;
+		break;
+	}
+	case NSLeftMouseDragged:
+	case NSRightMouseDragged:
+	case NSOtherMouseDragged:
+	{
+		if( dragging == nil ) dragging = [[self contentView] hitTest:[event locationInWindow]];
+		if( dragging ) EmitMouseEvent( event, dragging );
+		if(![self isEnabled]) return;
+		break;
+	}
+	case NSKeyDown:
+	case NSKeyUp:
+	case NSFlagsChanged:
+	{
+		NSResponder *handle=(NSResponder*)NSActiveGadget();
+		if( handle && EmitKeyEvent( event, handle )) return;
+		break;
+	}
+	}
+	
+	// End of Generic Key/Mouse Events
+	
+	// Gadget Filterkey Processing
+	
+	switch( [event type] ){
+	case NSKeyDown:
+		if( key=bbSystemTranslateKey( [event keyCode] ) ){
+			int mods=bbSystemTranslateMods( [event modifierFlags] );
+			BBObject *event=maxgui_maxgui_HotKeyEvent( key,mods );
+			if( event!=&bbNullObject ){
+				lastHotKey=key;
+				brl_event_EmitEvent( event );
+				return;
+			}
+		}
+		source=[self textFirstResponder];
+		if( source && !filterKeyDownEvent( event,source ) ) return;		
+		if(![self isEnabled]) return;
+		break;
+	case NSKeyUp:
+		key=bbSystemTranslateKey([event keyCode]);
+		if( lastHotKey && (key==lastHotKey ) ){
+			lastHotKey=0;
+			return;
+		}
+		if(![self isEnabled]) return;
+		break;
+	}
+	lastHotKey=0;
+	
+	// End of FilterKey Processing
+	
+	[super sendEvent:event];
+}
+- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender{
+//	printf("windowview got dragenter\n");fflush(stdout);
+	return YES;
+}
+- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender{
+	NSPasteboard *pboard = [sender draggingPasteboard];
+	if ( [[pboard types] containsObject:NSFilenamesPboardType] ) {
+		NSArray *files = [pboard propertyListForType:NSFilenamesPboardType];
+		int numberOfFiles = [files count];
+		// Perform operation using the list of files
+		// printf("windowview got drag\n");fflush(stdout);
+		int i;
+		for (i=0;i<numberOfFiles;i++)
+		{
+			BBString *name=bbStringFromNSString([files objectAtIndex:i]);
+			maxgui_cocoamaxgui_cocoagui_PostCocoaGuiEvent( BBEVENT_WINDOWACCEPT,self,0,0,0,0,(BBObject*)name );
+		}
+		
+	}
+	return YES;
+}
+-(void)didResize{
+	NSRect rect=[self localRect];
+	[self didMove];
+	PostGuiEvent( BBEVENT_WINDOWSIZE,self,0,0,rect.size.width,rect.size.height,0 );
+}
+-(void)didMove{
+	NSRect rect=[self localRect];
+	PostGuiEvent( BBEVENT_WINDOWMOVE,self,0,0,rect.origin.x,rect.origin.y,0 );		
+}
+-(void)zoom{
+	zooming = 1;
+}
+-(NSRect)localRect{
+	NSRect rect,vis;
+	int style;
+
+	rect=[self frame];
+	style=gadget->style;
+	if (style&WINDOW_CLIENTCOORDS){
+		rect=[self contentRectForFrameRect:rect];
+		if (style&WINDOW_STATUS) {
+			rect.size.height-=STATUSBARHEIGHT;		
+			rect.origin.y+=STATUSBARHEIGHT;		
+		}
+	}
+	vis=[[NSScreen deepestScreen] visibleFrame];
+	rect.origin.x-=vis.origin.x;
+	rect.origin.y=vis.size.height-(rect.origin.y-vis.origin.y)-rect.size.height;	
+	return rect;
+}
+-(BOOL)canBecomeKeyWindow{
+	return ([self isEnabled]);
+}
+-(BOOL)canBecomeMainWindow{
+	return ([self isEnabled] && [self isVisible] && ([self parentWindow]==nil));
+}
+-(BOOL)becomeFirstResponder{
+	return ([self isEnabled] && [self isVisible]);
+}
+-(void)setEnabled:(BOOL)e{
+	enabled=e;
+	if (enabled) [self makeKeyWindow];
+}
+-(BOOL)isEnabled{
+	return (enabled)?YES:NO;
+}
+-(void)dealloc{
+	int i;
+	id sview;
+	if (gadget->style&WINDOW_STATUS) {
+		for (i = 0; i < 3; i++) {
+			if (label[i]) {
+				[label[i] removeFromSuperview];
+				[label[i] release];
+			}
+		}
+		
+		sview = [view superview];
+		[view removeFromSuperview];
+		[view release];
+
+		[sview removeFromSuperview];
+		[sview release];
+	} else {
+		[view removeFromSuperview];
+		[view release];
+	}
+
+	[super dealloc];
+}
+@end
+
+// ToolView
+
+@implementation ToolView
+-(id)textFirstResponder{
+	id r=[self firstResponder];
+	//if ([r isKindOfClass:[PanelView class]]) return r;
+	if ([r isKindOfClass:[NSTextView class]]){
+		id d=[r delegate];
+		if( [d isKindOfClass:[NSTextField class]] ) return d;
+	}
+	return r;
+}
+-(id)initWithContentRect:(NSRect)rect styleMask:(unsigned int)mask backing:(NSBackingStoreType)backing defer:(BOOL)flag withGadget:(nsgadget*)_gadget{
+//withStatus:(BOOL)status{
+	id		client;
+	int		i;
+	NSText	*l;
+	NSBox	*box;
+	dragging = nil;
+	self=[super initWithContentRect:rect styleMask:mask backing:backing defer:flag];
+	gadget=_gadget;
+	view=[[FlippedView alloc] init];
+	enabled=true;
+	[self setContentView:view];
+	[self setAcceptsMouseMovedEvents:YES];
+	[self disableCursorRects];	//Fixes NSSetPointer not sticking.
+	if (gadget->style&WINDOW_STATUS){			//status){	//mask&NSTexturedBackgroundWindowMask)
+		rect.origin.x=rect.origin.y=0;
+		rect.size.height-=STATUSBARHEIGHT;
+		client=[[FlippedView alloc] initWithFrame:rect];
+		[client setAutoresizingMask:(NSViewWidthSizable|NSViewHeightSizable)];	
+		[view addSubview:client];
+// label for window status
+		rect.origin.y=rect.size.height+3;
+		rect.size.height=STATUSBARHEIGHT-4;		
+		rect.size.width-=[NSScroller scrollerWidth];
+		for (i=0;i<3;i++){
+			l=[[NSText alloc] initWithFrame:rect];
+			[l setDrawsBackground:NO];
+			[l setEditable:NO];
+			[l setSelectable:NO];
+			[l setAutoresizingMask:NSViewWidthSizable|NSViewMinYMargin];
+			switch (i){
+				case 0:[l setAlignment:NSLeftTextAlignment];break;
+				case 1:[l setAlignment:NSCenterTextAlignment];break;
+				case 2:[l setAlignment:NSRightTextAlignment];break;
+			}
+			if (view) [view addSubview:l];
+			label[i]=l;
+		}
+		
+		rect.origin.y-=3;
+		rect.size.height=2;
+		rect.size.width+=[NSScroller scrollerWidth];
+		
+		box=[[NSBox alloc] initWithFrame:rect];
+		[box setBoxType:NSBoxSeparator];
+		[box setTitlePosition:NSNoTitle];
+		[box setAutoresizingMask:NSViewWidthSizable|NSViewMinYMargin];
+		if (view) [view addSubview:box];
+		
+// set clientview to inner view
+		view=client;		
+	}
+	if ([self respondsToSelector: @selector(setShowsToolbarButton)]) [self setShowsToolbarButton: NO];
+	return self;
+}
+-(id)clientView{
+	return view;
+}
+-(void)setStatus:(NSString*)text align:(int)pos{
+	if (label[pos]) [label[pos] setString:text];
+}
+-(void)sendEvent:(NSEvent*)event{
+	
+	static int lastHotKey;
+	int key;
+	id source;
+	
+	// Handling of Generic Key/Mouse Events
+	
+	switch( [event type] ){
+	case NSMouseEntered:
+		[self disableCursorRects];
+	case NSLeftMouseDown:
+	case NSRightMouseDown:
+	case NSOtherMouseDown:
+	{
+		if( [event type] != NSMouseEntered ){
+			dragging = [[self contentView] hitTest:[event locationInWindow]];
+			[self makeFirstResponder:dragging];
+		}
+	}
+	case NSMouseMoved:
+	case NSMouseExited:
+	case NSScrollWheel:
+	{
+		NSView *hitView = [[self contentView] hitTest:[event locationInWindow]];
+		if (hitView) EmitMouseEvent( event, hitView );
+		if(![self isEnabled]) return;
+		break;
+	}
+	case NSLeftMouseUp:
+	case NSRightMouseUp:
+	case NSOtherMouseUp:
+	{
+		//fire event for the dragged view
+		if (dragging) {
+			EmitMouseEvent( event, dragging );
+			dragging = nil;
+		} else {
+			//fire the event for the recieving view (if it exists)
+			NSView *hitView = [[self contentView] hitTest:[event locationInWindow]];
+			if (hitView) EmitMouseEvent( event, hitView );
+		}
+		
+		if(![self isEnabled]) return;
+		break;
+	}
+	case NSLeftMouseDragged:
+	case NSRightMouseDragged:
+	case NSOtherMouseDragged:
+	{
+		if( dragging == nil ) dragging = [[self contentView] hitTest:[event locationInWindow]];
+		if( dragging ) EmitMouseEvent( event, dragging );
+		if(![self isEnabled]) return;
+		break;
+	}
+	case NSKeyDown:
+	case NSKeyUp:
+	case NSFlagsChanged:
+	{
+		NSResponder *handle=(NSResponder*)NSActiveGadget();
+		if( handle && EmitKeyEvent( event, handle )) return;
+		break;
+	}
+	}
+	
+	// End of Generic Key/Mouse Events
+	
+	// Gadget Filterkey Processing
+	
+	switch( [event type] ){
+	case NSKeyDown:
+		if( key=bbSystemTranslateKey( [event keyCode] ) ){
+			int mods=bbSystemTranslateMods( [event modifierFlags] );
+			BBObject *event=maxgui_maxgui_HotKeyEvent( key,mods );
+			if( event!=&bbNullObject ){
+				lastHotKey=key;
+				brl_event_EmitEvent( event );
+				return;
+			}
+		}
+		source=[self textFirstResponder];
+		if( source && !filterKeyDownEvent( event,source ) ) return;		
+		if(![self isEnabled]) return;
+		break;
+	case NSKeyUp:
+		key=bbSystemTranslateKey([event keyCode]);
+		if( lastHotKey && (key==lastHotKey ) ){
+			lastHotKey=0;
+			return;
+		}
+		if(![self isEnabled]) return;
+		break;
+	}
+	lastHotKey=0;
+	
+	// End of FilterKey Processing
+	
+	[super sendEvent:event];
+}
+- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender{
+//	printf("windowview got dragenter\n");fflush(stdout);
+	return YES;
+}
+- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender{
+	NSPasteboard *pboard = [sender draggingPasteboard];
+	if ( [[pboard types] containsObject:NSFilenamesPboardType] ) {
+		NSArray *files = [pboard propertyListForType:NSFilenamesPboardType];
+		int numberOfFiles = [files count];
+		// Perform operation using the list of files
+		// printf("windowview got drag\n");fflush(stdout);
+		int i;
+		for (i=0;i<numberOfFiles;i++)
+		{
+			BBString *name=bbStringFromNSString([files objectAtIndex:i]);
+			maxgui_cocoamaxgui_cocoagui_PostCocoaGuiEvent( BBEVENT_WINDOWACCEPT,self,0,0,0,0,(BBObject*)name );
+		}
+		
+	}
+	return YES;
+}
+-(void)didResize{
+	if (zooming) {
+		zooming = 0;
+		[self didMove];
+	}
+	NSRect rect=[self localRect];
+	PostGuiEvent( BBEVENT_WINDOWSIZE,self,0,0,rect.size.width,rect.size.height,0 );
+}
+-(void)didMove{
+	NSRect rect=[self localRect];
+	PostGuiEvent( BBEVENT_WINDOWMOVE,self,0,0,rect.origin.x,rect.origin.y,0 );		
+}
+-(void)zoom{
+	zooming = 1;
+}
+-(NSRect)localRect{
+	NSRect rect,vis;
+	int style;
+
+	rect=[self frame];
+	style=gadget->style;
+	if (style&WINDOW_CLIENTCOORDS){
+		rect=[self contentRectForFrameRect:rect];
+		if (style&WINDOW_STATUS) {
+			rect.size.height-=STATUSBARHEIGHT;		
+			rect.origin.y+=STATUSBARHEIGHT;		
+		}
+	}
+	vis=[[NSScreen deepestScreen] visibleFrame];
+	rect.origin.x=rect.origin.x-vis.origin.x;
+	rect.origin.y=vis.size.height-(rect.origin.y-vis.origin.y)-rect.size.height;	
+	return rect;
+}
+-(BOOL)canBecomeKeyWindow{
+	return ([self isEnabled]);
+}
+-(BOOL)canBecomeMainWindow{
+	return ([self isEnabled] && [self isVisible] && ([self parentWindow]==nil));
+}
+-(BOOL)becomeFirstResponder{
+	return ([self isEnabled] && [self isVisible]);
+}
+-(void)setEnabled:(BOOL)e{
+	enabled=e;
+	if (enabled) [self makeKeyWindow];
+}
+-(BOOL)isEnabled{
+	return (enabled)?YES:NO;
+}
+-(void)dealloc{
+	int i;
+	id sview;
+	if (gadget->style&WINDOW_STATUS) {
+		for (i = 0; i < 3; i++) {
+			if (label[i]) {
+				[label[i] removeFromSuperview];
+				[label[i] release];
+			}
+		}
+		
+		sview = [view superview];
+		[view removeFromSuperview];
+		[view release];
+
+		[sview removeFromSuperview];
+		[sview release];
+	} else {
+		[view removeFromSuperview];
+		[view release];
+	}
+
+	[super dealloc];
+}
+@end
+
+// global app stuff
+
+void NSBegin(){
+	GlobalApp=[[CocoaApp alloc] init];
+	HaltMouseEvents=0;
+}
+
+void NSEnd(){
+	[GlobalApp release];
+}
+
+int NSActiveGadget(){
+	NSWindow	*window;
+	NSResponder *responder;
+	window=[NSApp keyWindow];
+	if (!window) return 0;
+	responder=[window firstResponder];
+	if (!responder) return (int)window;
+	if ([responder isKindOfClass:[NSTextView class]] && 
+   		[window fieldEditor:NO forObject:nil] != nil ) { 
+			NSTextView *view=(NSTextView*)responder;
+			return (int)[view delegate];
+		}
+	return (int)responder;
+}
+
+void NSInitGadget(nsgadget *gadget){
+	NSRect 				rect,vis;
+	NSString 			*text;
+	NSView				*view;
+	NSWindow		*window;
+	NSButton			*button;
+	NSTextField			*textfield;
+	TextView			*textarea;
+	NSControl 		*combobox;
+	Toolbar			*toolbar;
+	TabView				*tabber;
+	TreeView			*treeview;
+	HTMLView			*htmlview;
+	PanelView			*panel;
+	PanelViewContent		*pnlcontent;
+	CanvasView			*canvas;
+	ListView				*listbox;
+	NSText				*label;
+	NSBox				*box;
+	NSSlider				*slider;
+	NSScroller			*scroller;
+	NSStepper				*stepper;
+	NSProgressIndicator	*progbar;
+	NSMenu				*menu;
+	NSMenuItem			*menuitem;
+	NodeItem			*node,*parent;
+	nsgadget				*group;
+	int 					style,flags;
+	NSImage			*image;
+		
+	rect=NSMakeRect(gadget->x,gadget->y,gadget->w,gadget->h);
+	text=NSStringFromBBString(gadget->textarg);
+	style=gadget->style;flags=0;
+	group=gadget->group;
+	if (group==(nsgadget*)&bbNullObject) group=0;
+	if (group) view=gadget->group->view;
+	
+	switch (gadget->internalclass){
+	case GADGET_DESKTOP:
+		rect=[[NSScreen deepestScreen] frame];
+		gadget->x=rect.origin.x;
+		gadget->y=rect.origin.y;
+		gadget->w=rect.size.width;
+		gadget->h=rect.size.height;
+		break;
+	case GADGET_WINDOW:
+		vis=[[NSScreen deepestScreen] visibleFrame];
+		rect.origin.x+=vis.origin.x;
+		rect.origin.y=vis.origin.y+vis.size.height-rect.origin.y-rect.size.height;
+		if (style&WINDOW_TITLEBAR) flags|=NSTitledWindowMask|NSClosableWindowMask;
+		if (style&WINDOW_RESIZABLE){
+			flags|=NSResizableWindowMask;
+			if (!(group && (group->internalclass==GADGET_WINDOW))) flags |=NSMiniaturizableWindowMask;
+		}
+		if (style&WINDOW_TOOL) flags|=NSUtilityWindowMask;
+		[NSApp activateIgnoringOtherApps:YES];
+		if (!(style&WINDOW_CLIENTCOORDS)){
+			rect=[NSWindow contentRectForFrameRect:rect styleMask:flags];
+		}else{
+			if (style&WINDOW_STATUS) {
+				rect.origin.y-=STATUSBARHEIGHT;		
+				rect.size.height+=STATUSBARHEIGHT;		
+			}
+		}
+		if (!(style&WINDOW_TOOL)) {
+			window=[[WindowView alloc] initWithContentRect:rect styleMask:flags backing:NSBackingStoreBuffered defer:YES withGadget:gadget];
+		} else {
+			window=[[ToolView alloc] initWithContentRect:rect styleMask:flags backing:NSBackingStoreBuffered defer:YES withGadget:gadget];
+		}
+		[window setOpaque:NO];
+		[window setAlphaValue:.999f];	
+		
+		if (style&WINDOW_HIDDEN) [window orderOut:window]; else [window makeKeyAndOrderFront:NSApp];
+		
+		if (group && (group->internalclass==GADGET_WINDOW)){
+			NSWindow	*parent;
+			parent=(NSWindow*)group->handle;
+			if(!(style&WINDOW_HIDDEN)) [parent addChildWindow:window ordered:NSWindowAbove];
+			[window setParentWindow:parent];
+		}
+		
+		if (style&WINDOW_ACCEPTFILES)
+			[window registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]]; 
+		
+		[window setTitle:text];	
+		[window setDelegate:GlobalApp];
+		gadget->handle=window;
+		gadget->view=[window clientView];
+		break;
+		
+	case GADGET_BUTTON:
+		button=[[NSButton alloc] initWithFrame:rect];
+		[button setTitle:text];
+		
+		[button setBezelStyle:NSRoundedBezelStyle];
+		
+		switch (style&7){
+			case 0:
+				// Push Button Size Hack
+				if (gadget->h > 30) {
+					[button setBezelStyle:NSRegularSquareBezelStyle];
+				} else {
+					if (gadget->h < 24) [button setBezelStyle:NSShadowlessSquareBezelStyle];
+					else [button setBezelStyle:NSRoundedBezelStyle];
+				}
+				break;
+			case BUTTON_CHECKBOX:
+				if (style&BUTTON_PUSH){
+					[button setBezelStyle:NSShadowlessSquareBezelStyle];
+					[button setButtonType:NSPushOnPushOffButton];
+				} else {
+					[button setButtonType:NSSwitchButton];
+				}
+				break;
+			case BUTTON_RADIO:
+				if (style&BUTTON_PUSH){
+					[button setBezelStyle:NSShadowlessSquareBezelStyle];
+					[button setButtonType:NSPushOnPushOffButton];
+				} else {
+					[button setButtonType:NSRadioButton];
+				}
+				break;
+			case BUTTON_OK:
+				[button setKeyEquivalent:@"\r"];
+				break;
+			case BUTTON_CANCEL:
+				[button setKeyEquivalent:@"\x1b"];
+				break;
+		}
+		[button setTarget:GlobalApp];
+		[button setAction:@selector(buttonPush:)];
+		if (view) [view addSubview:button];		
+		gadget->handle=button;
+		gadget->view=button;
+		break;
+	case GADGET_PANEL:
+		panel=[[PanelView alloc] initWithFrame:rect];
+		[panel setContentViewMargins:NSMakeSize(0.0,0.0)];
+		pnlcontent=[[PanelViewContent alloc] initWithFrame:[[panel contentView] frame]];
+		[pnlcontent setAutoresizesSubviews:NO];
+		[panel setContentView:pnlcontent];
+		[panel setGadget:gadget];
+		[panel setStyle:style];
+		[panel setEnabled:true];
+		[panel setTitle:text];
+		[pnlcontent setAlpha:1.0];
+		if (view) [view addSubview:panel];
+		gadget->view=pnlcontent;
+		gadget->handle=panel;
+		break;
+	case GADGET_CANVAS:
+		canvas=[[CanvasView alloc] initWithFrame:rect];
+		[canvas setAutoresizesSubviews:NO];
+		[canvas setGadget:gadget];
+		if (view) [view addSubview:canvas];
+		[canvas setStyle:style|PANEL_ACTIVE];
+		[canvas setEnabled:true];
+		gadget->view=[canvas contentView];
+		gadget->handle=canvas;
+		break;	
+	case GADGET_TEXTFIELD:
+		if (style==TEXTFIELD_PASSWORD){
+			textfield=[[NSSecureTextField alloc] initWithFrame:rect];
+		}else{
+			textfield=[[NSTextField alloc] initWithFrame:rect];
+		}
+		[textfield setDelegate:GlobalApp];
+		[textfield setEditable:YES];
+		[[textfield cell] setWraps:NO];
+		[[textfield cell] setScrollable:YES];
+		if (view) [view addSubview:textfield];		
+		gadget->handle=textfield;
+		gadget->view=textfield;
+		break;
+	case GADGET_TEXTAREA://http://developer.apple.com/documentation/Cocoa/Conceptual/TextUILayer/Tasks/TextInScrollView.html
+		textarea=[[TextView alloc] initWithFrame:rect];
+		if (style&TEXTAREA_READONLY) [textarea setEditable:NO];
+		if (style&TEXTAREA_WORDWRAP) [textarea setWordWrap:YES];
+		if (view) [view addSubview:[textarea getScroll]];
+		gadget->handle=textarea;
+		gadget->view=[textarea getScroll];// simon was here textarea;
+		break;		
+	case GADGET_COMBOBOX:
+		if (rect.size.height > 26) rect.size.height = 26;
+		combobox=[[NSComboBox alloc] initWithFrame:rect];
+		[combobox setUsesDataSource:NO];
+		[combobox setCompletes:YES];
+		[combobox setDelegate:GlobalApp];		
+		[combobox setEditable:(style&COMBOBOX_EDITABLE)?YES:NO];			
+		[combobox setSelectable:YES];			
+		if (view) [view addSubview:combobox];		
+		gadget->handle=combobox;
+		gadget->view=combobox;
+		break;
+	case GADGET_LISTBOX:
+		listbox=[[ListView alloc] initWithFrame:rect];
+		if (view) [view addSubview:listbox];		
+		gadget->handle=listbox;
+		gadget->view=listbox;
+		break;
+	case GADGET_TOOLBAR:
+		toolbar=[[Toolbar alloc] initWithIdentifier:text];
+		[toolbar setSizeMode:NSToolbarSizeModeSmall];
+		[toolbar setDisplayMode:NSToolbarDisplayModeIconOnly];
+		[toolbar setDelegate:GlobalApp];
+		window=(WindowView*)group->handle;
+		[window setToolbar:toolbar];
+		gadget->handle=toolbar;
+		gadget->view=[window clientView];
+		break;
+	case GADGET_TABBER:
+		tabber=[[TabView alloc] initWithFrame:rect];
+		[tabber setAutoresizesSubviews:NO];
+		if (view) [view addSubview:tabber];		//[tabber hostView]];		
+		gadget->handle=tabber;
+		gadget->view=[tabber clientView];
+		break;
+	case GADGET_TREEVIEW:
+		treeview=[[TreeView alloc] initWithFrame:rect];	//NSOutlineView
+		if (view) [view addSubview:treeview];		
+		gadget->handle=treeview;
+		gadget->view=treeview;
+		break;
+	case GADGET_HTMLVIEW:
+		htmlview=[[HTMLView alloc] initWithFrame:rect];
+		if (view) [view addSubview:htmlview];
+		[htmlview setStyle: style];
+		gadget->handle=htmlview;
+		gadget->view=htmlview;
+		break;
+    case GADGET_LABEL: /* BaH */
+		switch (style&3) {
+		case LABEL_SEPARATOR:
+			
+			box=[[NSBox alloc] initWithFrame:rect];
+			
+			[box setTitle:text];
+			[box setBoxType:NSBoxSeparator];
+			[box setTitlePosition:NSNoTitle];
+			
+			[box setContentView:[[FlippedView alloc] init]];
+			
+			if (view) [view addSubview:box];
+			gadget->handle=box;
+			gadget->view=[box contentView];
+			
+			break;
+			
+		default:
+			
+			textfield = [[NSTextField alloc] initWithFrame:rect];
+			
+			[textfield setEditable:NO];
+			[textfield setDrawsBackground:NO];
+			
+			if ((style&3)==LABEL_SUNKENFRAME) {
+				[textfield setBezeled:YES];
+				[textfield setBezelStyle:NSTextFieldSquareBezel];
+			} else {
+				[textfield setBezeled:NO];
+				if ((style&3)==LABEL_FRAME)
+				        [textfield setBordered:YES];
+				else
+				        [textfield setBordered:NO];
+			}
+			
+			[[textfield cell] setWraps:YES];
+			[[textfield cell] setScrollable:NO];
+			[textfield setStringValue:text];
+			
+			switch (style&24){
+				case LABEL_LEFT:[textfield setAlignment:NSLeftTextAlignment];break;
+				case LABEL_RIGHT:[textfield setAlignment:NSRightTextAlignment];break;
+				case LABEL_CENTER:[textfield setAlignment:NSCenterTextAlignment];break;
+			}               
+			
+			if (view) [view addSubview: textfield];
+			gadget->handle=textfield;
+			gadget->view=textfield;
+			
+			break;
+		}
+		break;			
+	case GADGET_SLIDER:
+		switch (style&12){
+		case SLIDER_SCROLLBAR:
+			if (rect.size.width>rect.size.height)		{
+				rect.size.height=[NSScroller scrollerWidth];
+			}
+			else{
+				rect.size.width=[NSScroller scrollerWidth];
+			}
+			scroller=[[NSScroller alloc] initWithFrame:rect];
+			[scroller setEnabled:YES];
+			[scroller setArrowsPosition:NSScrollerArrowsDefaultSetting];
+			[scroller setAction:@selector(scrollerSelect:)];
+			if (view) [view addSubview:scroller];		
+			gadget->handle=scroller;
+			gadget->view=scroller;
+			break;
+		case SLIDER_TRACKBAR:
+			slider=[[NSSlider alloc] initWithFrame:rect];
+			[slider setEnabled:YES];
+			[slider setAction:@selector(sliderSelect:)];
+			if (view) [view addSubview:slider];
+			gadget->handle=slider;
+			gadget->view=slider;
+			break;
+		case SLIDER_STEPPER:
+			stepper=[[NSStepper alloc] initWithFrame:rect];
+			[stepper setEnabled:YES];
+			[stepper setAction:@selector(sliderSelect:)];
+			[stepper setValueWraps:NO];
+			if (view) [view addSubview:stepper];
+			gadget->handle=stepper;
+			gadget->view=stepper;
+			break;
+		}
+		break;
+	case GADGET_PROGBAR:
+		progbar=[[NSProgressIndicator alloc] initWithFrame:rect];
+		[progbar setStyle:NSProgressIndicatorBarStyle];		
+		[progbar setIndeterminate:NO];
+		[progbar setMaxValue:1.0];
+		if (view) [view addSubview:progbar];		
+		gadget->handle=progbar;
+		gadget->view=progbar;
+		break;
+	case GADGET_MENUITEM:
+		// Allows a popup-menu to be created with no text without crashing.
+		if ([text length] || (group->internalclass == GADGET_DESKTOP)) {
+			menuitem=[[NSMenuItem alloc] initWithTitle:text action:@selector(menuSelect:) keyEquivalent:@""];
+			[menuitem setTag:style];
+			[GlobalApp addMenuItem:menuitem];
+		}
+		else{
+			menuitem=(NSMenuItem*)[NSMenuItem separatorItem];
+		}
+		if (group){
+			switch (group->internalclass){
+				case GADGET_WINDOW:		
+					menu=[[NSMenu alloc] initWithTitle:text];
+					[menu setAutoenablesItems:NO];
+					[menu setSubmenu:menu forItem:menuitem];
+					[menu release];
+					menu=[NSApp mainMenu];
+					[menu addItem:menuitem];
+					if ([text length]){
+						[menuitem release];
+					}
+					break;
+				case GADGET_MENUITEM:
+					menu=(NSMenu*)[group->handle submenu];
+					if (!menu){
+						menu=(NSMenu*)[[NSMenu alloc] initWithTitle:text];
+						[menu setAutoenablesItems:NO];
+						[group->handle setSubmenu:menu];
+						[menu addItem:menuitem];
+						[menu release];
+					} else {
+						[menu addItem:menuitem];
+					}
+					if ([text length]){
+						[menuitem release];
+					}
+					break;
+			}
+		}
+		gadget->handle=menuitem;
+		break;
+	case GADGET_NODE:
+		if (!group) break;
+		parent=0;
+		switch (group->internalclass){
+			case GADGET_TREEVIEW:
+				parent=[((TreeView*)group->handle) rootNode];
+				break;
+			case GADGET_NODE:
+				parent=(NodeItem*)group->handle;
+				break;
+		}
+		if (!parent) break;
+		node=[[NodeItem alloc] initWithTitle:text];
+		int index=style;
+		if (index==-1) index=[parent count];
+		if (index>[parent count]) index=[parent count];
+		[node attach:parent atIndex:index];
+		gadget->handle=node;
+		break;
+	}
+}
+
+@class color_delegate;
+@interface color_delegate:NSObject{}
+@end
+@implementation color_delegate
+- (void)windowWillClose:(NSNotification *)aNotification{[NSApp stopModal];}
+@end
+
+int NSColorRequester(int r,int g,int b){
+	NSColorPanel	*panel;
+	NSColor			*color;
+	color_delegate	*dele;
+	dele=[[color_delegate alloc] init];
+	color=[NSColor colorWithCalibratedRed:r/255.0L green:g/255.0L blue:b/255.0L alpha:1.0];
+	panel=[NSColorPanel sharedColorPanel];
+	[panel setColor:color];
+	[panel setDelegate:dele];
+	[NSApp runModalForWindow:panel];
+	color=[panel color];
+	if (color){
+		color=[color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
+		r=(int)((255*[color redComponent])+0.5);
+		g=(int)((255*[color greenComponent])+0.5);
+		b=(int)((255*[color blueComponent])+0.5);
+	}
+	return 0xff000000|(r<<16)|(g<<8)|b;
+}
+
+@class font_delegate;
+@interface font_delegate:NSObject{
+	NSFont		*_font;
+}
+-(id)initWithFont:(NSFont*)font;
+-(void)changeFont:(id)sender;
+-(id)font;
+-(void)windowWillClose:(NSNotification *)aNotification;
+-(unsigned int)validModesForFontPanel:(NSFontPanel *)fontPanel;
+@end
+@implementation font_delegate
+-(id)initWithFont:(NSFont*)font{
+	_font=font;
+	return self;
+}
+-(id)font{
+	return _font;
+}
+-(void)changeFont:(id)sender{
+	_font=[sender convertFont:_font];
+	return; 
+}
+- (void)windowWillClose:(NSNotification *)aNotification{
+	[NSApp stopModal];
+}
+-(unsigned int)validModesForFontPanel:(NSFontPanel *)fontPanel{
+	return NSFontPanelFaceModeMask|NSFontPanelSizeModeMask|NSFontPanelCollectionModeMask;//|NSFontPanelUnderlineEffectModeMask;
+}
+@end
+
+int NSGetSysColor( int colorindex, int* red, int* green, int* blue ){
+	
+	float r, g, b;
+	NSColor* c;
+	NSWindow* w;
+	
+	switch(colorindex){
+		case GUICOLOR_WINDOWBG:
+			w = [[NSWindow alloc] initWithContentRect:NSZeroRect styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:YES];
+			c = [w backgroundColor];
+			[w release];
+			break;
+		case GUICOLOR_GADGETBG:
+			c = [NSColor controlBackgroundColor];
+			break;
+		case GUICOLOR_GADGETFG:
+			c = [NSColor controlTextColor];
+			break;
+		case GUICOLOR_SELECTIONBG:
+			c = [NSColor selectedTextBackgroundColor];
+			break;
+		default:
+			return 0;
+			break;
+	}
+	
+	[[c colorUsingColorSpaceName:NSCalibratedRGBColorSpace] getRed:&r green:&g blue:&b alpha:NULL];
+	*red = (int)(255 * r);
+	*green = (int)(255 * g);
+	*blue = (int)(255 * b);
+	
+	return 1;
+}
+
+NSFont *NSRequestFont(NSFont *font){
+	NSFontPanel		*panel;
+	font_delegate		*dele;
+	if (!font) font=[NSFont userFontOfSize:0];
+	dele=[[font_delegate alloc] initWithFont:font];
+	panel=[NSFontPanel sharedFontPanel];
+	if (font) [panel setPanelFont:font isMultiple:NO];
+	[panel setEnabled:YES];
+	[panel setDelegate:dele];
+	[NSApp runModalForWindow:panel];
+	return [dele font];
+}
+
+NSFont *NSLoadFont(BBString *name,double size,int flags){
+	NSString			*text;
+	NSFont				*font;
+	NSFontManager		*manager;
+
+	text=NSStringFromBBString(name);
+	font=[NSFont fontWithName:text size:size];
+	if (!font) font=[NSFont systemFontOfSize:size];
+	if (flags){
+		manager=[NSFontManager sharedFontManager];
+		if (flags&FONT_BOLD) font=[manager convertFont:font toHaveTrait:NSBoldFontMask];
+		if (flags&FONT_ITALIC) font=[manager convertFont:font toHaveTrait:NSItalicFontMask];
+	}
+	[font retain];
+	return font;
+}
+
+NSFont *NSGetDefaultFont(){
+	return [NSFont systemFontOfSize:[NSFont systemFontSize]];
+}
+
+BBString *NSFontName(NSFont *font){
+	return bbStringFromNSString([font displayName]);	
+}
+
+int NSFontStyle(NSFont *font){
+	int	intBBStyleFlags;
+	int	intCocoaFontTraits;
+	NSFontManager *manager;
+	
+	manager = [NSFontManager sharedFontManager];
+	intCocoaFontTraits = [manager traitsOfFont: font];
+	
+	intBBStyleFlags = 0;
+	if (intCocoaFontTraits & NSBoldFontMask) intBBStyleFlags|=FONT_BOLD;
+	if (intCocoaFontTraits & NSItalicFontMask) intBBStyleFlags|=FONT_ITALIC;
+	
+	return intBBStyleFlags;
+}
+
+double NSFontSize(NSFont *font){
+	return (double)[font pointSize];
+}
+
+void* NSSuperview(NSView* handle){
+	if(handle) return [handle superview];
+	return 0;
+}
+
+// generic gadget commands
+
+void NSFreeGadget(nsgadget *gadget){
+	nsgadget *group;
+	NSWindow *parent;
+	TextView *textview;
+	FlippedView * flipped;
+	if (gadget->textcolor){
+		[gadget->textcolor release];
+		gadget->textcolor = 0;
+	}
+	if (gadget->handle){
+		switch (gadget->internalclass){
+		case GADGET_WINDOW:
+			if ([gadget->handle parentWindow]!=nil){			
+				[[gadget->handle parentWindow] removeChildWindow:(NSWindow*)gadget->handle];
+			}			
+			[gadget->handle close];
+			break;
+		case GADGET_NODE:
+			[gadget->handle remove];
+			[gadget->handle autorelease];
+			break;
+		case GADGET_MENUITEM:
+			[GlobalApp removeMenuItem:gadget->handle];
+			[[gadget->handle menu] removeItem:gadget->handle];
+			break;
+		case GADGET_TEXTAREA:
+			textview=(TextView*)gadget->handle;					
+			[gadget->view removeFromSuperview];
+			[textview free];
+			[textview autorelease];
+			break;
+		case GADGET_LABEL:
+			switch (gadget->style&3) {
+			case LABEL_SEPARATOR:
+				flipped=(FlippedView*)gadget->view;
+				[flipped removeFromSuperview];
+				[gadget->handle removeFromSuperview];
+				[flipped release];
+				break;
+			default:
+				[gadget->view removeFromSuperview];
+				break;
+			}
+			[gadget->handle autorelease];
+			break;
+		case GADGET_TABBER:
+			flipped=(FlippedView*)gadget->view;
+			[flipped removeFromSuperview];
+			[gadget->handle removeFromSuperview];
+			[flipped release];
+			//Cocoa throws an exception if items exist when handle is autoreleased.
+			NSClearItems(gadget);
+			[gadget->handle autorelease];
+			break;
+		case GADGET_PANEL:
+			[gadget->handle setColor:nil];
+			[gadget->handle removeFromSuperview];
+			[gadget->handle autorelease];
+			break;
+		default:
+			[[gadget->view superview] setNeedsDisplayInRect:[gadget->view frame]];
+			[gadget->view removeFromSuperview];
+			[gadget->handle autorelease];
+			break;
+		}	
+	}
+	gadget->handle=0;
+}
+
+void NSEnable(nsgadget *gadget,int state){
+	switch (gadget->internalclass){
+	case GADGET_WINDOW:
+	case GADGET_SLIDER:
+	case GADGET_TEXTFIELD:
+	case GADGET_MENUITEM:
+	case GADGET_BUTTON:
+	case GADGET_LISTBOX:
+	case GADGET_COMBOBOX:
+	case GADGET_TREEVIEW:
+	case GADGET_PANEL:
+	case GADGET_CANVAS:
+		[gadget->handle setEnabled:state];
+		break;
+	case GADGET_TEXTAREA:
+		[gadget->handle setSelectable:state];
+		if (!(gadget->style&TEXTAREA_READONLY)) [gadget->handle setEditable:state];
+		break;
+	}
+}
+
+void NSShow(nsgadget *gadget,int state){
+	switch (gadget->internalclass){
+	case GADGET_WINDOW:
+		if (state==[gadget->handle isVisible]) return;
+		if (state) {
+			if((gadget->group!=&bbNullObject) && (gadget->group->internalclass==GADGET_WINDOW) &&
+			([gadget->handle parentWindow]==nil)) [gadget->group->handle addChildWindow: gadget->handle ordered:NSWindowAbove];
+			[gadget->handle makeKeyAndOrderFront:NSApp];
+		} else {
+			if([gadget->handle parentWindow]!=nil) [[gadget->handle parentWindow] removeChildWindow:(NSWindow*)gadget->handle];
+			[gadget->handle orderOut:NSApp];
+		}
+		break;
+	case GADGET_TOOLBAR:
+		[gadget->handle setVisible:state];
+		break;
+	default:
+		[gadget->handle setHidden:!state];
+	}
+}
+
+void NSCheck(nsgadget *gadget,int state){
+	NSButton			*button;
+	switch (gadget->internalclass){
+	case GADGET_MENUITEM:
+		[gadget->handle setState:state];
+		break;
+	case GADGET_BUTTON:
+		button=(NSButton *)gadget->handle;
+		if(state==NSMixedState) [button setAllowsMixedState:YES]; else [button setAllowsMixedState:NO];
+		[button setState:state];
+		break; 
+	}
+}
+
+void NSPopupMenu(nsgadget *gadget,nsgadget *menugadget){
+	NSView			*view;
+	NSWindow			*window;
+	NSMenuItem		*menuitem;
+	NSEvent			*event;
+	NSPoint			loc;
+	
+	window=(NSWindow*)gadget->handle;
+	view=gadget->view;
+	menuitem=(NSMenuItem*)menugadget->handle;
+	event=[NSEvent 
+		mouseEventWithType:NSRightMouseUp 
+		location:[window convertScreenToBase:[NSEvent mouseLocation]]
+		modifierFlags:nil 
+		timestamp:0 
+		windowNumber:[window windowNumber] 
+     	context:nil
+		eventNumber:nil
+		clickCount:1 
+		pressure:0];
+	[NSMenu popUpContextMenu:[menuitem submenu] withEvent:event forView:view];		
+//	[event release];
+}
+
+int NSState(nsgadget *gadget){
+	NSWindow		*window;
+	TextView		*textview;
+	NSButton		*button;
+	NSView		*view;
+	Toolbar		*toolbar;
+	HTMLView		*browser;
+	NSMenuItem 	*menuItem;
+	int			state;
+
+	state=0;
+
+	switch (gadget->internalclass){
+	case GADGET_TEXTAREA:
+		textview=(TextView*)gadget->handle;
+		if ([textview isHidden]) state|=STATE_HIDDEN;
+		if ((!(gadget->style&TEXTAREA_READONLY)) && (![textview isEditable])) state|=STATE_DISABLED;
+		break;
+	case GADGET_HTMLVIEW:
+		browser=(HTMLView*)gadget->handle;
+		return [browser loaded];
+	case GADGET_WINDOW:
+		window=(NSWindow*)gadget->handle;
+		if ([window isMiniaturized]) state|=STATE_MINIMIZED;
+		if ([window isZoomed]) state|=STATE_MAXIMIZED;
+		if (![window isVisible]) state|=STATE_HIDDEN;
+		break;
+	case GADGET_MENUITEM:
+		menuItem=(NSMenuItem*)gadget->handle;
+		if ([menuItem state]==NSOnState) state|=STATE_SELECTED;
+		if (![menuItem isEnabled]) state|=STATE_DISABLED;
+		break;
+	case GADGET_BUTTON:
+		button=(NSButton *)gadget->handle;
+		switch (gadget->style&7){
+			case BUTTON_RADIO: case BUTTON_CHECKBOX:
+			if ([button state]==NSOnState) state|=STATE_SELECTED;
+			if ([button state]==NSMixedState) state|=STATE_INDETERMINATE;
+		}
+		if ([button isHidden]) state|=STATE_HIDDEN;
+		if (![button isEnabled]) state|=STATE_DISABLED;
+		break;
+	case GADGET_TOOLBAR:
+		toolbar=(Toolbar*)gadget->handle;
+		if ([toolbar isVisible]==NO) state|=STATE_HIDDEN;
+		break;		
+	case GADGET_PROGBAR:
+		view=(NSView*)gadget->handle;
+		if ([view isHidden]) state|=STATE_HIDDEN;
+		break;
+	default:
+		view=(NSView*)gadget->handle;
+		if ([view isHidden]) state|=STATE_HIDDEN;
+		if (![view isEnabled]) state|=STATE_DISABLED;
+		break;
+	}
+	return state;
+}
+
+void NSSetMinimumSize(nsgadget *gadget,int width,int height){
+	NSWindow	*window;
+	NSRect	rect;
+	int		style;
+	window=(NSWindow*)gadget->handle;
+	rect.origin.x=0;
+	rect.origin.y=0;
+	rect.size.width=width;
+	rect.size.height=height;
+	style=gadget->style;
+	if (!(style&WINDOW_CLIENTCOORDS)){
+		rect=[window contentRectForFrameRect:rect];
+		rect.size.width-=rect.origin.x;
+		rect.size.height-=rect.origin.y;
+	}else{
+		if (style&WINDOW_STATUS) rect.size.height+=STATUSBARHEIGHT;		
+	}
+	[window setContentMinSize:rect.size];
+}
+
+void NSSetMaximumSize(nsgadget *gadget,int width,int height){
+	NSWindow	*window;
+	NSRect	rect;
+	int		style;
+	window=(NSWindow*)gadget->handle;
+	rect.origin.x=0;
+	rect.origin.y=0;
+	rect.size.width=width;
+	rect.size.height=height;
+	style=gadget->style;
+	if (!(style&WINDOW_CLIENTCOORDS)){
+		rect=[window contentRectForFrameRect:rect];
+		rect.size.width-=rect.origin.x;
+		rect.size.height-=rect.origin.y;
+	}else{
+		if (style&WINDOW_STATUS) rect.size.height+=STATUSBARHEIGHT;		
+	}
+	[window setContentMaxSize:rect.size];
+}
+
+
+void NSSetStatus(nsgadget *gadget,BBString *data,int pos){
+	NSString			*text;
+	WindowView			*window;
+	ToolView			*toolview;
+
+	text=NSStringFromBBString(data);
+	if ((gadget->style&WINDOW_TOOL) == 0) {
+		window=(WindowView*)gadget->handle;
+		[window setStatus:text align:pos];
+	} else {
+		toolview =(ToolView*)gadget->handle;
+		[toolview setStatus:text align:pos];
+	}
+}
+
+int NSClientWidth(nsgadget *gadget){
+	NSRect		frame;	
+	if (gadget->internalclass==GADGET_DESKTOP){
+		frame=[[NSScreen deepestScreen] visibleFrame];
+		return frame.size.width;
+	}
+	if (!gadget->view) return gadget->w;
+	frame=[gadget->view frame]; 
+	return frame.size.width;
+}
+
+int NSClientHeight(nsgadget *gadget){
+	NSRect		frame;
+	if (gadget->internalclass==GADGET_DESKTOP){
+		frame=[[NSScreen deepestScreen] visibleFrame];
+		return frame.size.height;
+	}
+	if (!gadget->view) return gadget->h;
+	frame=[gadget->view frame]; 
+	return frame.size.height;
+}
+
+void NSRedraw(nsgadget *gadget){
+	NSView	*view;
+	
+	view=(NSView*)gadget->handle;
+	[view display];	//Can just call the display method
+}
+
+void NSActivate(nsgadget *gadget,int code){
+	NSWindow	*window;
+	NSView		*view;
+	NSRect		frame;
+	NodeItem	*node;
+	TreeView	*treeview;
+	HTMLView	*browser;
+	TextView	*textview;
+	NSTextField *textfield;
+	NSText *text;
+	NSComboBox *combo;
+
+// generic commands
+
+	switch (code){
+	case ACTIVATE_REDRAW:
+		NSRedraw(gadget);
+		return;
+	}
+	
+// gadget specific	
+
+	switch (gadget->internalclass){
+	case GADGET_WINDOW:
+		window=(NSWindow*)gadget->handle;
+		switch (code){
+		case ACTIVATE_FOCUS:
+			if([window isVisible]) [window makeKeyAndOrderFront:NSApp];		
+			break;
+		case ACTIVATE_CUT:
+			break;
+		case ACTIVATE_COPY:
+			break;
+		case ACTIVATE_PASTE:
+			break;
+		case ACTIVATE_MINIMIZE:
+			NSShow(gadget,true);
+			[window miniaturize:window];
+			break;
+		case ACTIVATE_MAXIMIZE:
+			if ([window isMiniaturized]) [window deminiaturize:window];
+			if ([window isZoomed]==NO) [window performZoom:window];
+			NSShow(gadget,true);
+			break;
+		case ACTIVATE_RESTORE:
+			if ([window isMiniaturized]) [window deminiaturize:window];
+			if ([window isZoomed]) [window performZoom:window];
+			NSShow(gadget,true);
+			break;
+		}
+		break;
+
+	case GADGET_TEXTFIELD:
+		textfield=(NSTextField*)gadget->handle;
+		window=[textfield window];
+		if (window) 
+		switch (code){
+		case ACTIVATE_FOCUS:
+			[window makeFirstResponder:textfield];
+			break;
+		case ACTIVATE_CUT:
+			text=[[textfield window] fieldEditor:YES forObject:textfield];
+			[text cut:textfield];
+			break;	
+		case ACTIVATE_COPY:
+			text=[[textfield window] fieldEditor:YES forObject:textfield];
+			[text copy:textfield];
+			break;	
+		case ACTIVATE_PASTE:
+			text=[[textfield window] fieldEditor:YES forObject:textfield];
+			[text paste:textfield];
+			break;
+		}
+		break;
+
+	case GADGET_TEXTAREA:
+		textview=(TextView*)gadget->handle;
+		switch (code){
+		case ACTIVATE_FOCUS:
+			window=[textview window];
+			if (window) [window makeFirstResponder:textview];
+			break;
+		case ACTIVATE_CUT:
+			[textview cut:textview];
+			break;	
+		case ACTIVATE_COPY:
+			[textview copy:textview];
+			break;	
+		case ACTIVATE_PASTE:
+			[textview pasteAsPlainText:textview];//paste:textview];
+			break;		
+		case ACTIVATE_PRINT:
+			[textview print:textview];
+			break;
+		}
+		break;
+
+	case GADGET_NODE:
+		node=(NodeItem*)gadget->handle;
+		treeview=[node getOwner];
+		switch (code){	
+		case ACTIVATE_SELECT:
+			[treeview selectNode:node];			
+			break;
+		case ACTIVATE_EXPAND:
+			[treeview expandNode:node];
+			break;
+		case ACTIVATE_COLLAPSE:
+			[treeview collapseNode:node];
+			break;
+		}
+		break;
+				
+	case GADGET_COMBOBOX:
+		switch (code){
+		case ACTIVATE_FOCUS:
+			combo=(NSComboBox*)gadget->handle;
+			[combo selectText:nil];
+			break;	
+		}
+		break;
+
+	case GADGET_HTMLVIEW:
+		browser=(HTMLView*)gadget->handle;
+		switch(code){
+		case ACTIVATE_COPY:
+			[browser copy:browser];
+			break;	
+		case ACTIVATE_BACK:
+			[browser goBack:browser];
+			break;
+		case ACTIVATE_FORWARD:
+			[browser goForward:browser];
+			break;
+		case ACTIVATE_PRINT:
+			view = [[[browser mainFrame] frameView] documentView];
+			if (view != nil) [view print:view];
+			break;
+		}
+						
+	default:
+		switch (code){
+		case ACTIVATE_FOCUS:
+			window=[gadget->handle window];
+			if (window) [window makeFirstResponder:gadget->handle];
+			break;
+		}
+	}
+}
+
+void NSRethink(nsgadget *gadget){
+	NSView		*view;
+	NSRect		rect,vis;
+	TextView	*textview;
+	TabView		*tabber;
+	NSButton		*button;
+	NSControl 	*combobox;
+	int			shouldhide;
+	
+	view=(NSView*)gadget->handle;
+	rect=NSMakeRect(gadget->x,gadget->y,gadget->w,gadget->h);
+	
+	shouldhide = FALSE;
+	
+	switch(gadget->internalclass){
+	case GADGET_WINDOW:
+		vis=[[NSScreen deepestScreen] visibleFrame];
+		rect.origin.x+=vis.origin.x;
+		rect.origin.y=vis.origin.y+vis.size.height-rect.origin.y-rect.size.height;
+		if ((gadget->style&WINDOW_CLIENTCOORDS)!=0){
+			if (gadget->style&WINDOW_STATUS) {
+				rect.origin.y-=STATUSBARHEIGHT;		
+				rect.size.height+=STATUSBARHEIGHT;		
+			}
+			rect = [(NSWindow*)view frameRectForContentRect:rect];
+		}
+		
+		if(![view isVisible]) shouldhide = TRUE;
+		[view setFrame:rect display:YES];
+		if(shouldhide) [view orderOut:view];
+		return;
+	case GADGET_NODE:
+	case GADGET_MENUITEM:
+	case GADGET_TOOLBAR:
+ 		return;
+	case GADGET_TEXTAREA:
+		textview=(TextView*)view;
+		[textview setScrollFrame:rect];
+		return;
+	case GADGET_COMBOBOX:
+		if (rect.size.height > 26) rect.size.height = 26;
+		break;
+	case GADGET_BUTTON:
+		button=(NSButton*)view;
+		// Push Button Size Hack
+		if ((gadget->style&7)==0){
+			if (gadget->h > 30) {
+				[button setBezelStyle:NSRegularSquareBezelStyle];
+			} else {
+				if (gadget->h < 24) { 
+					[button setBezelStyle:NSShadowlessSquareBezelStyle];
+				} else {
+					[button setBezelStyle:NSRoundedBezelStyle];
+				}
+			}	
+		}
+		break;
+	case GADGET_SLIDER:
+		switch (gadget->style&12){
+			case SLIDER_SCROLLBAR:
+				if (gadget->style & SLIDER_HORIZONTAL)
+					rect.size.height = [NSScroller scrollerWidth];
+				else
+					rect.size.width = [NSScroller scrollerWidth];		
+				break;
+		}
+	}
+	[[view superview] setNeedsDisplayInRect:[view frame]];
+	[view setFrame:rect];
+	[view setNeedsDisplay:YES];	
+}
+
+void NSRemoveColor(nsgadget *gadget){
+	switch (gadget->internalclass){
+	case GADGET_BUTTON:
+		if ([[gadget->handle cell] respondsToSelector:@selector(setDrawsBackground)]){
+			[[gadget->handle cell] setDrawsBackground:false];
+		}
+		break;
+	case GADGET_WINDOW:
+		[gadget->handle setBackgroundColor:nil];
+		[gadget->handle display];
+		break;
+	case GADGET_LABEL:
+		if((gadget->style&3)==LABEL_SEPARATOR) break;
+	case GADGET_COMBOBOX:
+	case GADGET_TEXTFIELD:
+		[gadget->handle setDrawsBackground:false];
+		break;
+	case GADGET_LISTBOX:
+	case GADGET_TREEVIEW:
+	case GADGET_PANEL:
+	case GADGET_TEXTAREA:
+		[gadget->handle setColor:nil];
+		break;	
+	}
+}
+
+void NSSetColor(nsgadget *gadget,int r,int g,int b){
+	NSColor				*color;
+
+	color=[NSColor colorWithDeviceRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1.0];
+	
+	switch (gadget->internalclass){
+	case GADGET_BUTTON:
+		if ([[gadget->handle cell] respondsToSelector:@selector(setBackgroundColor)]) [[gadget->handle cell] setBackgroundColor:color];
+		break;
+	case GADGET_COMBOBOX:
+	case GADGET_WINDOW:
+		[gadget->handle setBackgroundColor:color];
+		[gadget->handle display];
+		break;
+	case GADGET_LABEL:
+		if((gadget->style&3)==LABEL_SEPARATOR) break;
+		[gadget->handle setDrawsBackground:YES];
+	case GADGET_TEXTFIELD:
+		[gadget->handle setBackgroundColor:color];
+		break;
+	case GADGET_LISTBOX:
+	case GADGET_TREEVIEW:
+	case GADGET_PANEL:
+	case GADGET_TEXTAREA:
+		[gadget->handle setColor:color];
+		break;	
+	}
+}
+
+void NSSetAlpha(nsgadget *gadget,float alpha){
+	NSWindow	*window;
+	PanelView	*panel;
+	
+	switch (gadget->internalclass){
+	case GADGET_WINDOW:
+		window=(NSWindow*)gadget->handle;
+		[window setAlphaValue:alpha];
+		break;		
+	case GADGET_PANEL:
+		panel=(PanelView*)gadget->handle;
+		[panel setAlpha:alpha];
+		break;	
+	}
+}
+
+BBString *NSGetUserName(){
+	return bbStringFromNSString(CSCopyUserName(true));
+}
+
+BBString *NSGetComputerName(){
+	return bbStringFromNSString(CSCopyMachineName());
+}
+
+BBString *NSRun(nsgadget *gadget,BBString *text){
+	HTMLView			*htmlview;
+	NSString			*script;
+	BBString			*result;
+
+	result=&bbEmptyString;
+	switch (gadget->internalclass){
+	case GADGET_HTMLVIEW:
+		htmlview=(HTMLView*)gadget->handle;
+		script=NSStringFromBBString(text);
+		script=[htmlview stringByEvaluatingJavaScriptFromString:script];
+		result=bbStringFromNSString(script);
+		break;
+	}
+	return result;
+}
+
+void NSSetText(nsgadget *gadget,BBString *data){
+	NSString				*text;
+	NSMutableDictionary	*textAttributes;
+	NSMutableParagraphStyle *parastyle;
+	NSAttributedString		*attribtext;
+	NSObject				*nsobject;
+	
+	attribtext = nil;
+	
+	if(data == nil) data = &bbEmptyString;
+	
+	text = NSStringFromBBString(data);
+	
+	nsobject = (NSObject*)gadget->handle;
+	
+	//printf( "data->length: %d\n", data->length );fflush(stdout);
+	
+	switch (gadget->internalclass){
+	case GADGET_TEXTAREA:
+		[nsobject setText:text];
+		break;
+	case GADGET_HTMLVIEW:
+		[nsobject setAddress:text];
+		break;
+	case GADGET_LABEL: /* BaH */
+		switch (gadget->style&3) {
+		case LABEL_SEPARATOR:
+			return;
+		default:
+			[nsobject setStringValue:text];
+			return;
+		}
+		break;
+	case GADGET_BUTTON:
+		
+		//if ([nsobject respondsToSelector:@selector(setAttributedTitle)] /*&& [nsobject respondsToSelector:@selector(font)]*/){
+			
+			// Create attribute dictionary (autorelease'd)
+			textAttributes = [NSMutableDictionary dictionary];
+			
+			// Font
+			[textAttributes setObject: [nsobject font] forKey:NSFontAttributeName];
+	
+	 		// Paragraph style
+			parastyle = [[NSMutableParagraphStyle alloc] init];
+			[parastyle setParagraphStyle:[NSParagraphStyle defaultParagraphStyle]];
+			
+			if(gadget->internalclass == GADGET_BUTTON){
+				if(((gadget->style & BUTTON_PUSH) == BUTTON_PUSH) ||
+				  (((gadget->style & 7) != BUTTON_RADIO) &&
+				   ((gadget->style & 7) != BUTTON_CHECKBOX)))
+					[parastyle setAlignment:NSCenterTextAlignment];
+			}
+			
+			[textAttributes setObject: parastyle forKey:NSParagraphStyleAttributeName];
+			[parastyle release];
+			
+			// Text color
+			if(gadget->textcolor) [textAttributes setObject: gadget->textcolor forKey: NSForegroundColorAttributeName];
+			
+			// Underline / strikethrough
+			[textAttributes setObject: [NSNumber numberWithInt:0] forKey: NSUnderlineStyleAttributeName];
+			[textAttributes setObject: [NSNumber numberWithInt:0] forKey: NSStrikethroughStyleAttributeName];
+			
+			if ((gadget->intFontStyle&FONT_UNDERLINE)!=0) [textAttributes setObject: [NSNumber numberWithInt:(NSUnderlineStyleSingle|NSUnderlinePatternSolid)] forKey: NSUnderlineStyleAttributeName];
+			if ((gadget->intFontStyle&FONT_STRIKETHROUGH)!=0) [textAttributes setObject: [NSNumber numberWithInt:(NSUnderlineStyleSingle|NSUnderlinePatternSolid)] forKey: NSStrikethroughStyleAttributeName];
+			
+			// Create attibuted text
+			attribtext = [[NSAttributedString alloc] initWithString: text attributes: textAttributes];
+			
+			[nsobject setAttributedTitle:attribtext];
+			break;
+		//}
+	case GADGET_MENUITEM:
+		[nsobject setTitle:text];
+		// Required otherwise root window menus aren't updated.
+		[[nsobject submenu] setTitle:text];
+		break;
+	case GADGET_PANEL:
+	case GADGET_NODE:
+	case GADGET_WINDOW:
+		[nsobject setTitle:text];
+		break;
+	case GADGET_COMBOBOX:
+		if(!(gadget->style & COMBOBOX_EDITABLE)) break;
+	case GADGET_TEXTFIELD:
+		[nsobject setStringValue:text];
+		break;
+	}
+}
+
+BBString *NSGetText(nsgadget *gadget){
+	
+	NSObject		*nsobject;
+	BBString		*result;
+
+	result=&bbEmptyString;
+	nsobject=(NSObject*)gadget->handle;
+	
+	switch (gadget->internalclass){
+	case GADGET_TEXTAREA:
+		result=bbStringFromNSString([[nsobject storage] string]);
+		break;
+	case GADGET_TEXTFIELD:
+	case GADGET_COMBOBOX:
+		result=bbStringFromNSString([nsobject stringValue]);
+		break;	
+	case GADGET_HTMLVIEW:
+		result=bbStringFromNSString([nsobject address]);
+		break;
+	case GADGET_NODE:
+		result=bbStringFromNSString([nsobject value]);
+		break;
+	case GADGET_LABEL: /* BaH */
+		switch (gadget->style&3) {
+		case 0:
+		case LABEL_FRAME:
+		case LABEL_SUNKENFRAME:
+			result=bbStringFromNSString([nsobject stringValue]);
+		}
+		break;
+	case GADGET_PANEL:
+	case GADGET_WINDOW:
+	case GADGET_BUTTON:
+	case GADGET_MENUITEM:
+		result=bbStringFromNSString([nsobject title]);
+		break;
+	}
+	return result;
+}
+
+int NSCharWidth(NSFont *font,int charcode){	
+	NSSize size=[font advancementForGlyph:charcode];
+	return (int)size.width;
+}
+
+void NSSetFont(nsgadget *gadget,NSFont *font){
+	NSView			*view;
+	
+	view = (NSView*)gadget->handle;
+	
+	switch (gadget->internalclass){
+		case GADGET_LABEL:
+			if ((gadget->style&3)==LABEL_SEPARATOR) break;
+		case GADGET_BUTTON:
+			[view setFont:font];
+			NSSetText(gadget, NSGetText(gadget));		//Apply underline/strikethough formatting as attributed text in NSSetText().
+			break;
+		case GADGET_LISTBOX:
+		case GADGET_TREEVIEW:
+		case GADGET_COMBOBOX:
+		case GADGET_TEXTAREA:
+		case GADGET_TEXTFIELD:
+		case GADGET_TABBER:
+			[view setFont:font];
+			break;
+		
+	}
+}
+
+BBString * NSGetTooltip(nsgadget *gadget){
+
+	BBString			*result;
+	NSView			*view;
+	
+	result=&bbEmptyString;
+	view=(NSView*)gadget->handle;
+	
+	if(view) result=bbStringFromNSString([view toolTip]);
+	
+	return result;
+}
+
+int NSSetTooltip(nsgadget *gadget,BBString *data){
+	
+	NSString			*text;
+	NSView			*view;
+	
+	view =(NSView*)gadget->handle;
+	text=NSStringFromBBString(data);
+	
+	if(view){
+		[view setToolTip:text];
+		return 1;
+	}
+	
+	return 0;
+}
+
+// gadgetitem commands
+
+void NSClearItems(nsgadget *gadget)
+{
+	ListView			*listbox;
+	NSControl 		*combo;
+	NSTabView			*tabber;
+	Toolbar			*toolbar;
+	NSToolbarItem		*item;
+	NSArray			*items;
+	int				i,n;
+		
+	switch (gadget->internalclass){
+	case GADGET_LISTBOX:
+		listbox=(ListView*)gadget->handle;
+		[listbox clear];
+		break;
+	case GADGET_COMBOBOX:
+		combo=(NSControl*)gadget->handle;
+		[combo removeAllItems];
+		break;
+	case GADGET_TABBER:
+		tabber=(NSTabView*)gadget->handle;
+		items=[tabber tabViewItems];
+		n=[tabber numberOfTabViewItems];
+		for (i=0;i<n;i++) [tabber removeTabViewItem:[tabber tabViewItemAtIndex:0]];
+		break;
+	case GADGET_TOOLBAR:
+		toolbar=(Toolbar*)gadget->handle;
+		items=[toolbar items];
+		n=[items count];
+		for (i=0;i<n;i++) 	[toolbar removeItemAtIndex:0];
+		break;
+	}
+}
+
+void NSAddItem(nsgadget *gadget,int index,BBString *data,BBString *tip,NSImage *image,BBObject *extra){
+	NSString			*text,*tiptext;
+	NSControl 		*combo;
+	NSTabView			*tabber;
+	TabViewItem		*tabitem;
+	ListView			*listbox;
+	Toolbar			*toolbar;
+	NSToolbarItem		*item;
+
+	text=NSStringFromBBString(data);
+	tiptext=NSStringFromBBString(tip);
+	switch (gadget->internalclass){
+	case GADGET_LISTBOX:
+		listbox=(ListView*)gadget->handle;
+		[listbox addItem:text atIndex:index withImage:image withTip:tiptext withExtra:extra];
+		break;
+	case GADGET_COMBOBOX:
+		combo=(NSControl*)gadget->handle;
+		[combo insertItemWithObjectValue:text atIndex:index];
+//		[[combo itemAtIndex:index] setImage:image];
+		break;
+	case GADGET_TABBER:
+		tabber=(NSTabView*)gadget->handle;	
+		tabitem=[[TabViewItem alloc] initWithIdentifier:text];
+		[tabitem setLabel:text];
+		[tabitem setImage:image];
+		[tabber insertTabViewItem:tabitem atIndex:index];	
+		[tabitem release];
+		break;
+	case GADGET_TOOLBAR:	
+		toolbar=(Toolbar*)gadget->handle;
+		if (image==0){			
+			int v;
+			Gestalt( 'sysv',&v );
+			if( v>=0x1070 ){
+				[toolbar insertItemWithItemIdentifier:NSToolbarSpaceItemIdentifier atIndex:index];
+			}else{
+				[toolbar insertItemWithItemIdentifier:NSToolbarSeparatorItemIdentifier atIndex:index];
+			}
+		}
+		else{
+			item=[[NSToolbarItem alloc] initWithItemIdentifier:text];
+			[item setImage:image];
+//			[item setLabel:text];
+			[item setAction:@selector(iconSelect:)];
+			[item setTarget:GlobalApp];
+			[item setToolTip:tiptext];
+			[item setTag:0];
+			[GlobalApp addToolbarItem:item];
+			[toolbar addToolbarItem:item];
+			[toolbar insertItemWithItemIdentifier:text atIndex:index];								
+		}
+		break;
+	}
+}
+
+NSToolbarItem *FindToolbarItem(NSToolbar *toolbar,int index){
+	return (NSToolbarItem*)[[toolbar items] objectAtIndex:index];
+}
+
+void NSSetItem(nsgadget *gadget,int index,BBString *data,BBString *tip,NSImage *image,BBObject *extra){
+	NSString			*text,*tiptext;
+	NSControl 		*combo;
+	NSTabView			*tabber;
+	TabViewItem		*tabitem;
+	ListView			*listbox;
+	Toolbar			*toolbar;
+	NSToolbarItem		*item;
+
+	text=NSStringFromBBString(data);
+	tiptext=NSStringFromBBString(tip);
+
+	switch (gadget->internalclass){
+	case GADGET_LISTBOX:
+		listbox=(ListView*)gadget->handle;
+		[listbox setItem:text atIndex:index withImage:image withTip:tiptext withExtra:extra];
+		break;
+	case GADGET_COMBOBOX:
+		combo=(NSControl*)gadget->handle;
+		[combo removeItemAtIndex:index];
+		[combo insertItemWithObjectValue:text atIndex:index];
+//		[[combo itemAtIndex:index] setImage:image];
+		break;
+	case GADGET_TABBER:
+		tabber=(NSTabView*)gadget->handle;
+		tabitem=(TabViewItem*)[tabber tabViewItemAtIndex:index];
+		[tabitem setLabel:text];
+		[tabitem setImage:image];
+		break;
+	case GADGET_TOOLBAR:	
+		toolbar=(Toolbar*)gadget->handle;
+		item=FindToolbarItem(toolbar,index);
+		if (item)	{
+//			[item setLabel:text];
+			[item setImage:image];
+			[item setToolTip:tiptext];
+			[item setTag:0];
+		}
+		break;
+	}
+}
+
+void NSRemoveItem(nsgadget *gadget,int index){
+	ListView		*listbox;
+	NSControl 	*combo;
+	NSTabView		*tabber;
+	TabViewItem	*tabitem;
+	Toolbar		*toolbar;
+
+	switch (gadget->internalclass){
+	case GADGET_LISTBOX:
+		listbox=(ListView*)gadget->handle;
+		[listbox removeItemAtIndex:index];
+		break;
+	case GADGET_COMBOBOX:
+		combo=(NSControl*)gadget->handle;
+		[combo removeItemAtIndex:index];
+		break;
+	case GADGET_TABBER:
+		tabber=(NSTabView*)gadget->handle;
+		tabitem=(TabViewItem*)[tabber tabViewItemAtIndex:index];
+		[tabber removeTabViewItem:tabitem];
+		break;
+	case GADGET_TOOLBAR:
+		toolbar=(Toolbar*)gadget->handle;
+		[toolbar removeItemAtIndex:(int)index];
+		break;
+	}
+}
+
+void NSSelectItem(nsgadget *gadget,int index,int state){
+	NSControl 		*combo;
+	NSTabView			*tabber;
+	ListView			*listbox;
+	Toolbar			*toolbar;
+	NSToolbarItem		*item;
+
+	switch (gadget->internalclass){
+	case GADGET_LISTBOX:
+		listbox=(ListView*)gadget->handle;
+		if(state) [listbox selectItem:index]; else [listbox deselectItem:index];
+		break;
+	case GADGET_COMBOBOX:
+		combo=(NSControl*)gadget->handle;
+		[combo setDelegate:nil];
+		[combo selectItemAtIndex:index];
+		[combo setObjectValue:[combo objectValueOfSelectedItem]];
+		[combo setDelegate:GlobalApp];
+		break;
+	case GADGET_TABBER:
+		tabber=(NSTabView*)gadget->handle;
+		[tabber selectTabViewItemAtIndex:index];
+		break;
+	case GADGET_TOOLBAR:	
+		toolbar=(Toolbar*)gadget->handle;
+		item=FindToolbarItem(toolbar,index);
+		BOOL enable=(state&STATE_DISABLED)?false:true;
+		[item setEnabled:enable];
+		int pressed=(state&STATE_SELECTED)?1:0;
+		[item setTag:pressed];
+		break;
+	}
+}
+
+int NSSelectedItem(nsgadget *gadget,int index){
+	NSComboBox		*combo;
+	NSTabView			*tabber;
+	ListView			*listbox;
+	Toolbar			*toolbar;
+	NSToolbarItem		*item;
+	int				state;
+
+	state=0;
+	switch (gadget->internalclass){
+	case GADGET_LISTBOX:
+		listbox=(ListView*)gadget->handle;
+		if ([[listbox table] selectedRow]==index) state|=STATE_SELECTED;
+		break;
+	case GADGET_COMBOBOX:
+		combo=(NSControl*)gadget->handle;
+		if ([combo indexOfSelectedItem]==index) state|=STATE_SELECTED;
+		break;
+	case GADGET_TABBER:
+		tabber=(NSTabView*)gadget->handle;
+		if ([tabber indexOfTabViewItem:[tabber selectedTabViewItem]]==index) state|=STATE_SELECTED;
+		break;
+	case GADGET_TOOLBAR:	
+		toolbar=(Toolbar*)gadget->handle;
+		item=FindToolbarItem(toolbar,index);
+		if (![item isEnabled]) state|=STATE_DISABLED;
+		if ([item tag]!=0) state|=STATE_SELECTED;
+		break;
+	}
+	return state;
+}
+
+// treeview commands
+
+int NSCountKids(nsgadget *gadget){
+	TreeView		*treeview;
+	NodeItem		*node;
+
+	switch (gadget->internalclass){
+	case GADGET_TREEVIEW:
+		treeview=(TreeView*)gadget->handle;
+		return [treeview count];
+	case GADGET_NODE:
+		node=(NodeItem*)gadget->handle;
+		return [node count];
+	}
+	return 0;
+}
+
+id NSSelectedNode(nsgadget *gadget){
+	TreeView		*treeview;
+
+	switch (gadget->internalclass){
+	case GADGET_TREEVIEW:
+		treeview=(TreeView*)gadget->handle;
+		return [treeview selectedNode];		
+	}
+	return 0;
+}
+
+// textarea commands
+
+int LinePos(NSString *text,int pos){
+	int			line,i;
+
+	line=0;
+	for (i=0;i<pos;i++) {if ([text characterAtIndex:i]=='\n' ) line++;}
+	return line;
+}
+
+int CharPos(NSString *text,int line){
+	int			pos,n;
+
+	pos=0;
+	n=[text length];
+	while (pos<n && line>0){
+		if ([text characterAtIndex:pos]=='\n') line--;
+		pos++;
+	}
+	return pos;
+}
+
+NSRange GetRange(NSTextStorage *storage,int pos,int count,int units){
+	
+	NSString	*text;
+	unsigned int max;
+	
+	if (units==TEXTAREA_LINES){
+		text=[storage string];
+		if (count==TEXTAREA_ALL)
+			count=[storage length];
+		else
+			count=CharPos(text,pos+count);
+		pos=CharPos(text,pos);
+		max = [storage length]-pos;
+		count-=pos;
+	}
+	else{
+		max = [storage length]-pos;
+		if (count==TEXTAREA_ALL) count=max;
+	}
+	
+	if (count > max) count = max;
+	if (count<0) count=0;
+	
+	//NSLog(@"GetRange() pos: %d,  count: %d,  length: %d\n", pos, count, [storage length]);
+	
+	return NSMakeRange(pos,count);
+	
+}
+
+void NSReplaceText(nsgadget *gadget,int pos,int count,BBString *data,int units){
+	NSString			*text;
+	TextView			*textarea;
+	NSRange			range,snap;
+	NSTextStorage		*storage;
+	unsigned int			size;
+	
+	text=NSStringFromBBString(data);
+	textarea=(TextView*)gadget->handle;
+	
+	if(([[textarea string] length] == 0) || ((pos == 0) && (count == TEXTAREA_ALL))){
+		
+		[textarea setText:text];
+		
+	} else {
+		
+		snap=[textarea selectedRange];
+		range=GetRange([textarea storage],pos,count,units);
+		storage=[textarea storage];
+		[storage replaceCharactersInRange:range withString:text];	
+		size=[storage length];
+		if (snap.location>size) snap.location=size;
+		if (snap.location+snap.length>size) snap.length=size-snap.location;	
+		[textarea setSelectedRange:snap];
+		
+	}
+	
+}
+
+void NSAddText(nsgadget *gadget,BBString *data){
+	NSString			*text;
+	TextView			*textarea;
+	NSRange			range;
+
+	text=NSStringFromBBString(data);
+	textarea=(TextView*)gadget->handle;
+	[textarea addText:text];
+	range=GetRange([textarea textStorage],[[textarea string] length],0,0);
+	[textarea setSelectedRange:range];
+	[textarea scrollRangeToVisible:range];
+}
+
+BBString *NSAreaText(nsgadget *gadget,int pos,int length,int units){
+	TextView			*textarea;
+	NSRange			range;
+	NSAttributedString	*astring;
+	BBString				*bstring;
+
+	textarea=(TextView*)gadget->handle;
+	range=GetRange([textarea storage],pos,length,units);
+	astring=[[textarea storage] attributedSubstringFromRange:range];	
+	bstring=bbStringFromNSString([astring string]);
+	return bstring;
+}
+
+int NSAreaLen(nsgadget *gadget,int units){
+	TextView			*textarea;
+	NSTextStorage		*storage;
+	unsigned			ulen;
+
+	textarea=(TextView*)gadget->handle;
+	storage=[textarea storage];
+	ulen=[storage length];
+	if (units==TEXTAREA_LINES) ulen=LinePos([storage string],ulen)+1;
+	return ulen;	
+}
+
+void NSSetSelection(nsgadget *gadget,int pos,int length,int units){
+	TextView			*textarea;
+	NSRange			range;
+
+	textarea=(TextView*)gadget->handle;	
+	range=GetRange([textarea textStorage],pos,length,units);
+	[textarea setSelectedRange:range];
+	if( !textarea->lockedNest ) [textarea scrollRangeToVisible:range];
+}
+
+void NSLockText(nsgadget *gadget){
+	TextView			*textarea;
+
+	textarea=(TextView*)gadget->handle;
+	
+	if( !textarea->lockedNest ){
+		textarea->lockedRange=[textarea rangeForUserTextChange];
+		[textarea->storage beginEditing];
+	}
+
+	++textarea->lockedNest;
+}
+
+void NSUnlockText(nsgadget *gadget){
+	TextView			*textarea;
+	
+	textarea=(TextView*)gadget->handle;
+	
+	--textarea->lockedNest;
+
+	if( !textarea->lockedNest ){
+		NSRange range=textarea->lockedRange;
+		[textarea->storage endEditing];
+		if( range.location+range.length>[textarea->storage length] ) range=NSMakeRange( 0,0 );
+		[textarea setSelectedRange:range];
+	}
+}
+
+void NSSetTabs(nsgadget *gadget,int tabwidth){
+	TextView *textarea;
+	textarea=(TextView*)gadget->handle;	
+	[textarea setTabs:tabwidth];
+}
+
+void NSSetMargins(nsgadget *gadget,int leftmargin){
+	TextView *textarea;
+	textarea=(TextView*)gadget->handle;	
+	[textarea setMargins:leftmargin];
+}
+
+int NSCharAt(nsgadget *gadget,int line){
+	TextView		*textarea;
+	NSString		*text;
+	int				n,i;
+
+	textarea=(TextView*)gadget->handle;	
+	text=[[textarea storage] string];
+	n=[text length];i=0;
+	while (line){
+		if (i==n) break;
+		if ([text characterAtIndex:i]=='\n' ) line--;
+		i++;
+	}
+	return i;
+}
+
+int NSLineAt(nsgadget *gadget,int pos){
+	TextView			*textarea;
+	textarea=(TextView*)gadget->handle;	
+	return LinePos([[textarea storage] string],pos);
+}
+
+int NSCharX(nsgadget *gadget,int pos){
+	unsigned int rectCount;
+	NSRectArray rectArray;
+	TextView	*textarea = (TextView*)gadget->handle;
+	NSRange range = GetRange([textarea textStorage],pos,0,TEXTAREA_CHARS);
+	rectArray = [[textarea layoutManager] rectArrayForCharacterRange:range withinSelectedCharacterRange:range inTextContainer: [textarea textContainer] rectCount:&rectCount];
+	if(rectCount > 0) return (int)(((NSRect)rectArray[0]).origin.x-([textarea visibleRect].origin.x-[textarea textContainerOrigin].x));
+}
+
+int NSCharY(nsgadget *gadget,int pos){
+	unsigned int rectCount;
+	NSRectArray rectArray;
+	TextView	*textarea = (TextView*)gadget->handle;
+	NSRange range = GetRange([textarea textStorage],pos,0,TEXTAREA_CHARS);
+	rectArray = [[textarea layoutManager] rectArrayForCharacterRange:range withinSelectedCharacterRange:range inTextContainer: [textarea textContainer] rectCount:&rectCount];
+	if(rectCount > 0) return (int)(((NSRect)rectArray[0]).origin.y-([textarea visibleRect].origin.y-[textarea textContainerOrigin].y));
+}
+
+int NSGetCursorPos(nsgadget *gadget,int units){
+	TextView			*textarea;
+	NSRange			range;
+
+	textarea=(TextView*)gadget->handle;	
+	range=[textarea rangeForUserTextChange];
+	if (range.location == NSNotFound) return 0; //KORIOLIS (avoids read-only text-area crash)
+	if (units==TEXTAREA_LINES) return NSLineAt(gadget,range.location);
+	return range.location;
+}
+
+int NSGetSelectionlength(nsgadget *gadget,int units){
+	TextView			*textarea;
+	NSRange			range;
+
+	textarea=(TextView*)gadget->handle;	
+	range=[textarea rangeForUserTextChange];
+	if (range.location == NSNotFound) return 0; //KORIOLIS (avoids read-only text-area crash)
+	if (range.length == 0) return 0;
+	if (units == TEXTAREA_LINES){
+		int l0=NSLineAt(gadget,range.location);
+		int l1=NSLineAt(gadget,range.location+range.length-1);
+		return (l1-l0+1);
+	}
+	return range.length;
+}
+
+void NSSetTextColor(nsgadget *gadget,int r,int g,int b){
+	
+	if(gadget->textcolor) [gadget->textcolor release];
+	gadget->textcolor = [[NSColor colorWithDeviceRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1.0] retain];
+	
+	switch (gadget->internalclass){
+	case GADGET_LABEL:
+		switch (gadget->style&3) {
+			case LABEL_SEPARATOR:
+				return;
+		}
+	case GADGET_TEXTFIELD:
+	case GADGET_LISTBOX:
+	case GADGET_TREEVIEW:
+	case GADGET_TEXTAREA:
+		[gadget->handle setTextColor:gadget->textcolor];
+		break;
+	default:
+		NSSetText(gadget, NSGetText(gadget));	//Attempt to reset text with NSAttributedString
+		break;
+	}
+}
+
+void NSSetStyle(nsgadget *gadget,int r,int g,int b,int flags,int pos,int length,int units)	{
+	TextView			*textarea;
+	NSRange			_range;
+	NSColor				*color;
+	int traits = 0;
+
+	textarea=(TextView*)gadget->handle;	
+	_range=GetRange([textarea storage],pos,length,units);
+	color=[NSColor colorWithDeviceRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1.0];
+	
+	[[textarea storage] removeAttribute:NSLinkAttributeName range:_range];
+	[[textarea storage] addAttribute:NSForegroundColorAttributeName value:color range:_range];
+	[[textarea storage] addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:(flags & 4)?NSUnderlineStyleSingle:NSUnderlineStyleNone] range:_range];
+	[[textarea storage] addAttribute:NSStrikethroughStyleAttributeName value:[NSNumber numberWithInt:(flags & 8)?NSUnderlineStyleSingle:NSUnderlineStyleNone] range:_range];
+
+	traits |= (flags & 1)?NSBoldFontMask:NSUnboldFontMask;
+	traits |= (flags & 2)?NSItalicFontMask:NSUnitalicFontMask;
+
+	[[textarea storage] applyFontTraits: traits range:_range];
+}
+
+void NSSetValue(nsgadget *gadget,float value){
+	NSProgressIndicator	*progbar;
+	NSDate				*date;
+	NSValue				*info;
+	NSRunLoop			*runloop;
+	
+	switch (gadget->internalclass){
+	case GADGET_PROGBAR:
+		progbar=(NSProgressIndicator*)gadget->handle;
+		[progbar setDoubleValue:value];
+		break;
+	}
+}
+
+// slider / scrollbar
+
+void NSSetSlider(nsgadget *gadget,double value,double small,double big){
+	NSScroller		*scroller;
+	NSSlider			*slider;
+	NSStepper			*stepper;
+	NSRect			frame;
+	float			size;
+	
+	switch (gadget->style&12){
+	case SLIDER_SCROLLBAR:
+		scroller=(NSScroller*)gadget->handle;
+		if(value > (big-small))
+			value = 1.0L;
+		else if(big-small)
+			value/=(big-small);
+		else
+			value = 0.0L;
+		[scroller setKnobProportion:(small/big)];
+		[scroller setDoubleValue:value];
+		break;
+	case SLIDER_TRACKBAR:
+		slider=(NSSlider*)gadget->handle;
+		[slider setMinValue:small];
+		[slider setMaxValue:big];
+		[slider setDoubleValue:value];
+		break;
+	case SLIDER_STEPPER:
+		stepper=(NSStepper*)gadget->handle;
+		[stepper setMinValue:small];
+		[stepper setMaxValue:big];
+		[stepper setDoubleValue:value];
+		break;
+	}
+}
+
+double NSGetSlider(nsgadget *gadget){
+	NSControl	*control;
+	control = (NSControl*)gadget->handle;
+	return [control doubleValue];
+}
+
+
+NSCursor* NSCursorCreateStock(short sIndex)
+{
+
+    // Adapted from wxWidgets - if you believe this contravenes wxWidget's licensing
+    // agreements, please let the BRL team know and it will be removed.
+    
+    int i;
+    ArrayCursor* tmpCursor = &arrCursors[sIndex];
+    NSImage *tmpImage = [[NSImage alloc] initWithSize:NSMakeSize(16.0,16.0)];
+    
+    NSBitmapImageRep *tmpRep = [[NSBitmapImageRep alloc]
+        initWithBitmapDataPlanes: NULL
+        pixelsWide: 16
+        pixelsHigh: 16
+        bitsPerSample: 1
+        samplesPerPixel: 2
+        hasAlpha: YES
+        isPlanar: YES
+        colorSpaceName: NSCalibratedWhiteColorSpace
+        bytesPerRow: 2
+        bitsPerPixel: 1];
+    
+    unsigned char *planes[5];
+    [tmpRep getBitmapDataPlanes:planes];
+    
+    for(i=0; i<16; ++i)
+    {
+        planes[0][2*i  ] = (~tmpCursor->bits[i] & tmpCursor->mask[i]) >> 8 & 0xff;
+        planes[1][2*i  ] = tmpCursor->mask[i] >> 8 & 0xff;
+        planes[0][2*i+1] = (~tmpCursor->bits[i] & tmpCursor->mask[i]) & 0xff;
+        planes[1][2*i+1] = tmpCursor->mask[i] & 0xff;
+    }
+    
+    [tmpImage addRepresentation:tmpRep];
+    
+    NSCursor* tmpNSCursor =  [[NSCursor alloc]  initWithImage:tmpImage hotSpot:NSMakePoint(tmpCursor->hitpoint[1], tmpCursor->hitpoint[0])];
+    
+    [tmpRep release];[tmpImage release];
+    
+    return tmpNSCursor;
+}
+
+void NSSetPointer(int shape){
+	NSCursor *cursor;
+	cursor=[NSCursor arrowCursor];
+	
+	switch (shape){
+//	case POINTER_DEFAULT:cursor=[NSCursor ];break;
+	case POINTER_ARROW:cursor=[NSCursor arrowCursor];break;
+	case POINTER_IBEAM:cursor=[NSCursor IBeamCursor];break;
+//	case POINTER_WAIT:cursor=[NSCursor ];break;
+	case POINTER_CROSS:cursor=[NSCursor crosshairCursor];break;
+	case POINTER_UPARROW:cursor=[NSCursor resizeUpCursor];break;
+	case POINTER_SIZENWSE:cursor=NSCursorCreateStock(curNWSE);break;
+	case POINTER_SIZENESW:cursor=NSCursorCreateStock(curNESW);break;
+	case POINTER_SIZEWE:cursor=[NSCursor resizeLeftRightCursor];break;
+	case POINTER_SIZENS:cursor=[NSCursor resizeUpDownCursor];break;
+	case POINTER_SIZEALL:cursor=NSCursorCreateStock(curSizeAll);break;
+	case POINTER_NO:cursor=NSCursorCreateStock(curNoEntry);break;
+	case POINTER_HAND:cursor=[NSCursor pointingHandCursor];break;
+//	case POINTER_APPSTARTING:cursor=[NSCursor ];break;
+	case POINTER_HELP:cursor=NSCursorCreateStock(curHelp);break;
+	}
+	[cursor set];
+}
+
+typedef struct bbpixmap bbpixmap;
+
+struct bbpixmap{
+// BBObject
+	void		*class;
+//	int		refs;
+// pixmap
+	unsigned char *pixels;
+	int		width,height,pitch,format,capacity;
+};
+
+
+#define PF_I8 1
+#define PF_A8 2
+#define PF_BGR888 3
+#define PF_RGB888 4
+#define PF_BGRA8888 5
+#define PF_RGBA8888 6
+#define PF_STDFORMAT PF_RGBA8888
+
+const static char BytesPerPixel[]={0,1,1,3,3,4,4};
+const static char BitsPerPixel[]={0,8,8,24,24,32,32};
+const static char RedBitsPerPixel[]={0,0,0,8,8,8,8};
+const static char GreenBitsPerPixel[]={0,0,0,8,8,8,8};
+const static char BlueBitsPerPixel[]={0,0,0,8,8,8,8};
+const static char AlphaBitsPerPixel[]={0,0,8,0,0,8,8};
+
+NSImage *NSPixmapImage(bbpixmap *pix){
+	NSImage *image;
+	NSBitmapImageRep *bitmap;
+	int spp,bpp,i;
+	int bytesperrow;
+	BOOL	alpha;
+	unsigned char * data;
+		
+	alpha=AlphaBitsPerPixel[pix->format]?YES:NO;
+	spp=BytesPerPixel[pix->format];
+	bpp=BitsPerPixel[pix->format];
+	bytesperrow=pix->width*spp;
+	
+	bitmap=[[[NSBitmapImageRep alloc] 
+		initWithBitmapDataPlanes:NULL
+		pixelsWide:pix->width
+		pixelsHigh:pix->height
+		bitsPerSample:8 
+		samplesPerPixel:spp 
+		hasAlpha:alpha 
+		isPlanar:NO 
+		colorSpaceName:NSDeviceRGBColorSpace 
+//		bitmapFormat:NSAlphaNonpremultipliedBitmapFormat
+		bytesPerRow:bytesperrow 
+		bitsPerPixel:bpp] autorelease];
+		
+	data = [bitmap bitmapData];
+	
+	for( i = 0; i < pix->height; i++) {
+		memcpy( data + ( i * bytesperrow ), pix->pixels + ( i * pix->pitch ), bytesperrow );
+	}
+
+	image=[[NSImage alloc] initWithSize:NSMakeSize(pix->width,  pix->height)];
+	[image addRepresentation:bitmap];
+	[image retain];
+	return image;
+}
+
+void NSSetImage(nsgadget *gadget,NSImage *image,int flags){
+	PanelView *panel;
+	NSButton *button;
+	NSMenuItem *menu;
+	
+	switch (gadget->internalclass){
+	case GADGET_PANEL:
+		panel=(PanelView*)gadget->handle;
+		[panel setImage:image withFlags:flags];
+		break;
+	case GADGET_BUTTON:
+		if ((flags & GADGETPIXMAP_ICON) && (gadget->style <= BUTTON_PUSH)){ 
+			button=(NSButton *)gadget->handle;
+			[button setImage:image];
+			if (flags & GADGETPIXMAP_NOTEXT) {
+				[button setImagePosition:NSImageOnly];
+			} else {
+				[button setImagePosition:NSImageLeft];
+			}
+		}
+		break; 
+	case GADGET_MENUITEM:
+		if (flags & GADGETPIXMAP_ICON){
+			menu=(NSMenuItem*)gadget->handle;
+			[menu setImage:image];
+		}
+		break;
+	}
+}
+
+void NSSetIcon(nsgadget *gadget,NSImage *image){
+	NodeItem	*node;
+		
+	switch (gadget->internalclass){
+	case GADGET_NODE:
+		node=(NodeItem*)gadget->handle;
+		[node setIcon:image];
+		break;
+	}
+}
+
+void NSSetNextView(nsgadget *gadget,nsgadget *nextgadget){
+	NSView		*view,*nextview;
+	view=(NSView*)gadget->handle;
+	nextview=(NSView*)nextgadget->handle;
+	[view setNextKeyView:nextview];
+}
+
+static int keyToChar( int key ){
+	if( key>=KEY_A && key<=KEY_Z ) return key-KEY_A+'a';
+	if( key>=KEY_F1 && key<=KEY_F12 ) return key-KEY_F1+NSF1FunctionKey;
+	
+	switch( key ){
+	case KEY_BACKSPACE:return 8;
+	case KEY_TAB:return 9;
+	case KEY_ESC:return 27;
+	case KEY_SPACE:return 32;
+	case KEY_PAGEUP:return NSPageUpFunctionKey;
+	case KEY_PAGEDOWN:return NSPageDownFunctionKey;
+	case KEY_END:return NSEndFunctionKey;
+	case KEY_HOME:return NSHomeFunctionKey;
+	case KEY_UP:return NSUpArrowFunctionKey;
+	case KEY_DOWN:return NSDownArrowFunctionKey;
+	case KEY_LEFT:return NSLeftArrowFunctionKey;
+	case KEY_RIGHT:return NSRightArrowFunctionKey;
+	case KEY_INSERT:return NSInsertFunctionKey;
+	case KEY_DELETE:return NSDeleteFunctionKey;
+	case KEY_TILDE:return '~';
+	case KEY_MINUS:return '-';
+	case KEY_EQUALS:return '=';
+	case KEY_OPENBRACKET:return '[';
+	case KEY_CLOSEBRACKET:return ']';
+	case KEY_BACKSLASH:return '\\';
+	case KEY_SEMICOLON:return ';';
+	case KEY_QUOTES:return '\'';
+	case KEY_COMMA:return ',';
+	case KEY_PERIOD:return '.';
+	case KEY_SLASH:return '/';
+	}
+	return 0;
+}
+
+void NSSetHotKey(nsgadget *gadget,int key,int modifier){
+	int chr;
+	unichar uchar[1];
+	NSString *keyStr;
+	int modMask;
+	NSMenuItem *menuItem;
+	if( gadget->internalclass!=GADGET_MENUITEM ) return;
+	modMask=0;
+	if( modifier & 1 ) modMask|=NSShiftKeyMask;
+	if( modifier & 2 ) modMask|=NSControlKeyMask;
+	if( modifier & 4 ) modMask|=NSAlternateKeyMask;
+	if( modifier & 8 ) modMask|=NSCommandKeyMask;
+	menuItem=(NSMenuItem*)gadget->handle;
+	chr=keyToChar( key );
+	if( !chr ) {
+		[menuItem setKeyEquivalent:@""];
+		[menuItem setKeyEquivalentModifierMask:0];
+		return;
+	}
+	uchar[0]=chr;
+	keyStr=[NSString stringWithCharacters:uchar length:1];
+	[menuItem setKeyEquivalent:keyStr];
+	[menuItem setKeyEquivalentModifierMask:modMask];
+}

+ 1030 - 0
cocoamaxgui.mod/cocoagui.bmx

@@ -0,0 +1,1030 @@
+Strict
+
+Import MaxGUI.MaxGUI
+Import Pub.MacOs
+
+Import "-framework WebKit"
+Import "cocoa.macos.m"
+
+Extern
+	
+	Function bbSystemEmitOSEvent( nsevent:Byte Ptr,nsview:Byte Ptr,source:Object )
+	
+	Function ScheduleEventDispatch()
+	
+	Function NSBegin()
+	Function NSEnd()
+	
+	Function NSGetSysColor(colorindex,r:Int Ptr,g:Int Ptr, b:Int Ptr)
+	Function NSColorRequester(r,g,b)
+	Function NSSetPointer(shape)
+	
+	Function NSCharWidth(font:Byte Ptr,charcode)
+	' create
+	Function NSInitGadget(gadget:TNSGadget)
+	' generic
+	Function NSActiveGadget()
+	Function NSFreeGadget(gadget:TNSGadget)
+	Function NSClientWidth(gadget:TNSGadget)
+	Function NSClientHeight(gadget:TNSGadget)
+	Function NSRethink(gadget:TNSGadget)
+	Function NSRedraw(gadget:TNSGadget)
+	Function NSActivate(gadget:TNSGadget,code)
+	Function NSState(gadget:TNSGadget)
+	Function NSShow(gadget:TNSGadget,bool)
+	Function NSEnable(gadget:TNSGadget,bool)
+	Function NSCheck(gadget:TNSGadget,bool)
+	Function NSSetNextView(gadget:TNSGadget,nextgadget:TNSGadget)
+	Function NSSetHotKey(gadget:TNSGadget,hotkey,modifier)
+	Function NSSetTooltip(gadget:TNSGadget,tip$)
+	Function NSGetTooltip$(gadget:TNSGadget)
+	Function NSSuperview:Byte Ptr(view:Byte Ptr)
+	' window
+	Function NSSetStatus(gadget:TNSGadget,text$,pos)
+	Function NSSetMinimumSize(gadget:TNSGadget,width,height)
+	Function NSSetMaximumSize(gadget:TNSGadget,width,height)
+	Function NSPopupMenu(gadget:TNSGadget,menu:TNSGadget)
+	' font
+	Function NSRequestFont:Byte Ptr(font:Byte Ptr)
+	Function NSLoadFont:Byte Ptr(name$,size:Double,flags)
+	Function NSGetDefaultFont:Byte Ptr()
+	Function NSSetFont(gadget:TNSGadget,font:Byte Ptr)
+	Function NSFontName$(font:Byte Ptr)
+	Function NSFontStyle(font:Byte Ptr)
+	Function NSFontSize:Double(font:Byte Ptr)
+	' items
+	Function NSClearItems(gadget:TNSGadget)
+	Function NSAddItem(gadget:TNSGadget,index,text$,tip$,image:Byte Ptr,extra:Object)
+	Function NSSetItem(gadget:TNSGadget,index,text$,tip$,image:Byte Ptr,extra:Object)
+	Function NSRemoveItem(gadget:TNSGadget,index)
+	Function NSSelectItem(gadget:TNSGadget,index,state)
+	Function NSSelectedItem(gadget:TNSGadget,index)
+	Function NSSelectedNode:Byte Ptr(gadget:TNSGadget)
+	' text
+	Function NSSetText(gadget:TNSGadget,text$)
+	Function NSGetText$(gadget:TNSGadget)
+	Function NSReplaceText(gadget:TNSGadget,pos,length,text$,units)
+	Function NSAddText(gadget:TNSGadget,text$)
+	Function NSAreaText$(gadget:TNSGadget,pos,length,units)
+	Function NSAreaLen(gadget:TNSGadget,units)
+	Function NSLockText(gadget:TNSGadget)
+	Function NSUnlockText(gadget:TNSGadget)
+	Function NSSetTabs(gadget:TNSGadget,tabwidth)
+	Function NSSetMargins(gadget:TNSGadget,leftmargin)
+	Function NSSetColor(gadget:TNSGadget,r,g,b)
+	Function NSRemoveColor(gadget:TNSGadget)
+	Function NSSetAlpha(gadget:TNSGadget,alpha#)
+	Function NSSetTextColor(gadget:TNSGadget,r,g,b)
+	Function NSGetCursorPos(gadget:TNSGadget,units)
+	Function NSGetSelectionlength(gadget:TNSGadget,units)
+	Function NSSetStyle(gadget:TNSGadget,r,g,b,flags,pos,length,units)	
+	Function NSSetSelection(gadget:TNSGadget,pos,length,units)
+	Function NSCharAt(gadget:TNSGadget,line)
+	Function NSLineAt(gadget:TNSGadget,index)
+	Function NSCharX(gadget:TGadget,char)
+	Function NSCharY(gadget:TGadget,char)
+	' prop
+	Function NSSetValue(gadget:TNSGadget,value#)
+	' slider
+	Function NSSetSlider(gadget:TNSGadget,value:Double,small:Double,big:Double)
+	Function NSGetSlider:Double(gadget:TNSGadget)
+	' images for panels and nodes
+	Function NSPixmapImage:Byte Ptr(image:TPixmap)
+	Function NSSetImage(gadget:TNSGadget,nsimage:Byte Ptr,flags)
+	Function NSSetIcon(gadget:TNSGadget,nsimage:Byte Ptr)
+	Function NSCountKids(gadget:TNSGadget)
+	' html
+	Function NSRun$(gadget:TNSGadget,script$)
+	' misc
+	Function NSRelease(nsobject:Byte Ptr)
+	' system
+	Function NSGetUserName$()
+	Function NSGetComputerName$()
+	
+EndExtern
+
+Global GadgetMap:TMap=New TMap
+
+maxgui_driver=New TCocoaMaxGuiDriver
+
+Type TCocoaMaxGUIDriver Extends TMaxGUIDriver
+	
+	Global CocoaGuiFont:TCocoaGuiFont
+	
+	Method New()
+		NSBegin
+		atexit_ NSEnd
+		If Not CocoaGuiFont Then CocoaGuiFont = TCocoaGuiFont(LibraryFont(GUIFONT_SYSTEM))
+	End Method
+	
+	Method UserName$()
+		Return NSGetUserName$()
+	End Method
+	
+	Method ComputerName$()
+		Return NSGetComputerName$()
+	End Method
+		
+	Method CreateGadget:TGadget(internalclass,name$,x,y,w,h,group:TGadget,style)
+		Local p,hotkey
+		If internalclass=GADGET_MENUITEM
+			name=name.Replace("&","")
+		ElseIf internalclass=GADGET_BUTTON
+			p=name.Find("&")
+			If p>-1
+'				hotkey=Asc(name[p..p+1]) 'to do - convert and call SetHotKey before return
+				name=name[..p]+name[p+1..]
+			EndIf
+		ElseIf internalclass=GADGET_TOOLBAR
+			Global _toolbarcount
+			_toolbarcount:+1
+			name="Toolbar"+_toolbarcount
+		EndIf
+		Local gadget:TNSGadget = TNSGadget.Create(internalclass,name,x,y,w,h,TNSGadget(group),style)
+		If internalclass<>GADGET_WINDOW And internalclass<>GADGET_MENUITEM And internalclass<>GADGET_DESKTOP
+			gadget.SetLayout EDGE_CENTERED,EDGE_CENTERED,EDGE_CENTERED,EDGE_CENTERED
+		EndIf
+		If group Then gadget._SetParent group
+		gadget.SetTextColor(0,0,0)
+		gadget.LinkView
+		Return gadget	
+	End Method
+		
+	Function CreateFont:TGuiFont(handle:Byte Ptr,flags=FONT_NORMAL)
+		Local font:TGuiFont = New TCocoaGuiFont
+		font.handle = handle
+		font.name = NSFontName(handle)
+		font.size = NSFontSize(handle)
+		font.style = NSFontStyle(handle)|flags
+		Return font
+	EndFunction
+
+	Method LoadFont:TGuiFont(name$,size,flags)
+		Return CreateFont(NSLoadFont(name,Double(size),flags),flags)
+	End Method
+	
+	Method LoadFontWithDouble:TGuiFont(name$,size:Double,flags)
+		Return CreateFont(NSLoadFont(name,size,flags),flags)
+	End Method
+	
+	Method LibraryFont:TGuiFont( pFontType% = GUIFONT_SYSTEM, pFontSize:Double = 0, pFontStyle% = FONT_NORMAL )
+		If pFontType = GUIFONT_SYSTEM Then
+			Local tmpHandle:Byte Ptr = NSGetDefaultFont()
+			If pFontSize <= 0 Then pFontSize = NSFontSize(tmpHandle)
+			Return LoadFontWithDouble( NSFontName(tmpHandle), pFontSize, NSFontStyle(tmpHandle)|pFontStyle )
+		Else
+			Return Super.LibraryFont( pFontType, pFontSize, pFontStyle )
+		EndIf
+	EndMethod
+	
+	Method LookupColor( colorindex:Int, red:Byte Var, green:Byte Var, blue:Byte Var )
+		
+		Local r, g, b
+		
+		If NSGetSysColor( colorindex, Varptr r, Varptr g, Varptr b )
+			red = r & $FF
+			green = g & $FF
+			blue = b & $FF
+			Return True
+		EndIf
+		
+		Return Super.LookupColor( colorindex, red, green, blue )
+				
+	EndMethod
+	
+	Method RequestColor(r,g,b)
+		Return NSColorRequester(r,g,b)
+	End Method
+	
+	Method RequestFont:TGuiFont(font:TGuiFont)
+		Local	handle:Byte Ptr
+		If font handle=font.handle
+		handle=NSRequestFont(handle)
+		If handle
+			If font And handle=font.handle Return font
+			Return CreateFont(handle)
+		EndIf
+	End Method
+	
+	Method SetPointer(shape)
+		NSSetPointer shape
+	End Method		
+	
+	Method ActiveGadget:TGadget()
+		PollSystem()
+		Local handle:Byte Ptr = NSActiveGadget()
+		If handle Return GadgetFromHandle(handle)
+	End Method
+	
+	Method LoadIconStrip:TIconStrip(source:Object)
+		Return TCocoaIconStrip.Create(source)
+	End Method
+End Type
+
+Function GadgetFromHandle:TNSGadget( handle:Byte Ptr )
+	Return TNSGadget( GadgetMap.ValueForKey( TPtrWrapper.Create(handle) ) )
+End Function
+
+Function EmitCocoaOSEvent( event:Byte Ptr,handle:Byte Ptr,gadget:Object = Null )
+	Local owner:TGadget = TGadget(gadget)
+	If Not owner Then owner = GadgetFromHandle( handle )
+	If owner Then
+		While owner.source
+			owner = owner.source
+		Wend
+	EndIf
+	bbSystemEmitOSEvent event,handle,owner
+End Function
+
+Function EmitCocoaMouseEvent( event:Byte Ptr, handle:Byte Ptr )
+	Local gadget:TNSGadget
+'	While handle
+		gadget = GadgetFromHandle( handle )
+		If gadget Then
+			If (gadget.sensitivity & SENSITIZE_MOUSE) Then
+				EmitCocoaOSEvent( event, handle, gadget )
+				Return 1
+			EndIf
+			Return 0
+		EndIf
+'		handle = NSSuperview(handle)
+'	Wend
+End Function
+
+Function EmitCocoaKeyEvent( event:Byte Ptr, handle:Byte Ptr )
+	Local gadget:TNSGadget
+	While handle
+		gadget = GadgetFromHandle( handle )
+		If gadget Then
+			If (gadget.sensitivity & SENSITIZE_KEYS) Then
+				EmitCocoaOSEvent( event, handle, gadget )
+				Return 1
+			EndIf
+			Return 0
+		EndIf
+		handle = NSSuperview(handle)
+	Wend
+End Function
+
+?Not x64
+Function PostCocoaGuiEvent( id,handle:Byte Ptr,data,mods,x,y,extra:Object )
+?x64
+Function PostCocoaGuiEvent( id,handle:Byte Ptr,data:Long,mods,x,y,extra:Object )
+?
+	'DebugLog "PostCocoaGuiEvent"
+	Local gadget:TNSGadget
+	
+	DispatchGuiEvents()
+	
+	If handle Then
+		
+		gadget = GadgetFromHandle(handle)
+		
+		If gadget Then
+			
+			Select gadget.internalclass
+				Case GADGET_TREEVIEW
+					extra=GadgetFromHandle(data)
+					data = 0
+			EndSelect
+			
+			Select id
+				Case EVENT_WINDOWSIZE
+					If gadget.width <> x Or gadget.height <> y Then
+						gadget.SetRect gadget.xpos,gadget.ypos,x,y
+						gadget.LayoutKids
+					Else
+						Return
+					EndIf
+					
+				Case EVENT_WINDOWMOVE
+					If gadget.xpos <> x Or gadget.ypos <> y Then
+						gadget.SetRect x,y,gadget.width,gadget.height
+					Else
+						Return
+					EndIf
+					
+				Case EVENT_MENUACTION
+					extra=TNSGadget.popupextra
+					TNSGadget.popupextra=Null
+					
+				Case EVENT_GADGETACTION
+					
+					Select gadget.internalclass
+						Case GADGET_SLIDER
+							Local oldValue:Int = gadget.GetProp()
+							If data Then
+								Select (gadget.style&(SLIDER_SCROLLBAR|SLIDER_TRACKBAR|SLIDER_STEPPER))
+									Case SLIDER_SCROLLBAR
+										If data > 1 Then
+											data = gadget.small
+										ElseIf data < -1 Then
+											data = -gadget.small
+										EndIf
+								EndSelect
+								gadget.SetProp(oldValue+data)
+								data=gadget.GetProp()
+								If (data = oldValue) Then Return
+							Else
+								data=gadget.GetProp()
+							EndIf
+						Case GADGET_LISTBOX, GADGET_COMBOBOX, GADGET_TABBER
+							If (data > -1 And data < gadget.items.length) extra=gadget.ItemExtra(data)
+						Case GADGET_BUTTON
+							Select (gadget.style&7)
+								Case BUTTON_CHECKBOX
+									If ButtonState(gadget) = CHECK_INDETERMINATE Then SetButtonState(gadget, CHECK_SELECTED )
+								Case BUTTON_RADIO
+									If (gadget.style&BUTTON_PUSH) Then SetButtonState(gadget,CHECK_SELECTED)
+									gadget.ExcludeOthers()
+							EndSelect
+							data=ButtonState(gadget)
+						Case GADGET_TOOLBAR
+							If data>-1 Then
+								extra=gadget.ItemExtra(data)
+								If (gadget.ItemFlags(data)&GADGETITEM_TOGGLE) Then gadget.SelectItem(data,2)
+							EndIf
+					EndSelect
+					
+				Case EVENT_GADGETSELECT, EVENT_GADGETMENU
+					Select gadget.internalclass
+						Case GADGET_LISTBOX, GADGET_COMBOBOX, GADGET_TABBER
+							If data>-1 Then extra=gadget.ItemExtra(data)
+					EndSelect
+					
+				Case EVENT_GADGETLOSTFOCUS
+				
+					QueueGuiEvent id,gadget,data,mods,x,y,extra
+					ScheduleEventDispatch()
+					Return
+					
+			EndSelect
+		EndIf
+	
+	EndIf
+	
+	PostGuiEvent id,gadget,data,mods,x,y,extra
+	
+EndFunction
+
+Function FilterKeyDown( handle:Byte Ptr,key,mods )
+	Local source:TNSGadget
+	If handle
+		source=GadgetFromHandle(handle)
+	EndIf
+	If source And source.eventfilter<>Null
+		Local event:TEvent=CreateEvent(EVENT_KEYDOWN,source,key,mods)
+		Return source.eventfilter(event,source.context)
+	EndIf
+	Return 1
+End Function
+
+Function FilterChar( handle:Byte Ptr,key,mods )
+	Local source:TNSGadget
+	Select key
+		' Return true if they are arrow key characters
+		Case 63232, 63233, 63234, 63235
+			Return 1
+	EndSelect
+	If handle
+		source=GadgetFromHandle(handle)
+	EndIf
+	If source And source.eventfilter<>Null 'Return source.charfilter(char,mods,source.context)
+		Local event:TEvent=CreateEvent(EVENT_KEYCHAR,source,key,mods)
+		Return source.eventfilter(event,source.context)
+	EndIf
+	Return 1
+End Function
+
+Type TNSGadget Extends TGadget
+	
+	Field internalclass, origclass	'internalclass: Class the Cocoa driver uses to draw the gadget, origclass: Expected class to be returned by Class() method
+	Field handle:Byte Ptr
+	Field view:Byte Ptr, textcolor:Byte Ptr	'view: NSView handle, textcolor: NSColor handle for Objective-C code
+	Field intFontStyle	'Copy of font.style used by cocoa.macos.m to handle underlining/strikethrough etc. that isn't included in NSFont
+	Field pixmap:TPixmap
+	Field icons:TCocoaIconStrip
+	Field small, big
+	Field canvas:TGraphics
+	Field font:TCocoaGuiFont
+	Field enabled:Int = True, forceDisable:Int = False
+
+' main factory command
+
+	Function Create:TNSGadget(internalclass,text$,x,y,w,h,group:TGadget,style)
+		
+		Local gadget:TNSGadget = New TNSGadget
+		gadget.origclass = internalclass
+		gadget.internalclass = internalclass
+		
+		If Not group And internalclass<>GADGET_DESKTOP Then group = Desktop()
+		gadget.parent = group
+		
+		gadget.name = text
+		gadget.SetRect x,y,w,h	'setarea
+		gadget.style = style
+		gadget.font = TCocoaMaxGUIDriver.CocoaGUIFont
+		
+		If TNSGadget(group) Then
+			gadget.forceDisable = Not (TNSGadget(group).enabled And Not TNSGadget(group).forceDisable)
+		EndIf
+		
+		NSInitGadget gadget
+
+		If internalclass<>GADGET_TOOLBAR 'toolbars retain name to key insertgadgetitem
+			gadget.name = Null
+		EndIf
+		
+		GadgetMap.Insert TPtrWrapper.Create(gadget.handle),gadget
+		If gadget.view And gadget.handle <> gadget.view Then
+			GadgetMap.Insert TPtrWrapper.Create(gadget.view),gadget
+		EndIf
+		
+		If internalclass=GADGET_SLIDER Then gadget.SetRange(1,10)
+		gadget.LockLayout()
+		
+		If (internalclass=GADGET_WINDOW) And (style&WINDOW_STATUS) Then
+			If (style&WINDOW_CLIENTCOORDS) Then
+				gadget.SetMinimumSize(25,0)
+			Else
+				gadget.SetMinimumSize(25,70)
+			EndIf
+		EndIf
+		
+		If LocalizationMode() & LOCALIZATION_OVERRIDE Then LocalizeGadget(gadget,text,"")
+		
+		gadget.SetEnabled(gadget.enabled)
+		
+		Return gadget
+		
+	End Function
+	
+	Method Class()
+		Return origclass
+	EndMethod
+	
+	Function ToView:TNSGadget(value:Object)
+		Local	view:TNSGadget = TNSGadget(value)
+		If Not view Return
+		Select view.internalclass
+			Case GADGET_DESKTOP,GADGET_WINDOW,GADGET_TOOLBAR,GADGET_LABEL,GADGET_PROGBAR,GADGET_MENUITEM,GADGET_NODE
+				Return Null
+		End Select
+		Return view
+	End Function
+	
+	Method LinkView()
+		Local	First:TNSGadget
+		Local	prev:TNSGadget
+		Local	i,n
+
+		If Not parent Return
+		If Not ToView(Self) Return
+		n=parent.kids.count()-1
+		If n<0 Return
+' find first view in family
+		For i=0 Until  n
+			First=ToView(parent.kids.ValueAtIndex(i))
+			If First Exit
+		Next
+		If Not First Return
+' find last view in family
+		For i=n-1 To 0 Step -1
+			prev=ToView(parent.kids.ValueAtIndex(i))
+			If prev Exit
+		Next
+		If Not prev Return
+		NSSetNextView(prev,Self)
+		NSSetNextView(Self,First)
+	End Method
+	
+	Method Delete()
+		Free()
+	End Method
+	
+' generic gadget commands
+
+	Method Query:Byte Ptr(queryid)
+		Select queryid
+			Case QUERY_NSVIEW
+				Return handle
+			Case QUERY_NSVIEW_CLIENT
+				Return view
+		End Select				
+	End Method
+
+	Method Free()
+		If handle Then
+			
+			If canvas Then canvas.close
+			
+			GadgetMap.Remove TPtrWrapper.Create(handle)
+			If view And handle <> view Then
+				GadgetMap.Remove TPtrWrapper.Create(view)
+				view = Null
+			EndIf
+				
+			If parent Then
+				parent.kids.Remove Self
+			End If
+			
+			NSFreeGadget Self
+			font = Null
+			
+			handle = Null
+			
+		EndIf
+	End Method
+
+	Method Rethink()			'resize	- was recursive
+		NSRethink( Self )
+	End Method
+		
+	Method ClientWidth()
+		Return Max(NSClientWidth(Self),0)
+	End Method
+	
+	Method ClientHeight()
+		Return Max(NSClientHeight(Self),0)
+	End Method
+	
+	Method Activate(cmd)
+		NSActivate( Self, cmd )
+	End Method
+	
+	Method State()
+		Local tmpState:Int = NSState(Self)&~STATE_DISABLED
+		If Not enabled Then tmpState:|STATE_DISABLED
+		Return tmpState
+	End Method
+	
+	Method SetShow(bool)
+		NSShow( Self, bool )
+	End Method
+
+	Method SetText(msg$)
+		If internalclass=GADGET_HTMLVIEW
+			Local	anchor$,a
+			a=msg.Find("#")
+			If a<>-1 anchor=msg[a..];msg=msg[..a]
+			If msg[0..7].ToLower()<>"http://" And msg[0..7].ToLower()<>"file://"
+				If FileType(msg)
+					msg="file://"+msg
+				Else
+					msg="http://"+msg
+				EndIf
+			EndIf
+			msg:+anchor
+			msg=msg.Replace(" ","%20")
+		ElseIf internalclass=GADGET_MENUITEM
+			msg=msg.Replace("&", "")
+		EndIf
+		NSSetText Self,msg
+	End Method
+	
+	Method Run$(msg$)
+		If internalclass=GADGET_HTMLVIEW Return NSRun(Self,msg)
+	End Method
+
+	Method GetText$()
+		Return NSGetText(Self)
+	End Method
+
+	Method SetFont(pFont:TGuiFont)
+		If Not TCocoaGuiFont(pFont) Then pFont = TCocoaMaxGUIDriver.CocoaGuiFont
+		font = TCocoaGuiFont(pFont)
+		intFontStyle = font.style
+		NSSetFont( Self, font.handle )
+	End Method
+
+	Method SetColor(r,g,b)
+		NSSetColor Self,r,g,b
+	End Method
+
+	Method RemoveColor()
+		NSRemoveColor Self
+	End Method
+
+	Method SetAlpha(alpha#)
+		NSSetAlpha Self,alpha
+	End Method
+	
+	Method SetTextColor(r,g,b)
+		NSSetTextColor Self,r,g,b
+	End Method
+	
+	Method SetPixmap(pixmap:TPixmap,flags)
+		Local	nsimage:Byte Ptr, x
+		If pixmap
+			Select pixmap.format
+				Case PF_I8,PF_BGR888
+					pixmap=pixmap.Convert( PF_RGB888 )
+				Case PF_A8,PF_BGRA8888
+					pixmap=pixmap.Convert( PF_RGBA8888 )
+			End Select
+			
+			If AlphaBitsPerPixel[ pixmap.format ]
+				For Local y=0 Until pixmap.height
+					For x=0 Until pixmap.width
+						Local argb=pixmap.ReadPixel( x,y )
+						pixmap.WritePixel x,y,premult(argb)
+					Next
+				Next
+			EndIf
+			nsimage=NSPixmapImage(pixmap)
+		EndIf
+		NSSetImage(Self,nsimage,flags)
+	End Method
+	
+	Method SetTooltip(pTip$)
+		Select internalclass
+			Case GADGET_WINDOW, GADGET_DESKTOP, GADGET_LISTBOX, GADGET_MENUITEM, GADGET_TOOLBAR, GADGET_TABBER, GADGET_NODE
+			Default;Return NSSetTooltip( Self, pTip )
+		EndSelect
+	EndMethod
+	
+	Method GetTooltip$()
+		Select internalclass
+			Case GADGET_WINDOW, GADGET_DESKTOP, GADGET_LISTBOX, GADGET_MENUITEM, GADGET_TOOLBAR, GADGET_TABBER, GADGET_NODE
+			Default;Return NSGetTooltip( Self )
+		EndSelect
+	EndMethod
+	
+	Method ExcludeOthers()
+		For Local g:TNSGadget = EachIn parent.kids
+			If g<>Self And g.internalclass=GADGET_BUTTON And (g.style&7)=BUTTON_RADIO
+				NSCheck g,False
+			EndIf
+		Next
+	End Method
+
+	Method SetSelected(bool)
+		NSCheck Self,bool
+		If internalclass=GADGET_BUTTON And (style&7)=BUTTON_RADIO And bool
+			ExcludeOthers
+		EndIf
+	End Method
+	
+	Method SetEnabled(enable)
+		Local old:Int = enabled And Not forceDisable
+		enabled = enable
+		If Class() = GADGET_WINDOW Then
+			NSEnable Self, enable
+		Else
+			enable = enable And Not forceDisable
+			NSEnable Self, enable
+			If (enable <> old) Then
+				For Local tmpGadget:TNSGadget = EachIn kids
+					tmpGadget.forceDisable = Not enable
+					If tmpGadget.Class() <> GADGET_WINDOW Then tmpGadget.SetEnabled(tmpGadget.enabled)
+				Next
+			EndIf
+		EndIf
+	End Method
+	
+	Method SetHotKey(hotkey,modifier)
+		NSSetHotKey Self,hotkey,modifier
+	End Method
+	
+' window commands
+	
+	Field _statustext$
+	
+	Method GetStatusText$()
+		Return _statustext
+	EndMethod
+	
+	Method SetStatusText(msg$)
+		Local	t,m0$,m1$,m2$
+		_statustext = msg
+		m0=msg
+		t=m0.find("~t");If t<>-1 m1=m0[t+1..];m0=m0[..t];
+		t=m1.find("~t");If t<>-1 m2=m1[t+1..];m1=m1[..t];		
+		NSSetStatus Self,m0,0
+		NSSetStatus Self,m1,1
+		NSSetStatus Self,m2,2
+	End Method
+	
+	Method GetMenu:TGadget()
+		Return Self
+	End Method
+
+	Global popupextra:Object
+	
+	Method PopupMenu(menu:TGadget,extra:Object)
+		popupextra=extra
+		NSPopupMenu Self,TNSGadget(menu)
+	End Method
+	
+	Method UpdateMenu()
+	End Method
+	
+	Method SetMinimumSize(w,h)
+		NSSetMinimumSize Self,w,h
+	End Method
+	
+	Method SetMaximumSize(w,h)
+		NSSetMaximumSize Self,w,h
+	End Method
+
+	Method SetIconStrip(iconstrip:TIconStrip)
+		icons=TCocoaIconStrip(iconstrip)
+	End Method
+
+' item handling commands
+
+	Method ClearListItems()
+		NSClearItems Self
+	End Method
+
+	Method InsertListItem(index,item$,tip$,icon,extra:Object)
+		Local	image:Byte Ptr
+		If internalclass=GADGET_TOOLBAR
+			item=name+":"+index
+		EndIf
+		If icons And icon>=0 image=icons.images[icon]
+		NSAddItem Self,index,item,tip,image,extra
+	End Method
+	
+	Method SetListItem(index,item$,tip$,icon,extra:Object)
+		Local	image:Byte Ptr
+		If internalclass=GADGET_TOOLBAR
+			item=name+":"+index
+		EndIf
+		If icons And icon>=0 image=icons.images[icon]
+		NSSetItem Self,index,item,tip,image,extra
+	End Method
+	
+	Method RemoveListItem(index)
+		NSRemoveItem Self,index
+	End Method
+	
+	Method SetListItemState(index,state)
+		NSSelectItem Self,index,state
+	End Method
+	
+	Method ListItemState(index)
+ 		Return NSSelectedItem(Self,index)
+	End Method
+	
+' treeview commands	
+
+	Method RootNode:TGadget()
+		Return Self
+	End Method
+	
+	Method SetIcon(icon)
+		Local	p:TNSGadget
+		p=Self
+		While p
+			If p.icons Exit
+			p=TNSGadget(p.parent)
+		Wend
+		If p
+			If icon>-1
+				NSSetIcon Self,p.icons.images[icon]		
+			Else
+				NSSetIcon Self,Null		
+			EndIf
+		EndIf				
+	End Method
+	
+	Method InsertNode:TGadget(index,text$,icon)
+		Local	node:TNSGadget = Create(GADGET_NODE,text,0,0,0,0,Self,index)
+		node.SetIcon icon
+		node._SetParent Self
+		Return node
+	End Method
+	
+	Method ModifyNode(text$,icon)
+		NSSetText Self,text
+		SetIcon icon
+	End Method
+
+	Method SelectedNode:TGadget()
+		Local	index:Byte Ptr = NSSelectedNode(Self)
+		If (index) Return GadgetFromHandle(index)
+	End Method
+
+	Method CountKids()
+		Return NSCountKids(Self)
+	End Method
+
+' textarea commands
+
+	Method ReplaceText(pos,length,text$,units)
+?debug
+		If pos<0 Or pos+length>AreaLen(units) Throw "Illegal Range"
+?	
+		NSReplaceText Self,pos,length,text$,units
+	End Method
+
+	Method AddText(text$)
+		NSAddText Self,text
+	End Method
+
+	Method AreaText$(pos,length,units)
+?debug
+		If pos<0 Or pos+length>AreaLen(units) Throw "Illegal Range"
+?	
+		Return NSAreaText(Self,pos,length,units)
+	End Method
+
+	Method AreaLen(units)
+		Return NSAreaLen(Self,units)
+	End Method
+
+	Method LockText()
+		NSLockText Self
+	End Method
+
+	Method UnlockText()
+		NSUnlockText Self
+	End Method
+
+	Method SetTabs(tabwidth)
+		NSSetTabs Self,tabwidth
+	End Method
+
+	Method SetMargins(leftmargin)
+		NSSetMargins Self,leftmargin
+	End Method
+
+	Method GetCursorPos(units)
+		Return NSGetCursorPos(Self,units)
+	End Method
+
+	Method GetSelectionLength(units)
+		Return NSGetSelectionLength(Self,units)
+	End Method
+
+	Method SetStyle(r,g,b,flags,pos,length,units) 	
+?debug
+		If pos<0 Or pos+length>AreaLen(units) Throw "Illegal Range"
+?	
+		If length NSSetStyle Self,r,g,b,flags,pos,length,units
+	End Method
+
+	Method SetSelection(pos,length,units)
+?debug
+		If pos<0 Or pos+length>AreaLen(units) Throw "Illegal Range"
+?	
+		NSSetSelection Self,pos,length,units
+	End Method
+
+	Method CharAt(line)
+?debug
+		If line<0 Or line>AreaLen(TEXTAREA_LINES) Throw "Parameter Out Of Range"
+?	
+		Return NSCharAt(Self,line)
+	End Method
+
+	Method LineAt(index)
+?debug
+		If index<0 Or index>AreaLen(TEXTAREA_CHARS) Throw "Parameter Out Of Range"
+?	
+		Return NSLineAt(Self,index)
+	End Method
+	
+	Method CharX(char)
+		Return NSCharX(Self,char)
+	EndMethod
+	
+	Method CharY(char)
+		Return NSCharY(Self,char)
+	EndMethod
+	
+' progbar
+	
+	Method SetValue(value#)
+		NSSetValue Self,value
+	End Method
+
+' slider / scrollbar
+
+	Method SetRange(_small,_big)
+		small=_small
+		big=_big
+		NSSetSlider Self,GetProp(),small,big
+	End Method
+	
+	Method SetProp(pos)
+		NSSetSlider Self,pos,small,big
+	End Method
+
+	Method GetProp()
+		Local value:Double = NSGetSlider(Self)
+		If Not (style&(SLIDER_TRACKBAR|SLIDER_STEPPER))
+			value:*(big-small)
+			If value>big-small value=big-small
+		EndIf
+		Return Int(value+0.5:Double)
+	End Method
+	
+' canvas
+
+	Method AttachGraphics:TGraphics( flags )
+		canvas=brl.Graphics.AttachGraphics( Query(QUERY_NSVIEW_CLIENT),flags )
+	End Method
+	
+	Method CanvasGraphics:TGraphics()
+		Return canvas
+	End Method
+
+End Type
+
+
+Type TCocoaIconStrip Extends TIconStrip
+	
+	Field images:Byte Ptr[]
+	
+	Function IsNotBlank(pixmap:TPixmap)
+		Local y, h = pixmap.height
+		Local c = pixmap.ReadPixel(0,0) 			
+		For Local x = 0 Until h
+			For y = 0 Until h
+				If pixmap.ReadPixel(x,y)<>c Return True
+			Next
+		Next
+	End Function
+		
+	Function Create:TCocoaIconStrip(source:Object)
+		Local	icons:TCocoaIconStrip
+		Local	pixmap:TPixmap,pix:TPixmap
+		Local	n,x,w
+		pixmap=TPixmap(source)
+		If Not pixmap pixmap=LoadPixmap(source)
+		If Not pixmap Return		
+		Select pixmap.format
+		Case PF_I8,PF_BGR888
+			pixmap=pixmap.Convert( PF_RGB888 )
+		Case PF_A8,PF_BGRA8888
+			pixmap=pixmap.Convert( PF_RGBA8888 )
+		End Select
+		
+		If AlphaBitsPerPixel[ pixmap.format ]
+			For Local y=0 Until pixmap.height
+				For x=0 Until pixmap.width
+					Local argb=pixmap.ReadPixel( x,y )
+					pixmap.WritePixel x,y,premult(argb)
+				Next
+			Next
+		EndIf
+
+		n=pixmap.width/pixmap.height;
+		If n=0 Return		
+		icons=New TCocoaIconStrip
+		icons.pixmap=pixmap
+		icons.count=n
+		icons.images=New Byte Ptr[n]
+		w=pixmap.width/n			
+		For x=0 Until n
+			pix=pixmap.Window(x*w,0,w,pixmap.height)
+			If IsNotBlank(pix) icons.images[x]=NSPixmapImage(pix)
+		Next
+		Return icons
+	EndFunction	
+	
+EndType
+
+Type TCocoaGuiFont Extends TGuiFont
+	
+	Method Delete()
+		If handle Then
+			NSRelease(handle)
+			handle = 0
+		EndIf
+	EndMethod
+	
+	Method CharWidth(char)
+		If handle
+			Return NSCharWidth(handle,char)
+		EndIf
+		Return 0
+	EndMethod 
+		
+EndType
+
+Type TPtrWrapper Final
+	Field value:Byte Ptr
+	Function Create:TPtrWrapper(value:Byte Ptr)
+		Local tmpWrapper:TPtrWrapper = New TPtrWrapper
+		tmpWrapper.value = value
+		Return tmpWrapper
+	EndFunction
+	Method Compare( o:Object )
+		Local c:TPtrWrapper = TPtrWrapper(o)
+		If c Then Return (value - c.value)
+		Return Super.Compare(o)
+	EndMethod
+	Method ToString$()
+		'Return value
+	EndMethod
+EndType
+
+Private
+
+Function premult(argb)
+	Local a = ((argb Shr 24) & $FF)
+	Return ((((argb&$ff00ff)*a)Shr 8)&$ff00ff)|((((argb&$ff00)*a)Shr 8)&$ff00)|(a Shl 24)
+End Function

+ 232 - 0
cocoamaxgui.mod/cocoamaxgui.bmx

@@ -0,0 +1,232 @@
+Rem
+bbdoc: MaxGUI Drivers/CocoaMaxGUI
+about:
+This Module provides a Cocoa based #MaxGUI driver For Mac OS X.
+
++Notes
+[
+* Listbox item tooltips are only supported on Mac OS X 10.4 And higher.
+] 
+
+End Rem
+Module MaxGUI.CocoaMaxGUI
+
+Strict
+
+ModuleInfo "Version: 1.55B"
+ModuleInfo "Author: Simon Armstrong, Seb Hollington"
+ModuleInfo "License: zlib/libpng"
+ModuleInfo "Copyright: Blitz Research Ltd."
+
+ModuleInfo "History: 1.55 Dev"
+ModuleInfo "History: Added patch for blank toolbar items in Lion"
+ModuleInfo "History: Added UserName$ and ComputerName$ support"
+ModuleInfo "History: Stopped EmitCocoaMouseEvent from crashing htmlview"
+ModuleInfo "History: 1.54 Release"
+ModuleInfo "History: Added RemoveGadgetColor support"
+ModuleInfo "History: Removed use of NSPopoupButton for non editable ComboBoxes /topic=91200"
+ModuleInfo "History: Reduced ambiguous use of gadget.(arg)name$ /topic=91292"
+ModuleInfo "History: 1.53 Release"
+ModuleInfo "History: Added GetStatusText() implementation."
+ModuleInfo "History: 1.52b Release"
+ModuleInfo "History: Fixed several TextArea CTDs."
+ModuleInfo "History: 1.51 Release"
+ModuleInfo "History: skn3[ac]'s canvas EVENT_MOUSEUP firing fix."
+ModuleInfo "History: Added icon support to non-editable ComboBoxes."
+ModuleInfo "History: Fixed ComboBox events and implemented non-editable ComboBoxes as NSPopUpButtons."
+ModuleInfo "History: 1.50 Release"
+ModuleInfo "History: Added LookupColor() method to TCocoaMaxGUIDriver."
+ModuleInfo "History: 1.49b Release"
+ModuleInfo "History: Fixed EVENT_GADGETLOSTFOCUS interrupting modal drop-down boxes."
+ModuleInfo "History: 1.49 Release"
+ModuleInfo "History: Fixed SetTextAreaText style problem."
+ModuleInfo "History: Added support for thumb-size jumps for scroll-bars."
+ModuleInfo "History: 1.48b Release"
+ModuleInfo "History: Removed NSString helper functions, instead linking to those in Pub.MacOS."
+ModuleInfo "History: Swapped out NSInteger for (int) to avoid compile errors for OS X < 10.5."
+ModuleInfo "History: 1.48 Release"
+ModuleInfo "History: Fixed mouse and key events for various different gadgets."
+ModuleInfo "History: Added support for mouse wheel events."
+ModuleInfo "History: Fixed listbox tooltip crash."
+ModuleInfo "History: 1.47 Release"
+ModuleInfo "History: Fixed DeselectGadgetItem() for ListBox gadgets."
+ModuleInfo "History: Applied d-bug's NSScrollbar sizing fix."
+ModuleInfo "History: 1.46b Release"
+ModuleInfo "History: Swapped out deprecated selectItem() selectors for their selectItemIndexes() counterparts."
+ModuleInfo "History: 1.46 Release"
+ModuleInfo "History: Fixed panel pixmaps with alpha components."
+ModuleInfo "History: Fixed NSColorRequester()."
+ModuleInfo "History: 1.45 Release"
+ModuleInfo "History: Fixed event generation for canvas gadgets."
+ModuleInfo "History: Fixed the CanvasView setAlpha unrecognized selector error."
+ModuleInfo "History: 1.44 Release"
+ModuleInfo "History: Added explicit removal of NSLinkAttributeName in NSSetStyle()."
+ModuleInfo "History: Fixed NSScroller events."
+ModuleInfo "History: Swapped out deprecated float selectors for their double-precision counterparts."
+ModuleInfo "History: Disabled a few unwanted NSTextView features."
+ModuleInfo "History: Fixed progress bar NSState() crash."
+ModuleInfo "History: Disabling a panel should now grey out all of its children."
+ModuleInfo "History: Fixed a few issues concerning client areas and toolbars."
+ModuleInfo "History: Suppressed arrow keys EVENT_GADGETCHAR filter."
+ModuleInfo "History: Fixed group panel initial text setting."
+ModuleInfo "History: Fixed NSSetPointer through disableCursorRects calls."
+ModuleInfo "History: Fixed HTMLView navigation bugs, and added support for both style constants."
+ModuleInfo "History: Finished treeview icon support."
+ModuleInfo "History: Fixed listview/treeview scrollbar problems."
+ModuleInfo "History: Added recursive owner.source handling to EmitCocoaOSEvent."
+ModuleInfo "History: PanelViews now extend and use NSBox."
+ModuleInfo "History: Added separator for statusbar."
+ModuleInfo "History: Attempt to fix PANEL_SUNKENFRAME offset issues."
+ModuleInfo "History: LABEL_SUNKENFRAME alignment fix."
+ModuleInfo "History: Added TCocoaGuiFont and corresponding Delete() method."
+ModuleInfo "History: Attempt to fix button fonts and colors."
+ModuleInfo "History: Fixed ClearGadgetItems() for tabber."
+ModuleInfo "History: Fixed exception when freeing tabbers."
+ModuleInfo "History: 1.43 Release"
+ModuleInfo "History: Nodes should now be added to their parent's 'kids' list."
+ModuleInfo "History: 1.42 Release"
+ModuleInfo "History: Updated NSGadget struct in cocoa.macos.m with recent changes made to MaxGUI TGadget."
+ModuleInfo "History: 1.41 Release"
+ModuleInfo "History: Fixed clipping issue involving tabs with icons."
+ModuleInfo "History: Fixed strange combobox popup list behaviour when appearing over mouse-sensitive gadgets."
+ModuleInfo "History: Added EVENT_GADGETMENU for tabbers."
+ModuleInfo "History: Added maximum size restraint (26px) for comboboxes to avoid warnings on Leopard."
+ModuleInfo "History: Fixed crashes caused by changing NSFont pointers. Use GetFontHandle() to refresh."
+ModuleInfo "History: 1.40 Release"
+ModuleInfo "History: Added CharX() and CharY() methods for text areas."
+ModuleInfo "History: Fixed activation issues when windows are restored from a minimized state."
+ModuleInfo "History: Fixed drawing when PANELPIXMAP_FIT2 was used with the PANEL_BORDER flag."
+ModuleInfo "History: Fixed hidden child window behaviour (a problem causing the IDE Options window to show when restoring from the dock)."
+ModuleInfo "History: 1.39 Release"
+ModuleInfo "History: Fixed ACTIVATE_PRINT code for HTMLViews so that the page is printed instead of just the visible region."
+ModuleInfo "History: Added hack so that treeviews now have a horizontal scrollbar (if required)."
+ModuleInfo "History: Changed child window behaviour so that they are more like child windows in MaxGUI.Win32MaxGUIEx."
+ModuleInfo "History: Added several Window checks to determine if it is hidden before proceeding."
+ModuleInfo "History: Fixed textcolor memory access error in NSFreeGadget."
+ModuleInfo "History: Fixed NSGetText() for HTMLViews and NodeItems."
+ModuleInfo "History: Added new BUTTON_PUSH support for radio/checkboxes."
+ModuleInfo "History: Fixed FontStyle() so that it now returns values."
+ModuleInfo "History: Added LibraryFont() method to TCocoaMaxGUIDriver."
+ModuleInfo "History: 1.38 Release"
+ModuleInfo "History: Added new Class() method to return a gadget's class for the new GadgetClass() function."
+ModuleInfo "History: 1.37 Release"
+ModuleInfo "History: Fixed push, ok and cancel buttons returning alternate values from ButtonState() - now returns 0."
+ModuleInfo "History: NSState() and NSCheck() tweaked for CHECK_INDETERMINATE."
+ModuleInfo "History: Disabled text-areas should no longer allow you to select text."
+ModuleInfo "History: Fixed limited tabstops in textareas (now uses setDefaultTabInterval selector)."
+ModuleInfo "History: Cleaned up NSSetText(), NSGetText(), NSRedraw() and NSRethink()."
+ModuleInfo "History: Added label, button and text-field text colors."
+ModuleInfo "History: Added button, text-field and window background colors."
+ModuleInfo "History: Added SetSensitivity() and GetSensitivity() methods."
+ModuleInfo "History: 1.36 Release"
+ModuleInfo "History: Added GadgetText() support for more gadgets (e.g. buttons/menus etc.)."
+ModuleInfo "History: Improved handling of text-areas in NSState to avoid crash."
+ModuleInfo "History: Swapped tabber icon drawing code (so that it works)."
+ModuleInfo "History: Added finishing touch to tool-window support (thanks Brucey)!"
+ModuleInfo "History: Fixed TCocoaIconStrip to work with ExtractIconPixmapFromStrip()."
+ModuleInfo "History: Tidied up PostCocoaGUIEvent() and added item-extra to tabber events."
+ModuleInfo "History: 1.35 Release"
+ModuleInfo "History: Added SetMaximumSize method to TNSGadget for possible future implementation of SetMaxWindowSize()."
+ModuleInfo "History: Added gadget font support for Buttons, Listboxes, Treeviews and Comboboxes."
+ModuleInfo "History: Added a workaround for missing setEnabled responder on textareas."
+ModuleInfo "History: Added Koriolis's fix for read-only text-areas in NSGetCursorPos() and NSGetSelectionlength()."
+ModuleInfo "History: Added SetGadgetTooltip() support for non-item based gadgets."
+ModuleInfo "History: Added Brucey's icon support for buttons and menus using SetGadgetPixmap()."
+ModuleInfo "History: Added possible fix for app crashing when popup-menus are created with no text."
+ModuleInfo "History: Added possible fix for GadgetDisabled() on certain gadgets."
+ModuleInfo "History: Added style hack to accomodate taller buttons."
+ModuleInfo "History: 1.34 Release"
+ModuleInfo "History: Fixed excessive memory usage by NSPixmapImage"
+ModuleInfo "History: 1.33 Release"
+ModuleInfo "History: Implemented Brucey's fixes"
+ModuleInfo "History: 1.32 Release"
+ModuleInfo "History: Fixed to support new SetDataSource fields in TGadget"
+ModuleInfo "History: 1.31 Release"
+ModuleInfo "History: Fixed TreeView generating extra events"
+ModuleInfo "History: Added Seb's fix for button state in EVENT_GADGETACTION data"	
+ModuleInfo "History: 1.30 Release"
+ModuleInfo "History: Fixed ClearGadgetItems on ListBox generating event"
+ModuleInfo "History: Strip windows hotkey shortcut '&' from CreateButton text"
+ModuleInfo "History: Fixed FreeGadget childwindow crash"
+ModuleInfo "History: Fixed SetPanelPixmap panel,Null"
+ModuleInfo "History: 1.29 Release"
+ModuleInfo "History: Added fixes for new label code"
+ModuleInfo "History: 1.28 Release"
+ModuleInfo "History: Optimized ListView tooltip usage"
+ModuleInfo "History: Added Brucey's fixes for ListView events"
+ModuleInfo "History: Added Brucey's fixes for Label alignment"
+ModuleInfo "History: 1.27 Release"
+ModuleInfo "History: Bumped version for bizzarro TEXTFORMAT_????? issue"
+ModuleInfo "History: 1.26 Release"
+ModuleInfo "History: Fixed gadget and extra data fields for EVENT_GADGETMENU node events"
+ModuleInfo "History: Added itemx extra object to relevant GADGETACTION events"
+ModuleInfo "History: Tweaked bounds checking on textarea CharAt and LineAt"
+ModuleInfo "History: 1.25 Release"
+ModuleInfo "History: Fixed keyboard filtering bug introduced in 1.23"
+ModuleInfo "History: 1.24 Release"
+ModuleInfo "History: Bumped to keep in sync with new TMap"
+ModuleInfo "History: 1.23 Release"
+ModuleInfo "History: Fixed ActiveGadget, Cut, Copy and Paste for TextFields"
+ModuleInfo "History: Fixed RequestColor exception with non RGB colors"
+ModuleInfo "History: 1.22 Release"
+ModuleInfo "History: Premultiply pixels when calling NSPixmap with alpha"
+ModuleInfo "History: 1.21 Release"
+ModuleInfo "History: Fixed SetMinWindowSize"
+ModuleInfo "History: 1.20 Release"
+ModuleInfo "History: Fixed WINDOW_CLIENTCOORDS behavior"
+ModuleInfo "History: Desktop() client shape now based on [Screen visibleFrame]"
+ModuleInfo "History: 1.19 Release"
+ModuleInfo "History: Fixed multiple toolbar errors"
+ModuleInfo "History: 1.18 Release"
+ModuleInfo "History: Added EVENT_GADGETLOSTFOCUS"
+ModuleInfo "History: 1.17 Release"
+ModuleInfo "History: Rebuilt under 10.3.9"
+ModuleInfo "History: 1.16 Release"
+ModuleInfo "History: Fixed SetGadgetText to work with menu items courtesy Byteemoz"
+ModuleInfo "History: 1.15 Release"
+ModuleInfo "History: Fixed Radio Buttons to exclude others in group"
+ModuleInfo "History: 1.14 Release"
+ModuleInfo "History: Fixed TNSGadget.GetText$() for menu items"
+ModuleInfo "History: 1.13 Release"
+ModuleInfo "History: NSLoadFont now defaults to systemFontOfSize if font not found"
+ModuleInfo "History: 1.12 Release"
+ModuleInfo "History: Rebuilt under 10.3.9"
+ModuleInfo "History: 1.11 Release"
+ModuleInfo "History: Stopped borderless window exceptions (NSDrawWindowBackground)"
+ModuleInfo "History: 1.10 Release"
+ModuleInfo "History: Added ComboBox support in NSGetText and NSSetText"
+ModuleInfo "History: Fixed ListBox gadget action not reporting selection in EventData"
+ModuleInfo "History: 1.09 Release"
+ModuleInfo "History: Fixed TextView::SetFont (affecting empty TextAreas like MaxIDE output)"
+ModuleInfo "History: 1.08 Release"
+ModuleInfo "History: Removed NSCompositeCopy so 32bit panelpixmaps blend with window not desktop"
+ModuleInfo "History: Fixed DisableGadget for TextFields, Sliders and Menus"
+ModuleInfo "History: Stopped TreeViewNode with iconstrip crashing with no icon (icon=-1)"
+ModuleInfo "History: Stopped stepper Slider value from wrapping around"
+ModuleInfo "History: Fixed TextField to scroll single line correctly"
+ModuleInfo "History: Added out of range error checks for TextArea commands"
+ModuleInfo "History: 1.07 Release"
+ModuleInfo "History: Added support for ActiveGadget() command"
+ModuleInfo "History: Fixed FreeGadget TextArea not removing the view "
+ModuleInfo "History: 1.06 Release"
+ModuleInfo "History: Fixed RedrawGadget with window gadgets"
+ModuleInfo "History: Fixed unselecting item in listbox error"
+ModuleInfo "History: 1.05 Release"
+ModuleInfo "History: Fixed redraw of superview after setframe on view"
+ModuleInfo "History: Fixed InsertTreeViewNode ignoring index"
+ModuleInfo "History: Fixed SelectTreeViewNode generating multiple events"
+ModuleInfo "History: 1.04 Release"
+ModuleInfo "History: Fixed NSEnable and NSState STATE_DISABLED issues"
+ModuleInfo "History: 1.03 Release"
+ModuleInfo "History: Fixed NSRequestFont behavior with null default"
+ModuleInfo "History: Fixed Disable on Panel and Canvas NSGadgets"
+ModuleInfo "History: 1.02 Release"
+ModuleInfo "History: Added Query(QUERY_NSVIEW) and Query(QUERY_NSVIEW_CLIENT)"
+ModuleInfo "History: Fixed positioning of PopupWindowMenu"
+ModuleInfo "History: Flipped coordinate system for PANEL_VIEW client"
+ModuleInfo "History: 1.01 Release"
+ModuleInfo "History: Now uses default app menu instead of creating new menu"
+
+?MacOs
+Import "cocoagui.bmx"
+?

+ 40 - 0
drivers.mod/drivers.bmx

@@ -0,0 +1,40 @@
+
+Strict
+
+Rem
+bbdoc: MaxGUI/Drivers
+about:
+Your MaxGUI applications should import this module if they want BlitzMax to selectively import the latest official #{MaxGUI drivers} for your application and platform:
+
+[ @Platform | @{Default Driver}
+* Windows 2000/XP/Vista | #MaxGUI.Win32MaxGUIEx
+* Windows 9X | #MaxGUI.Win32MaxGUIEx (requires unicows.dll or MSLU to run)
+* Linux | #MaxGUI.FLTKMaxGUI
+* Mac OS X | #MaxGUI.CocoaMaxGUI
+]
+End Rem
+Module MaxGUI.Drivers
+
+ModuleInfo "Version: 0.04"
+ModuleInfo "Author: Simon Armstrong"
+ModuleInfo "License: zlib/libpng"
+ModuleInfo "Copyright: Blitz Research Ltd"
+
+ModuleInfo "History: 0.04 Release"
+ModuleInfo "History: MaxGUI.Win32MaxGUIEx has now become the standard Windows MaxGUI driver."
+ModuleInfo "History: 0.03 Release"
+ModuleInfo "History: The most appropriate driver is automatically selected at run-time for the OS."
+ModuleInfo "History: Both the old ANSI and new UNICODE Windows modules are now imported."
+ModuleInfo "History: 0.02 Release"
+ModuleInfo "History: Added compiler directives and removed MaxGUI.MaxGUI."
+ModuleInfo "History: 0.01 Release"
+ModuleInfo "History: Initial release required for BlitzMax 1.28 examples update."
+
+?Win32
+Import MaxGUI.Win32MaxGUIEx
+Import "-lunicows"
+?MacOs
+Import Maxgui.CocoaMaxGui
+?Linux
+Import Maxgui.FLTKMaxGui
+?

+ 47 - 0
localization.mod/doc/createlanguage.bmx

@@ -0,0 +1,47 @@
+' createlanguage.bmx
+
+Strict
+
+Import MaxGUI.Drivers
+
+' Enable the localization engine, and automatically localize gadgets when they are created
+SetLocalizationMode(LOCALIZATION_ON|LOCALIZATION_OVERRIDE)
+
+Global window:TGadget = CreateWindow("{{window_title}}",100,100,320,240,Null,WINDOW_TITLEBAR|WINDOW_STATUS)
+	
+	Global btnEnglish:TGadget = CreateButton("{{btn_english}}",5,5,100,30,window,BUTTON_RADIO)
+	Global btnFrench:TGadget = CreateButton("{{btn_french}}",5,40,100,30,window,BUTTON_RADIO)
+	SetButtonState( btnEnglish, True )
+
+' Create a new 'English' language
+Global lngEnglish:TMaxGUILanguage = CreateLanguage("English (English)")
+
+DefineLanguageToken( lngEnglish, "window_title", "My Window" )
+DefineLanguageToken( lngEnglish, "btn_english", "English" )
+DefineLanguageToken( lngEnglish, "btn_french", "French" )
+
+' Create a new 'French' language
+Global lngFrench:TMaxGUILanguage = CreateLanguage("Français (French)")
+
+DefineLanguageToken( lngFrench, "window_title", "Ma Fenêtre" )
+DefineLanguageToken( lngFrench, "btn_english", "Anglais" )
+DefineLanguageToken( lngFrench, "btn_french", "Français" )
+
+' Set the default language
+SetLocalizationLanguage( lngEnglish )
+
+Repeat
+	SetStatusText window, LanguageName( LocalizationLanguage() )
+	Select WaitEvent()
+		Case EVENT_GADGETACTION
+			Select EventSource()
+				Case btnEnglish
+					SetLocalizationLanguage( lngEnglish )
+				Case btnFrench
+					SetLocalizationLanguage( lngFrench )
+			EndSelect
+		Case EVENT_APPTERMINATE, EVENT_WINDOWCLOSE
+			End
+	EndSelect
+Forever
+

+ 10 - 0
localization.mod/doc/intro.bbdoc

@@ -0,0 +1,10 @@
+MaxGUI.Localization is a simple yet powerful localization engine that you can use to localize your applications.
+Although the module is designed primarily for use with the MaxGUI toolkit, it is self-contained and so can be 
+imported into other BlitzMax games and applications separately, without the overhead of the rest of MaxGUI.
+
+
+It is recommended that you read through the command set below to familiarize yourself with the module before
+use.  
+
+Whenever applicable, MaxGUI coders should use the #LocalizeGadget command in #{MaxGUI.MaxGUI} in favour of 
+#LocalizeString to ensure that gadgets are updated when the language or localization settings are changed.

+ 377 - 0
localization.mod/language.bmx

@@ -0,0 +1,377 @@
+Strict
+
+Import Brl.Map
+Import Brl.TextStream
+
+Rem
+bbdoc: Create a new empty language to be used with MaxGUI's localization system. 
+about: This function is provided in case it is necessary to create a new language from scratch. 
+In the majority of cases, languages should instead be loaded from INI files using #LoadLanguage. 
+
+Use the #DefineLanguageToken, #RemoveLanguageToken and #ClearLanguageTokens commands to add to and 
+modify the returned language.  #SetLanguageName and #LanguageName may also be useful.
+
+See Also: #LoadLanguage, #SetLocalizationLanguage, #LocalizeString and #LocalizeGadget.
+EndRem
+Function CreateLanguage:TMaxGuiLanguage( name$ )
+	Return New TMaxGuiLanguage.Create(name)
+EndFunction
+
+Rem
+bbdoc: Load a language from an INI text stream.
+about: @{url} can be a filepath or any other readable #TStream object.
+
+The INI text stream must contain, at minimum, an INI section labelled '[LanguageDefinition]' and 
+a 'LanguageID' token which should be assigned an appropriate language name.
+
+A typical language INI file may look something like:
+
+{{
+[LanguageDefinition]
+
+LanguageID = Français (French)
+LanguageVersion = v0.1
+LanguageAuthor = Various Sources
+
+; Toolbar Tips
+tb_new                                       = "Nouveau"
+tb_open                                      = "Ouvrir"
+tb_close                                     = "Fermer"
+tb_save                                      = "Enregistrer"
+tb_cut                                       = "Couper"
+tb_copy                                      = "Copier"
+tb_paste                                     = "Coller"
+...
+tb_home                                      = "Page d'Accueil"
+tb_back                                      = "Précédente"
+tb_forward                                   = "Suivante"
+
+; Tabs
+tab_help                                     = "Aide"
+tab_output                                   = "Sortie"
+tab_locked:%1                                = "construction:%1"
+
+; Time Format, by example: 13:09:02
+; h = 1 (12 hour clock)       hh = 13 (24 hour clock)
+; m = 9 (without leading 0)   mm = 09 (including leading 0)
+; s = 2 (without leading 0)   ss = 02 (including leading 0)
+; pp = {{pm}} (or '{{am}}' from 00:00 -> 11:59)
+
+longtime = hh:mm:ss pp
+shorttime = {{longtime}}          ; We want short time to be formatted exactly like {{longtime}}
+
+; Date Format, by example: 9th June 2009
+; d = 9    dd = 09    ddd = {{Wed}}    dddd = {{Wednesday}}
+; m = 6    mm = 06    mmm = {{Jun}}    mmmm = {{June}}
+; yy = 09  yyyy = 2009             oo = {{9th}}
+
+longdate = dddd oo mmmm dddd      ; e.g. Wednesday 9th June 2009
+shortdate = dd/mm/yy              ; e.g. 09/06/09
+
+; AM / PM
+am = AM
+pm = PM
+
+; Ordinals
+
+1st = 1e
+2nd = 2er
+3rd = 3e
+4th = 4e
+; etc.
+
+; Days of the week
+
+Monday = "Lundi"
+Mon = "Lun"
+Tueday = "Mardi"
+Tue = "Mar"
+Wednesday = "Mercredi"
+Wed = "Mer"
+Thursday = "Jeudi"
+Thu = "Jeu"
+Friday = "Vendredi"
+Fri = "Ven"
+Saturday = "Samedi"
+Sat = "Sam"
+Sunday = "Dimanche"
+Sun = "Dim"
+}}
+
+Note how a semicolon ';' is used to mark the start of a line comment.
+
+INI files support the following escape sequence characters:
+
+[ @{INI Escape Sequence} | @{BlitzMax Equivalent}  
+* \\ | ~\ 
+* \r | ~~r 
+* \n | ~~n 
+* \t | ~~t
+* \# | ~# 
+* \; | ; 
+* \: | : 
+] 
+
+The bottom three escape sequences are only strictly required if the value of the INI key is not enclosed 
+in quotes.  For example, the following definitions are expected to evaluate to the same string ( ~#;: ).
+
+{{ 
+	MyToken = \#\;\:
+	MyToken = "#;:"
+	MyToken = "\#\;\:"
+}}
+
+Use the #DefineLanguageToken, #RemoveLanguageToken and #ClearLanguageTokens commands to add to and 
+modify the returned language.  #SetLanguageName and #LanguageName may also be useful.
+
+To construct a new language from scratch, use the #CreateLanguage command instead.
+
+See Also: #SetLocalizationLanguage, #SaveLanguage, #LocalizeString and #LocalizeGadget.
+EndRem
+Function LoadLanguage:TMaxGuiLanguage( url:Object )
+	Return TMaxGuiLanguage.LoadLanguage(url)
+EndFunction
+
+Rem
+bbdoc: Saves a language as an INI section to the supplied stream.
+about: @{url} can be a filepath or any other writable #TStream object.
+
+If @{url} is a string ending in "/" or "\", it is assumed that @{url} is a directory path and a default filename 
+will be appended like so:
+
+{{
+url = String(url) + LanguageName(language).Split(" ")[0] + ".language.ini"
+}}
+
+WARNING: This command will automatically overwrite any existing file at the supplied/resulting file path.
+
+See Also: #LoadLanguage, #SetLocalizationLanguage, #LocalizeString and #LocalizeGadget.
+EndRem
+Function SaveLanguage( language:TMaxGuiLanguage, url:Object )
+	If Not TStream(url) And (String(url).EndsWith("/") Or String(url).EndsWith("\")) Then 
+		url = String(url) + language.GetName().Split(" ")[0] + ".language.ini"
+	EndIf
+	SaveText( language.Serialize(), url )
+EndFunction
+
+Rem
+bbdoc: Redefine a language's name.
+about: See Also: #LanguageName, #LoadLanguage, #CreateLanguage and #SetLocalizationLanguage.
+EndRem
+Function SetLanguageName( language:TMaxGuiLanguage, name$ )
+	language.SetName(name)
+EndFunction
+
+Rem
+bbdoc: Returns a language's name.
+about: See Also: #SetLanguageName, #LoadLanguage, #CreateLanguage and #SetLocalizationLanguage.
+EndRem
+Function LanguageName$( language:TMaxGuiLanguage )
+	Return language.GetName()
+EndFunction
+
+Rem
+bbdoc: Define a language-specific value for a localization token.
+about: Localization tokens are case insensitive, and if a token definition already exists in the language
+the token value will be overwritten with this most recent @{value$}.
+
+See Also: #LoadLanguage, #CreateLanguage, #SaveLanguage and #SetLocalizationLanguage.
+EndRem
+Function DefineLanguageToken( language:TMaxGuiLanguage, token$, value$ )
+	language.DefineToken(token,value)
+EndFunction
+
+Rem
+bbdoc: Look-up the value of a token for a specific language.
+about: Localization tokens are case insensitive, and are either loaded in with the language or defined
+using the #DefineLanguageToken command.
+
+If an explicit token definition is not found in the language, the @{token$} string is returned as it was passed.
+
+See Also: #LoadLanguage, #CreateLanguage, #SaveLanguage and #SetLocalizationLanguage.
+EndRem
+Function LanguageTokenDefinition$( language:TMaxGuiLanguage, token$ )
+	Return language.LookupToken(token)
+EndFunction
+
+Rem
+bbdoc: Remove a token definition from a language.
+about: The only token which cannot be removed is 'LanguageID' as every language requires this one token to be defined -
+it defines the language name.  If a matching token isn't already defined, then the command returns silently.
+
+Note: Localization tokens are case insensitive so the following commands are all requesting the same token to be removed:
+
+{{
+RemoveLanguageToken( language, "WelcomeMessage" )
+RemoveLanguageToken( language, "WELCOMEMESSAGE" )
+RemoveLanguageToken( language, "welcomemessage" )
+RemoveLanguageToken( language, "WeLcOmEmEsSaGe" )
+}}
+
+See Also: #ClearLanguageTokens, #DefineLanguageToken, #LoadLanguage, #CreateLanguage, #SaveLanguage and #SetLocalizationLanguage.
+EndRem
+Function RemoveLanguageToken( language:TMaxGuiLanguage, token$ )
+	language.RemoveToken(token)
+EndFunction
+
+Rem
+bbdoc: Removes all the tokens defined in a language.
+about: The only token which will not be removed is 'LanguageID' as every language requires this one token to be defined -
+it defines the language name.
+
+See Also: #RemoveLanguageToken, #DefineLanguageToken, #LoadLanguage, #CreateLanguage, #SaveLanguage and #SetLocalizationLanguage.
+EndRem
+Function ClearLanguageTokens( language:TMaxGuiLanguage )
+	language.ClearTokens()
+EndFunction
+
+Type TMaxGuiLanguage
+	
+	?Win32
+	Const CARRIAGE_RETURN:String = "~r~n"
+	?Not Win32
+	Const CARRIAGE_RETURN:String = "~n"
+	?
+	
+	Const SECTION_HEADER:String = "LanguageDefinition"
+	Const LANGUAGENAME_TOKEN:String = "LanguageId"
+	
+	Field strName:String = "Unknown Language"
+	Field mapDictionary:TMap = CreateMap()
+	
+	Method Create:TMaxGuiLanguage(name$)
+		SetName(name)
+		Return Self
+	EndMethod
+	
+	Method SetName(pName$)
+		DefineToken( LANGUAGENAME_TOKEN, pName )
+	EndMethod
+	
+	Method GetName$()
+		Return strName
+	EndMethod
+	
+	Method DefineToken( pToken:String, pText:String )
+		If pToken Then
+			If pToken = LANGUAGENAME_TOKEN Then strName = pText
+			MapInsert( mapDictionary, pToken.ToLower(), Prepare(pText) )
+		EndIf
+	EndMethod
+	
+	Method RemoveToken( pToken:String )
+		If pToken And pToken.ToLower() <> LANGUAGENAME_TOKEN.ToLower() Then MapRemove( mapDictionary, pToken.ToLower() )
+	EndMethod
+	
+	Method LookupToken$(pToken$)
+		Local tmpValue$ = String(MapValueForKey( mapDictionary, pToken.ToLower() ))
+		If tmpValue Then Return Prepare(tmpValue) Else Return pToken
+	EndMethod
+	
+	Method ClearTokens()
+		ClearMap mapDictionary
+		SetName(GetName())
+	EndMethod
+	
+	Method LoadEntriesFromText( text:String )
+		
+		'Very rough INI section parser
+		
+		Local tmpIndex:Int, tmpStage:Int = 0
+		
+		For Local tmpLine:String = EachIn text.Split("~n")
+			
+			tmpStage = 0
+			
+			'Search for valid ';' comment
+			For tmpIndex = 0 Until tmpLine.length
+				Select tmpLine[tmpIndex]
+					Case Asc("~q");If tmpStage <> 0 Then tmpStage = 2
+					Case Asc("=");If tmpStage = 0 Then tmpStage = 1
+					Case Asc(";")
+						If tmpStage = 0 Or tmpStage = 1 Then
+							Exit
+						Else 
+							If tmpLine[tmpIndex-1] <> Asc("\") Then tmpStage = 0-(tmpIndex)
+						EndIf
+				EndSelect
+			Next
+			
+			'Strip the comment if ';' was the last character
+			If tmpStage < 0 Then tmpLine = tmpLine[..Abs(tmpStage)]
+			
+			'Strip any whitespace
+			tmpLine = StripWhitespace(tmpLine[..tmpIndex])
+			If Not tmpLine Then Continue
+			
+			'Test for a new section header
+			If tmpLine[0] = "["[0] Then Exit
+			
+			'Slow but easy code to handle any escape characters
+			tmpLine = tmpLine.Replace("\\","~0").Replace("\r","~r").Replace("\n","~n").Replace("\;",";").Replace("\#","#").Replace("\:",":").Replace("\t","~t").Replace("~0","\")
+			
+			'Find the separator
+			tmpIndex = tmpLine.Find("=")
+			
+			'If we have a key/value pair, define a new key in our dictionary.
+			If tmpIndex > 0 Then DefineToken( StripWhitespace(tmpLine[..tmpIndex],True), StripWhitespace(tmpLine[tmpIndex+1..],True) )
+		Next
+		
+	EndMethod
+	
+	Method Serialize:String()
+		
+		Local tmpString:String = "["+SECTION_HEADER+"]" + CARRIAGE_RETURN + LANGUAGENAME_TOKEN + " = ~q" + GetName() + "~q" + CARRIAGE_RETURN
+		For Local tmpKey:String = EachIn MapKeys(mapDictionary)
+			If tmpKey <> LANGUAGENAME_TOKEN Then
+				tmpString:+tmpKey+" = ~q"+String(MapValueForKey(mapDictionary,tmpKey))+"~q"+CARRIAGE_RETURN
+			EndIf
+		Next
+		Return tmpString
+		
+	EndMethod
+	
+	Method Deserialize:TMaxGuiLanguage(pString$)
+		
+		Local tmpIndex:Int = pString.Find("["+SECTION_HEADER+"]")
+		If tmpIndex < 0 Then Return Null
+		
+		tmpIndex = pString.Find("~n",tmpIndex+SECTION_HEADER.length+2)
+		If tmpIndex < 0 Then Return Null
+		
+		If pString.ToLower().Find(LANGUAGENAME_TOKEN.ToLower(),tmpIndex+1) < 0 Then Return Null
+'DebugStop		
+		ClearMap mapDictionary
+		LoadEntriesFromText( pString[tmpIndex..] )
+		
+		Return Self
+	EndMethod
+	
+	Function LoadLanguage:TMaxGUILanguage( stream:Object )
+		
+		Return New TMaxGuiLanguage.Deserialize( LoadText(stream) )
+		
+	EndFunction
+	
+	Function StripWhitespace:String( text$, pStripQuotes:Int = False )
+		Local i:Int, j:Int
+		For i = 0 Until text.length
+			If text[i] = " "[0] Or text[i] = "~t"[0] Then Continue
+			Exit
+		Next
+		For j = text.length-1 To i Step -1
+			If text[j] = " "[0] Or text[j] = "~t"[0] Or text[j] = "~r"[0] Then Continue
+			Exit
+		Next
+		If pStripQuotes And (j-i)>0 And text[i] = "~q"[0] And text[j] = "~q"[0] Then
+			i:+1;j:-1
+		EndIf
+		Return text[i..j+1]
+	EndFunction
+	
+	Function Prepare$(text$)
+		If text="~0" Then Return "" ElseIf text="" Then Return "~0"
+		Return text
+	EndFunction
+	
+EndType

+ 430 - 0
localization.mod/localization.bmx

@@ -0,0 +1,430 @@
+Strict
+
+Rem
+bbdoc: MaxGUI/Localization
+End Rem
+Module MaxGUI.Localization
+
+ModuleInfo "Version: 1.02"
+ModuleInfo "Author: Seb Hollington"
+ModuleInfo "License: zlib/libpng"
+ModuleInfo "Copyright: Seb Hollington"
+
+ModuleInfo "History: 1.02 Release"
+ModuleInfo "History: Fixed date ordinals so that entire term is a token."
+ModuleInfo "History: 1.01 Release"
+ModuleInfo "History: Added a CreateLanguage() example."
+ModuleInfo "History: Added INI file escape sequence info to LoadLanguage() docs."
+ModuleInfo "History: Fixed semicolon INI escape sequence bug."
+ModuleInfo "History: 1.00 Release"
+ModuleInfo "History: Initial release."
+
+Import BRL.System
+Import "language.bmx"
+
+Const LOCALIZATION_OFF:Int = 0
+Const LOCALIZATION_ON:Int = 1
+
+Rem
+bbdoc: Returns the localized version of a string.
+about: This function takes one parameter: @{localizationstring$}.
+
+A localization string is just like any other string except that any phrase enclosed in a double pair of
+curly-braces is identified as a localization token.  For example, the following examples all use valid
+localization strings.
+
+{{
+LocalizeString("{{welcomemessage}}")                      'Localization token(s): welcomemessage
+LocalizeString("{{apptitlelabel}}: {{AppTitle}}")         'Localization token(s): apptitlelabel, AppTitle
+LocalizeString("Current Time: {{CurrentTime}}")           'Localization token(s): CurrentTime
+}}
+
+Localization tokens are case insensitive, and may be made up of any combination of alphanumeric
+characters.  Firstly, the token is tested to see if it is a reserved word.  The following tokens
+are currently reserved (although more maybe added in the future):
+
+[ @{Localization Token} | @{Token Will Be Replaced With...}
+* AppDir | The value of the #AppDir global constant.
+* AppFile | The value of the #AppFile global constant.
+* AppTitle | The value of the #AppTitle global constant.
+* LaunchDir | The value of the #LaunchDir global constant.
+* GCMemAlloced | The value returned by the #GCMemAlloced function (at the moment the token is parsed).
+]
+
+There are also some reserved date and time tokens which will display the current date and time (at the
+moment of parsing) using any formats defined in the current language.  If there are no matching formats
+explicitly defined, the formats default to:
+
+[ @{Localization Token} | @{Default Format} | @{Sample Output}
+* ShortTime | "hh:mm pp" | 02:36 {{pm}}
+* LongTime | "hh:mm:ss" | 14:36:51
+* ShortDate | "dd/mm/yy" | 04/08/09
+* LongDate | "dddd oo mmmm yyyy" | {{Monday}} {{4th}} {{August}} 2009
+]
+
+Notice how any text-based time and date information is wrapped in curly braces.  These tokens will be
+localized, just like any other token, and so can be modified by adding a corresponding entry to the
+localization language.
+
+This also demonstrates the ability of the localization parser to handle nested tokens.  To prevent lock-
+ups, the localization parser checks for cyclic token definitions, and if one is encountered the token will
+be simply replaced with '!ERROR!' and the the offending localization string will be identified in the warning
+message written to standard error.
+
+If and only if the localization token isn't reserved will the current localization language be queried.  If
+no localization language is selected, or if there is no matching token defined in the current language, the
+token will simply be stripped of its curly braces in the returned string.  Each language is required to have
+at least one token defined: {{LanguageID}}.  This should represent the language name e.g. 'Français (French)'.
+
+%{NOTE: This function requires the LOCALIZATION_ON flag to be set (see #SetLocalizationMode) otherwise
+the function will simply return @{localizationstring$} exactly as it was passed (including any curly braces).}
+
+See Also: #SetLocalizationMode, #LocalizationMode, #SetLocalizationLanguage and #LocalizationLanguage.
+EndRem
+Function LocalizeString$( localizationstring$ )
+	Return TMaxGUILocalizationEngine.LocalizeString( localizationstring )
+EndFunction
+
+
+Rem
+bbdoc: Enable or disable the localization engine, and set other localization modes.
+about: The mode can be set to:
+
+[ @{Constant} | @{Meaning}
+* LOCALIZATION_OFF | Any localized gadgets will display their localizedtext$ as their actual text.
+* LOCALIZATION_ON | Localized gadgets will use the current language to display their text.
+]
+
+Either mode can be combined (btiwse OR'd) with LOCALIZATION_OVERRIDE, which will cause gadgets
+to become automatically 'localized' when they are created, with any @{text$} parameters supplied
+to the @{CreateGadget()} functions being interpreted as localization strings.
+
+If any window menus are localized, #UpdateWindowMenu may have to be called on all relevant windows for the text changes
+to be visible.
+
+See Also: #LocalizationMode, #SetLocalizationLanguage, #LocalizationLanguage and #LocalizeGadget.
+EndRem
+Function SetLocalizationMode( Mode:Int = LOCALIZATION_ON )
+	_SetLocalizationMode(Mode:Int)
+EndFunction
+
+Global _SetLocalizationMode( Mode:Int ) = TMaxGUILocalizationEngine.SetMode
+
+Rem
+bbdoc: Returns the value previously set using #SetLocalizationMode.
+about: The default value for a MaxGUI program is LOCALIZATION_OFF.
+
+See #SetLocalizationMode for valid modes, and their corresponding constants.
+EndRem
+Function LocalizationMode:Int()
+	Return TMaxGUILocalizationEngine.GetMode()
+EndFunction
+
+Rem
+bbdoc: Set the language to be used by MaxGUI's localization system.
+about: Languages can be loaded from files/streams using #LoadLanguage and created from scratch using
+#CreateLanguage.
+
+This function will automatically update the text of any gadget marked as 'localized' using #LocalizeGadget.
+
+If any window menus are localized, #UpdateWindowMenu may have to be called on all relevant windows for the text changes
+to be visible.
+
+See Also: #LocalizationLanguage, #SetLocalizationMode, #LocalizationMode and #LocalizeString.
+EndRem
+Function SetLocalizationLanguage( language:TMaxGUILanguage )
+	_SetLocalizationLanguage( language )
+EndFunction
+
+Global _SetLocalizationLanguage( language:TMaxGUILanguage ) = TMaxGUILocalizationEngine.SetLanguage
+
+Rem
+bbdoc: Returns the current language used by MaxGUI's localization system.
+about: Use the #DefineLanguageToken, #RemoveLanguageToken and #ClearLanguageTokens commands to add to and
+modify the returned language.  #SetLanguageName and #LanguageName may also be useful.
+
+about: See Also: #SetLocalizationLanguage, #SetLocalizationMode, #LocalizationMode and #LocalizeGadget.
+EndRem
+Function LocalizationLanguage:TMaxGUILanguage()
+	Return TMaxGUILocalizationEngine.GetLanguage()
+EndFunction
+
+Private
+
+Type TMaxGUILocalizationEngine
+	
+	Global intLocalizationMode:Int = LOCALIZATION_OFF
+	Global _currentLanguage:TMaxGUILanguage
+	Global _localizeStack:String[]
+	
+	Method New()
+		'Return Null
+	EndMethod
+	
+	' Indirection allows MaxGUI.MaxGUI's TMaxGUIDriver to intercept function calls
+	' and update gadgets if necessary (see bottom of maxgui.mod/driver.bmx).
+	Global SetMode( Mode:Int ) = TMaxGUILocalizationEngine._SetMode
+	Global SetLanguage( language:TMaxGUILanguage ) = TMaxGUILocalizationEngine._SetLanguage
+	
+	Function _SetMode( Mode:Int )
+		intLocalizationMode = Mode
+	EndFunction
+	
+	Function GetMode:Int()
+		Return intLocalizationMode
+	EndFunction
+	
+	Function GetLanguage:TMaxGUILanguage()
+		Return _currentLanguage
+	EndFunction
+	
+	Function _SetLanguage( language:TMaxGUILanguage )
+		_currentLanguage = language
+	EndFunction
+	
+	Function LocalizeString:String( Text$ )
+		
+		' Only localize the string if the localization engine is turned on.
+		If (intLocalizationMode&LOCALIZATION_ON) Then
+			
+			' Check for cyclic definitions by comparing localization string with those on the stack.
+			For Local i:Int = _localizeStack.length-1 To 0 Step -1
+				If _localizeStack[i] = Text Then
+					WriteStderr "WARNING: Encountered cyclic localization string: ~q"+_localizeStack[i]+"~q.~n"
+					Return "!ERROR!"
+				EndIf
+			Next
+			
+			' Add localization string to the stack.
+			_localizeStack:+[Text]
+			
+			Local tmpText:String
+			Local i:Int, tmpPrevChar:Int		
+			Local tmpCount:Int, tmpOpenings:Int[Text.length/2]		'manages opening character index for nested tokens
+			
+			' Start parsing for curly braces
+			While i < Text.length
+				Select Text[i]
+					Case Asc("{")
+						'If previous char was also an opening "{" then we're entering into a token
+						If tmpPrevChar = Text[i] Then
+							tmpOpenings[tmpCount] = i+1
+							tmpCount:+1
+							tmpPrevChar = 0
+							
+						'Otherwise update the value of the last char and move onto the next character.
+						Else
+							tmpPrevChar = Text[i]
+						EndIf
+						
+					Case Asc("}")
+						
+						'If previous char was also a closing "}" then we're leaving a token, so interpret it.
+						If tmpPrevChar = Text[i] Then
+							
+							' Retrieve the token text
+							tmpCount:-1
+							tmpText = Text[tmpOpenings[tmpCount]..i-1]
+							
+							' Check for reserved words or run it through the dictionary.
+							Select tmpText.ToLower()
+								
+								' Keywords
+								Case "appfile";tmpText = AppFile
+								Case "appdir";tmpText = AppDir
+								Case "apptitle";tmpText = AppTitle
+								Case "launchdir";tmpText = LaunchDir
+								Case "gcmemalloced";tmpText = GCMemAlloced()
+								
+								' Time parsing
+								Case "shorttime", "longtime"
+									' Check if the current language defines its own time format for the token
+									If _currentLanguage Then tmpText = LocalizeString(_currentLanguage.LookupToken(tmpText))
+									' Either way, call LocalizeTime() and then localize the returned string (in case it contains tokens too).
+									tmpText = LocalizeString(LocalizedTime(tmpText))
+									
+								' Date parsing
+								Case "shortdate", "longdate"
+									' Check if the current language defines its own date format for the token
+									If _currentLanguage Then tmpText = LocalizeString(_currentLanguage.LookupToken(tmpText))
+									' Either way, call LocalizeDate() and then localize the returned string (in case it contains tokens too).
+									tmpText = LocalizeString(LocalizedDate(tmpText))
+									
+								' Language definition
+								Default
+'DebugStop
+									If _currentLanguage Then
+										' Lookup token using the current language, and localize the returned string (in case that contains tokens).
+										tmpText = LocalizeString(_currentLanguage.LookupToken(tmpText))
+									EndIf
+									
+							EndSelect
+							
+							' Substitute the localized text into the string in-place, to enable nested parsing to work.
+							Text = Text[..tmpOpenings[tmpCount]-2] + tmpText + Text[i+1..]
+							i:+(tmpText.length-(i+3-tmpOpenings[tmpCount]))
+							tmpPrevChar = 0
+							
+						'Otherwise update the value of the last char and move onto the next character.
+						Else
+							tmpPrevChar = Text[i]
+						EndIf
+						
+					Default
+						tmpPrevChar = 0
+				EndSelect
+				i:+1
+			Wend
+			
+			' Remove localization string from stack as we're about to return
+			_localizeStack = _localizeStack[.._localizeStack.length-1]
+			
+		EndIf
+		
+		' Return the localized text.
+		Return Text
+		
+	EndFunction
+	
+	Function LocalizedTime:String(pTimeFormat$)
+		Local i:Int = 0, tmpTokenCount:Int = 0, tmpToken$, tmpTime:String[] = CurrentTime().Split(":")
+		Select pTimeFormat.ToLower()
+			Case "shorttime";pTimeFormat = "hh:mm "
+			Case "longtime";pTimeFormat = "hh:mm:ss "
+			Default;pTimeFormat:+" "
+		EndSelect
+		While i < pTimeFormat.length
+			
+			If tmpTokenCount And (pTimeFormat[i-1] <> pTimeFormat[i]) Then
+				tmpToken = Null
+				Select pTimeFormat[i-1]
+					Case Asc("h")
+						Select tmpTokenCount
+							Case 1;tmpToken = Int(tmpTime[0]) Mod 12
+							Case 2;tmpToken = Int(tmpTime[0])
+						EndSelect
+					Case Asc("m")
+						Select tmpTokenCount
+							Case 1;tmpToken = Int(tmpTime[1])
+							Case 2;tmpToken = tmpTime[1]
+						EndSelect
+					Case Asc("s")
+						Select tmpTokenCount
+							Case 1;tmpToken = Int(tmpTime[2])
+							Case 2;tmpToken = tmpTime[2]
+						EndSelect
+					Case Asc("p")
+						If tmpTokenCount = 2 Then
+							If tmpTime[0] < 12 Then tmpToken = "{{am}}" Else tmpToken = "{{pm}}"
+						EndIf
+				EndSelect
+				If tmpToken
+					pTimeFormat = pTimeFormat[..(i-tmpTokenCount)] + tmpToken + pTimeFormat[i..]
+					i:+tmpToken.length-tmpTokenCount
+				EndIf
+				tmpTokenCount = 0
+			EndIf
+			
+			Select pTimeFormat[i]
+				Case "h"[0],"m"[0],"s"[0],"p"[0]
+					tmpTokenCount:+1
+				Default
+					tmpTokenCount = 0
+			EndSelect
+			
+			i:+1
+			
+		Wend
+		Return pTimeFormat[..pTimeFormat.length-1]
+	EndFunction
+	
+	Function LocalizedDate:String(pDateFormat$)
+		Local i:Int = 0, tmpTokenCount:Int = 0, tmpToken$, tmpDate:String[] = CurrentDate().Split(" ")
+		Select pDateFormat.ToLower()
+			Case "shortdate";pDateFormat= "dd/mm/yy "
+			Case "longdate";pDateFormat = "dddd oo mmmm yyyy "
+			Default;pDateFormat:+" "
+		EndSelect
+		While i < pDateFormat.length
+			
+			If tmpTokenCount And (pDateFormat[i-1] <> pDateFormat[i]) Then
+				tmpToken = Null
+				Select pDateFormat[i-1]
+					Case Asc("d")
+						Select tmpTokenCount
+							Case 1;tmpToken = Int(tmpDate[0])
+							Case 2;tmpToken = tmpDate[0]
+							Case 3,4
+								Local tmpDayAsInt:Int = DayOfTheWeek(Int(tmpDate[0]),_MonthAsNumber(tmpDate[1]),Int(tmpDate[2]))
+								If tmpTokenCount = 3 Then tmpToken = "{{"+_shortDays[tmpDayAsInt]+"}}" Else tmpToken = "{{"+_fullDays[tmpDayAsInt]+"}}"
+						EndSelect
+					Case Asc("m")
+						Select tmpTokenCount
+							Case 1,2
+								Local tmpMonth:Int = _MonthAsNumber(tmpDate[1])
+								If tmpTokenCount = 1 And tmpMonth < 10 Then tmpToken = " " + tmpMonth Else tmpToken = tmpMonth
+							Case 3;tmpToken = "{{"+tmpDate[1]+"}}"
+							Case 4;tmpToken = "{{" + _fullMonths[_MonthAsNumber(tmpDate[1])] + "}}"
+						EndSelect
+					Case Asc("y")
+						Select tmpTokenCount
+							Case 2;tmpToken = tmpDate[2][tmpDate.length-2..]
+							Case 4;tmpToken = tmpDate[2]
+						EndSelect
+					Case Asc("o")
+						If tmpTokenCount = 2 Then
+							Select Int(tmpDate[0])
+								Case 1,21,31;tmpToken = "{{" + Int(tmpDate[0]) + "st}}"
+								Case 2,22;tmpToken = "{{" + Int(tmpDate[0]) + "nd}}"
+								Case 3,23;tmpToken = "{{" + Int(tmpDate[0]) + "rd}}"
+								Default;tmpToken = "{{" + Int(tmpDate[0]) + "th}}"
+							EndSelect
+						EndIf
+				EndSelect
+				If tmpToken
+					pDateFormat = pDateFormat[..(i-tmpTokenCount)] + tmpToken + pDateFormat[i..]
+					i:+tmpToken.length-tmpTokenCount
+				EndIf
+				tmpTokenCount = 0
+			EndIf
+			
+			Select pDateFormat[i]
+				Case Asc("d"),Asc("m"),Asc("y"),Asc("o")
+					tmpTokenCount:+1
+				Default
+					tmpTokenCount = 0
+			EndSelect
+			
+			i:+1
+		Wend
+		Return pDateFormat[..pDateFormat.length-1]
+	EndFunction
+	
+	Global _fullMonths:String[] = ["", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
+	Global _shortDays:String[] = ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]
+	Global _fullDays:String[] = ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]
+	
+	Function _MonthAsNumber:Int(Month$)
+		Select Month.ToLower()
+			Case "jan";Return 1
+			Case "feb";Return 2
+			Case "mar";Return 3
+			Case "apr";Return 4
+			Case "may";Return 5
+			Case "jun";Return 6
+			Case "jul";Return 7
+			Case "aug";Return 8
+			Case "sep";Return 9
+			Case "oct";Return 10
+			Case "nov";Return 11
+			Case "dec";Return 12
+		EndSelect
+		RuntimeError "Unrecognised month: ~q" + Month + "~q"
+	EndFunction
+	
+	Function DayOfTheWeek:Int(Day:Int, Month:Int, Year:Int)
+		Local Jt:Float = Float(367 * Year - ((7 * (Year + 5001 + ((Month - 9) / 7))) / 4) + ((275 * Month) / 9) + Day + 1729777)+1.5
+		Return (jt Mod 7)
+	End Function
+
+EndType

+ 36 - 0
maxgui.mod/doc/canvasbeginpaint.bmx

@@ -0,0 +1,36 @@
+' canvasbeginpaint.bmx
+
+Strict
+
+Import MaxGui.Drivers
+
+AppTitle = "Canvas Painter Example"
+
+Local window:TGadget = CreateWindow(AppTitle,50,50,200,200)
+
+	' create a canvas that occupies entire window client area
+	
+	Local canvas:TGadget = CreateCanvas(0,0,ClientWidth(window),ClientHeight(window),window)
+	SetGadgetLayout canvas, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED
+
+' create a timer as our single event source
+
+Local timer:TTimer = CreateTimer(50)
+
+Repeat
+	Select WaitEvent()
+		Case EVENT_WINDOWCLOSE, EVENT_APPTERMINATE
+			End
+		Default
+			CanvasBeginPaint(canvas)
+			SetClsColor( 0, 255*Sin(MilliSecs()/5.0), 0 )
+			Cls()
+			Flip()
+	EndSelect
+Forever
+
+Function CanvasBeginPaint(canvas:TGadget)
+	SetGraphics CanvasGraphics(canvas)
+	SetVirtualResolution ClientWidth(canvas), ClientHeight(canvas)
+	SetViewport 0, 0, ClientWidth(canvas), ClientHeight(canvas)
+End Function

+ 38 - 0
maxgui.mod/doc/createbutton.bmx

@@ -0,0 +1,38 @@
+' createbutton.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+Global window:TGadget = CreateWindow("MaxGUI Buttons",40,40,400,330,Null,WINDOW_TITLEBAR|WINDOW_CLIENTCOORDS)
+	CreateButton("Std. Button",10,10,120,30,window,BUTTON_PUSH)
+	CreateButton("OK Button",140,10,120,30,window,BUTTON_OK)
+	CreateButton("Cancel Button",270,10,120,30,window,BUTTON_CANCEL)
+
+Global panel:TGadget[4]
+	panel[0]=CreatePanel(10,50,380,60,window,PANEL_GROUP,"Checkbox")
+		FillPanelWithButtons(panel[0], BUTTON_CHECKBOX, "Checkbox")
+	panel[1]=CreatePanel(10,120,380,60,window,PANEL_GROUP,"Checkbox (with Push Button Style)")
+		FillPanelWithButtons(panel[1], BUTTON_CHECKBOX|BUTTON_PUSH, "Toggle")
+	panel[2]=CreatePanel(10,190,380,60,window,PANEL_GROUP,"Radio Buttons")
+		FillPanelWithButtons(panel[2], BUTTON_RADIO, "Option ")
+	panel[3]=CreatePanel(10,260,380,60,window,PANEL_GROUP,"Radio Buttons (with Push Button Style)")
+		FillPanelWithButtons(panel[3], BUTTON_RADIO|BUTTON_PUSH, "Option")
+
+Repeat
+	Select WaitEvent()
+		Case EVENT_WINDOWCLOSE, EVENT_APPTERMINATE
+			End
+		Case EVENT_GADGETACTION
+			Print "EVENT_GADGETACTION~n" + ..
+			"GadgetText(): ~q" + GadgetText(TGadget(EventSource())) + "~q ~t " + ..
+			"ButtonState(): "+ ButtonState(TGadget(EventSource()))
+	EndSelect
+Forever
+
+Function FillPanelWithButtons( pPanel:TGadget, pStyle%, pText$ = "Button" )
+	Local buttonwidth% = (pPanel.width-10)/3
+	For Local i% = 0 Until 3
+		CreateButton( pText + " " + (i+1), 5+(i*buttonwidth), 5, buttonwidth-10, 26, pPanel, pStyle )
+	Next
+EndFunction

+ 49 - 0
maxgui.mod/doc/createcanvas.bmx

@@ -0,0 +1,49 @@
+' createcanvas.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+Global GAME_WIDTH=320
+Global GAME_HEIGHT=240
+
+' create a centered window with client size GAME_WIDTH,GAME_HEIGHT
+
+Local wx=(ClientWidth(Desktop())-GAME_WIDTH)/2
+Local wy=(ClientHeight(Desktop())-GAME_HEIGHT)/2
+
+Local window:TGadget=CreateWindow("My Canvas",wx,wy,GAME_WIDTH,GAME_HEIGHT,Null,WINDOW_TITLEBAR)'|WINDOW_CLIENTCOORDS)
+
+' create a canvas for our game
+Local canvas:TGadget=CreateCanvas(0,0,320,240,window)
+
+' create an update timer
+
+CreateTimer 60
+
+While WaitEvent()
+	Select EventID()
+		Case EVENT_TIMERTICK
+			RedrawGadget canvas
+
+		Case EVENT_GADGETPAINT
+			SetGraphics CanvasGraphics(canvas)
+			SetOrigin 160,120
+			SetLineWidth 5
+			Cls
+			Local t=MilliSecs()
+			DrawLine 0,0,120*Cos(t),120*Sin(t)
+			DrawLine 0,0,80*Cos(t/60),80*Sin(t/60)
+			Flip
+
+		Case EVENT_MOUSEMOVE
+			Print "MOVE!"
+
+		Case EVENT_WINDOWCLOSE
+			FreeGadget canvas
+			End
+
+		Case EVENT_APPTERMINATE
+			End
+	End Select
+Wend

+ 51 - 0
maxgui.mod/doc/createcombobox.bmx

@@ -0,0 +1,51 @@
+' createcombobox.bmx
+
+Strict
+
+Import MaxGui.Drivers
+
+AppTitle = "ComboBox Style Example"
+
+Global window:TGadget = CreateWindow( AppTitle, 100, 100, 300, 200, Null, WINDOW_TITLEBAR|WINDOW_STATUS )
+	
+	CreateLabel( "No Style (0): ", 5, 5, ClientWidth(window)-10, 24, window, LABEL_LEFT )
+	Global stdComboBox:TGadget = CreateComboBox( 5, 29, ClientWidth(window)-10, 26, window, 0 )
+		AddGadgetItem stdComboBox, "Short"
+		AddGadgetItem stdComboBox, "Medium"
+		AddGadgetItem stdComboBox, "Fat", True
+		AddGadgetItem stdComboBox, "Humungous"
+		
+	CreateLabel( "COMBOBOX_EDITABLE: ", 5, 59, ClientWidth(window)-10, 24, window, LABEL_LEFT )
+	Global editcombobox:TGadget = CreateComboBox( 5, 83, ClientWidth(window)-10, 26, window, COMBOBOX_EDITABLE )
+		AddGadgetItem editcombobox, "United Kingdom"
+		AddGadgetItem editcombobox, "United States", True
+
+Local tmpText$
+
+Repeat
+	WaitEvent()
+	Print CurrentEvent.ToString()
+	Select EventID()
+		'Combobox Event(s)
+		'EventData() holds the index of the selected item (or -1 if no item is currently selected)
+		Case EVENT_GADGETACTION
+			Select EventSource()
+				Case stdComboBox
+					tmpText = ""
+					If EventData() > -1 Then
+						tmpText = GadgetItemText(TGadget(EventSource()), EventData())
+					EndIf
+					SetStatusText window, "Weight chosen: " + tmpText
+				Case editComboBox
+					tmpText = ""
+					If EventData() > -1 Then 
+						tmpText = GadgetItemText(TGadget(EventSource()), EventData())
+					Else 
+						tmpText = GadgetText(TGadget(EventSource())) + " [user text]"
+					EndIf
+					SetStatusText window, "Country chosen: " + tmpText
+			EndSelect
+		Case EVENT_WINDOWCLOSE, EVENT_APPTERMINATE
+			End
+	EndSelect
+Forever

+ 23 - 0
maxgui.mod/doc/createhtmlview.bmx

@@ -0,0 +1,23 @@
+' createhtmlview.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+Local window:TGadget
+Local htmlview:TGadget
+
+window=CreateWindow("My Window",30,20,600,440,,15|WINDOW_ACCEPTFILES)
+
+htmlview=CreateHTMLView(0,0,ClientWidth(window),ClientHeight(window),window)
+SetGadgetLayout htmlview,1,1,1,1 
+
+HtmlViewGo htmlview,"www.blitzmax.com"
+
+While WaitEvent()
+	Print CurrentEvent.ToString()
+	Select EventID()
+		Case EVENT_WINDOWCLOSE
+			End
+	End Select
+Wend

+ 17 - 0
maxgui.mod/doc/createlabel.bmx

@@ -0,0 +1,17 @@
+' createlabel.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+Local window:TGadget
+
+window=CreateWindow("My Window",30,20,320,480)
+
+CreateLabel("A plain label",10,10,280,52,window)
+CreateLabel("A label with LABEL_FRAME",10,80,280,60,window,LABEL_FRAME)
+CreateLabel("A label with LABEL_SUNKENFRAME",10,150,280,60,window,LABEL_SUNKENFRAME)
+CreateLabel("not applicable",10,220,280,54,window,LABEL_SEPARATOR)
+
+While WaitEvent()<>EVENT_WINDOWCLOSE
+Wend

+ 36 - 0
maxgui.mod/doc/createlistbox.bmx

@@ -0,0 +1,36 @@
+' createlistbox.bmx
+
+Strict
+
+Import MaxGui.Drivers
+
+AppTitle = "ListBox Example"
+
+Global window:TGadget = CreateWindow( AppTitle, 100, 100, 200, 200, Null, WINDOW_TITLEBAR|WINDOW_STATUS|WINDOW_RESIZABLE )
+	
+	Global listbox:TGadget = CreateListBox( 0, 0, ClientWidth(window), ClientHeight(window), window )
+	SetGadgetLayout listbox, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED
+	
+	SetGadgetIconStrip listbox, LoadIconStrip("toolbar.png")
+	AddGadgetItem listbox, "New", False, 0, "Create something."
+	AddGadgetItem listbox, "Open", False, 1, "Open something."
+	AddGadgetItem listbox, "Save", False, 2, "Save something.", "Extra Item Object!"
+	AddGadgetItem listbox, "No Icon", False, -1, "This should not have an icon set."
+	
+
+SelectGadgetItem listbox, 2
+
+While WaitEvent()
+	Print CurrentEvent.ToString()
+	Select EventID()
+		Case EVENT_WINDOWCLOSE, EVENT_APPTERMINATE;End
+		'ListBox Event(s)
+		'EventData() holds the index of the corresponding listbox item.
+		Case EVENT_GADGETSELECT
+			SetStatusText window, "Selected Item Index: " + EventData()
+		Case EVENT_GADGETACTION
+			SetStatusText window, "Double-Clicked Item Index: " + EventData()
+		Case EVENT_GADGETMENU
+			SetStatusText window, "Right-Clicked Item Index: " + EventData()
+	End Select
+Wend

+ 64 - 0
maxgui.mod/doc/createmenu.bmx

@@ -0,0 +1,64 @@
+' createmenu.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+Local window:TGadget
+Local filemenu:TGadget
+Local editmenu:TGadget
+Local helpmenu:TGadget
+
+Const MENU_NEW=101
+Const MENU_OPEN=102
+Const MENU_SAVE=103
+Const MENU_CLOSE=104
+Const MENU_EXIT=105
+
+Const MENU_CUT=106
+Const MENU_COPY=107
+Const MENU_PASTE=108
+
+Const MENU_ABOUT=109
+
+window=CreateWindow("My Window",40,40,320,240)
+
+filemenu=CreateMenu("&File",0,WindowMenu(window))
+CreateMenu"&New",MENU_NEW,filemenu,KEY_N,MODIFIER_COMMAND
+CreateMenu"&Open",MENU_OPEN,filemenu,KEY_O,MODIFIER_COMMAND
+CreateMenu"&Close",MENU_CLOSE,filemenu,KEY_W,MODIFIER_COMMAND
+CreateMenu"",0,filemenu
+CreateMenu"&Save",MENU_SAVE,filemenu,KEY_S,MODIFIER_COMMAND
+Local saves:TGadget = CreateMenu("Save More",0,filemenu)
+CreateMenu"",0,filemenu
+CreateMenu"E&xit",MENU_EXIT,filemenu,KEY_F4,MODIFIER_COMMAND
+
+editmenu=CreateMenu("&Edit",0,WindowMenu(window))
+CreateMenu "Cu&t",MENU_CUT,editmenu,KEY_X,MODIFIER_COMMAND
+CreateMenu "&Copy",MENU_COPY,editmenu,KEY_C,MODIFIER_COMMAND
+CreateMenu "&Paste",MENU_PASTE,editmenu,KEY_V,MODIFIER_COMMAND
+
+helpmenu=CreateMenu("&Help",0,WindowMenu(window))
+CreateMenu "&About",MENU_ABOUT,helpmenu
+
+CreateMenu("Option 1", 110,saves)
+Local opt:TGadget = CreateMenu("Option 2", 111,saves)
+
+UpdateWindowMenu window
+
+While True
+	WaitEvent 
+	Select EventID()
+		Case EVENT_WINDOWCLOSE
+			End
+		Case EVENT_MENUACTION
+			Select EventData()
+				Case MENU_EXIT
+					End
+				Case MENU_ABOUT
+					Notify "Incrediabler~n(C)2005 Incredible Software"
+				Case 111
+					CheckMenu(opt)
+			End Select
+	End Select
+Wend

+ 34 - 0
maxgui.mod/doc/createpanel.bmx

@@ -0,0 +1,34 @@
+' createpanel.bmx
+
+Strict
+
+Import MaxGui.Drivers
+
+AppTitle = "Panel Example"
+
+Local window:TGadget = CreateWindow( AppTitle, 100, 100, 440, 240, Null, WINDOW_TITLEBAR|WINDOW_CLIENTCOORDS|WINDOW_RESIZABLE )
+
+' create an active panel that occupies entire window client area
+
+Local panel:TGadget = CreatePanel(0,0,ClientWidth(window),ClientHeight(window),window,PANEL_ACTIVE)
+SetGadgetLayout panel, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED
+
+' and add to it a smaller green panel with a sunken edge
+
+Local panel2:TGadget = CreatePanel(10,10,200,200,panel,PANEL_ACTIVE|PANEL_SUNKEN)
+SetGadgetColor(panel2,160,255,160)
+
+' and finally a group panel with a child button
+
+Local group:TGadget = CreatePanel(220,10,200,200,panel,PANEL_GROUP,"Group Label")
+Local button:TGadget = CreateButton("Push Button",0,10,ClientWidth(group)-20,26,group)
+
+
+Repeat
+	WaitEvent()
+	Print CurrentEvent.ToString()
+	Select EventID()
+		Case EVENT_WINDOWCLOSE, EVENT_APPTERMINATE
+			End
+	End Select
+Forever

+ 24 - 0
maxgui.mod/doc/createprogbar.bmx

@@ -0,0 +1,24 @@
+' createprogbar.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+Local window:TGadget=CreateWindow("My Window",50,50,240,100,,WINDOW_TITLEBAR)
+
+Local progbar:TGadget=CreateProgBar(10,10,200,20,window)
+
+CreateLabel "Please Wait",10,40,200,20,window
+
+CreateTimer 10
+
+While WaitEvent()
+	Select EventID()
+		Case EVENT_WINDOWCLOSE
+			End
+		Case EVENT_TIMERTICK
+			Local t=EventData()
+			If t=50 End
+			UpdateProgBar progbar,t/50.0
+	End Select
+Wend

+ 42 - 0
maxgui.mod/doc/createslider.bmx

@@ -0,0 +1,42 @@
+' createslider.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+Local window:TGadget=CreateWindow("My Window",0,0,240,240,,WINDOW_TITLEBAR)
+
+Local slider:TGadget[3]
+
+' standard vertical and horizontal scroll bars
+
+slider[0]=CreateSlider(10,10,16,100,window,SLIDER_VERTICAL)
+slider[1]=CreateSlider(30,10,100,16,window,SLIDER_HORIZONTAL)
+
+' a horizontal trackbar
+
+slider[2]=CreateSlider(30,30,100,24,window,SLIDER_HORIZONTAL|SLIDER_TRACKBAR)
+
+' a row of vertical trackbars
+
+Local trackbar:TGadget[5]
+
+For Local i=0 To 4
+	trackbar[i]=CreateSlider(30+i*20,50,16,60,window,SLIDER_VERTICAL|SLIDER_TRACKBAR)
+Next
+
+' a single stepper
+
+Local stepper:TGadget
+stepper=CreateSlider(10,120,24,24,window,SLIDER_STEPPER)
+
+SetSliderValue stepper,4
+Print SliderValue(stepper)
+
+While WaitEvent()
+	Print CurrentEvent.ToString()
+	Select EventID()
+		Case EVENT_WINDOWCLOSE
+			End
+	End Select
+Wend

+ 65 - 0
maxgui.mod/doc/createtabber.bmx

@@ -0,0 +1,65 @@
+' createtabber.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+Local window:TGadget
+Local tabber:TGadget
+Local document:TGadget[3]
+Local currentdocument:TGadget
+
+' CreateDocument creates a hidden panel that fills entire tabber client area 
+
+Function CreateDocument:TGadget(tabber:TGadget)
+	Local	panel:TGadget
+	panel=CreatePanel(0,0,ClientWidth(tabber),ClientHeight(tabber),tabber)
+	SetGadgetLayout panel,1,1,1,1
+	HideGadget panel
+	Return panel
+End Function
+
+' create a default window with a tabber gadget that fills entire client area
+
+window=CreateWindow("My Window",30,20,400,300)
+
+tabber=CreateTabber(0,0,ClientWidth(window),ClientHeight(window),window)
+SetGadgetLayout tabber,1,1,1,1 
+
+' add three items and corresponding document panels to the tabber
+
+AddGadgetItem tabber,"Document 0 R",False,-1,""
+AddGadgetItem tabber,"Document 1 G",False,-1,"Tabber Tip 1"
+AddGadgetItem tabber,"Document 2 B",False,-1,"tips 4 2"
+
+document[0]=CreateDocument(tabber)
+document[1]=CreateDocument(tabber)
+document[2]=CreateDocument(tabber)
+
+SetPanelColor document[0],255,200,200
+SetPanelColor document[1],200,255,200
+SetPanelColor document[2],200,200,255
+
+' our documents start off hidden so make first one current and show
+
+currentdocument=document[0]
+ShowGadget currentdocument
+
+' standard message loop with special tabber EVENT_GADGETACTION and EVENT_GADGETMENU handling
+
+While WaitEvent()
+	Select EventID()
+		Case EVENT_GADGETACTION
+			If EventSource()=tabber
+				HideGadget currentdocument
+				currentdocument=document[EventData()]
+				ShowGadget currentdocument
+			EndIf
+		Case EVENT_GADGETMENU
+			If EventSource()=tabber
+				Notify "You right clicked the tab with index " + EventData() + "!"
+			EndIf
+		Case EVENT_WINDOWCLOSE
+			End
+	End Select
+Wend

+ 29 - 0
maxgui.mod/doc/createtextarea.bmx

@@ -0,0 +1,29 @@
+' createtextarea.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+Global window:TGadget = CreateWindow( "My Window", 130, 20, 400, 400 )
+
+Global textarea:TGadget = CreateTextArea( 0, 0, ClientWidth(window), ClientHeight(window), window )
+	SetGadgetLayout( textarea, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED )
+	SetGadgetText( textarea, "A TextArea gadget. :-)~n~nOne line...~n...and then another!")
+	ActivateGadget( textarea )
+
+' Select the entire third (index: 2 [base-0]) line.
+SelectTextAreaText( textarea, 2, 1, TEXTAREA_LINES )
+
+' Output the properties of the current text selection (should be 1, 1 as set above).
+Print "TextAreaCursor(): " + TextAreaCursor( textarea, TEXTAREA_LINES )
+Print "TextAreaSelLen(): " + TextAreaSelLen( textarea, TEXTAREA_LINES )
+
+While WaitEvent()
+	Print CurrentEvent.ToString()
+	Select EventID()
+		Case EVENT_WINDOWCLOSE
+			End
+		Case EVENT_APPTERMINATE
+			End
+	End Select
+Wend

+ 35 - 0
maxgui.mod/doc/createtextfield.bmx

@@ -0,0 +1,35 @@
+' createtextfield.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+Local window:TGadget
+Local textfield:TGadget
+Local button:TGadget
+
+window=CreateWindow("My Window",30,20,320,200)
+
+textfield=CreateTextField(4,4,120,22,window)
+SetGadgetText( textfield,"A textfield gadget" )
+
+' we need an OK button to catch return key
+
+button=CreateButton("OK",130,4,80,24,window,BUTTON_OK)
+
+ActivateGadget textfield
+
+While WaitEvent()
+	Print CurrentEvent.ToString()
+	Select EventID()
+	Case EVENT_GADGETACTION
+		Select EventSource()
+			Case textfield
+				Print "textfield updated"
+			Case button
+				Print "return key / OK button pressed"
+		End Select
+	Case EVENT_WINDOWCLOSE
+		End
+	End Select
+Wend

+ 23 - 0
maxgui.mod/doc/createtimer.bmx

@@ -0,0 +1,23 @@
+' createtimer.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+Local window:TGadget
+Local label:TGadget
+
+window=CreateWindow("Timer Test",40,40,160,64,Null,WINDOW_TITLEBAR)
+label=CreateLabel("",10,10,200,20,window)
+
+CreateTimer(1)
+
+While True
+	WaitEvent 
+	Select EventID()
+		Case EVENT_WINDOWCLOSE
+			End
+		Case EVENT_TIMERTICK
+			SetGadgetText label,CurrentTime()
+	End Select
+Wend

+ 37 - 0
maxgui.mod/doc/createtoolbar.bmx

@@ -0,0 +1,37 @@
+' createtoolbar.bmx
+
+Strict
+
+Import MaxGui.Drivers
+
+AppTitle = "ToolBar Example"
+
+Global window:TGadget = CreateWindow( AppTitle, 100, 100, 400, 32, Null, WINDOW_TITLEBAR|WINDOW_STATUS|WINDOW_RESIZABLE|WINDOW_CLIENTCOORDS )
+
+	Global toolbar:TGadget = CreateToolBar( "toolbar.png", 0, 0, 0, 0, window )
+
+	DisableGadgetItem toolbar, 2
+	
+	SetToolBarTips toolbar, ["New", "Open", "Save should be disabled."] 
+	
+	AddGadgetItem toolbar, "", 0, GADGETICON_SEPARATOR	'Add a separator.
+	AddGadgetItem toolbar, "Toggle", GADGETITEM_TOGGLE, 2, "This toggle button should change to a light bulb when clicked."
+
+	Global button:TGadget = CreateButton( "Show/Hide Toolbar", 2, 2, 180, 28, window )
+	SetGadgetLayout button, EDGE_ALIGNED, EDGE_CENTERED, EDGE_ALIGNED, EDGE_CENTERED
+	
+While WaitEvent()
+	Print CurrentEvent.ToString()
+	Select EventID()
+		Case EVENT_WINDOWCLOSE, EVENT_APPTERMINATE;End
+		'ToolBar Event(s)
+		'EventData() holds the index of the toolbar item clicked.
+		Case EVENT_GADGETACTION
+			Select EventSource()
+				Case button
+					If GadgetHidden(toolbar) Then ShowGadget(toolbar) Else HideGadget(toolbar)
+				Case toolbar 
+					SetStatusText window, "Toolbar Item Clicked: " + EventData()
+			EndSelect
+	End Select
+Wend

+ 30 - 0
maxgui.mod/doc/createtreeview.bmx

@@ -0,0 +1,30 @@
+' createtreeview.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+Local window:TGadget=CreateWindow("My Window",50,50,240,240,Null,WINDOW_TITLEBAR|WINDOW_CLIENTCOORDS)
+Local treeview:TGadget=CreateTreeView(5,5,ClientWidth(window)-10,ClientHeight(window)-10,window)
+
+SetGadgetLayout treeview, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED
+
+Local root:TGadget=TreeViewRoot(treeview)
+
+Local help:TGadget=AddTreeViewNode("Help",root)
+AddTreeViewNode "Topic 1",help
+AddTreeViewNode "Topic 2",help
+AddTreeViewNode "Topic 3",help
+
+Local projects:TGadget=AddTreeViewNode("Projects",root)
+AddTreeViewNode("Sub Project",AddTreeViewNode("Project 1",projects))
+AddTreeViewNode("Project 2",projects)
+AddTreeViewNode("Project 3",projects)
+
+While WaitEvent()
+	Print CurrentEvent.ToString()
+	Select EventID()
+		Case EVENT_WINDOWCLOSE
+			End
+	End Select
+Wend

+ 36 - 0
maxgui.mod/doc/createwindow.bmx

@@ -0,0 +1,36 @@
+' createwindow.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+AppTitle = "CreateWindow() Example"
+
+Global FLAGS:Int
+
+' Comment/uncomment any of the following lines to experiment with the different styles.
+
+FLAGS:| WINDOW_TITLEBAR
+FLAGS:| WINDOW_RESIZABLE
+FLAGS:| WINDOW_MENU
+FLAGS:| WINDOW_STATUS
+FLAGS:| WINDOW_CLIENTCOORDS
+'FLAGS:| WINDOW_HIDDEN
+FLAGS:| WINDOW_ACCEPTFILES
+'FLAGS:| WINDOW_TOOL
+'FLAGS:| WINDOW_CENTER
+
+Local window:TGadget = CreateWindow( AppTitle, 100, 100, 320, 240, Null, FLAGS )
+
+If (FLAGS & WINDOW_STATUS) Then
+	SetStatusText( window, "Left aligned~tCenter aligned~tRight aligned" )
+EndIf
+
+Repeat
+	WaitEvent()
+	Print CurrentEvent.ToString()
+	Select EventID()
+		Case EVENT_APPTERMINATE, EVENT_WINDOWCLOSE
+			End
+	End Select
+Forever

BIN
maxgui.mod/doc/fltkbuttons.png


BIN
maxgui.mod/doc/fltkcombobox.png


BIN
maxgui.mod/doc/fltklistbox.png


BIN
maxgui.mod/doc/fltkmenu.png


BIN
maxgui.mod/doc/fltkpanels.png


BIN
maxgui.mod/doc/fltkprogbar.png


BIN
maxgui.mod/doc/fltksliders.png


BIN
maxgui.mod/doc/fltktabber.png


BIN
maxgui.mod/doc/fltktextarea.png


BIN
maxgui.mod/doc/fltktextfield.png


BIN
maxgui.mod/doc/fltktreeview.png


BIN
maxgui.mod/doc/fltkwindow.png


+ 37 - 0
maxgui.mod/doc/gadgetclass.bmx

@@ -0,0 +1,37 @@
+Strict
+
+Import MaxGUI.Drivers
+
+AppTitle = "GadgetClass() Example"
+Global wndMain:TGadget = CreateWindow(AppTitle,100,100,220,200,Null,WINDOW_TITLEBAR|WINDOW_CLIENTCOORDS|WINDOW_STATUS)
+
+	Global btnTest:TGadget = CreateButton("Push Button",10,10,200,30,wndMain,BUTTON_PUSH)
+	Global chkTest:TGadget = CreateButton("Check Button",10,40,200,30,wndMain,BUTTON_CHECKBOX)
+	
+	Global cmbTest:TGadget = CreateComboBox(10,70,200,26,wndMain)
+		AddGadgetItem(cmbTest,"Item 1");AddGadgetItem(cmbTest,"Item 2",GADGETITEM_DEFAULT);AddGadgetItem(cmbTest,"Item 3")
+	
+	Global sldTest:TGadget = CreateSlider(10,100,200,30,wndMain,SLIDER_HORIZONTAL|SLIDER_TRACKBAR)
+
+Repeat
+
+	WaitEvent()
+	SetStatusText wndMain, CurrentEvent.ToString()
+	
+	Select EventID()
+		
+		Case EVENT_WINDOWCLOSE, EVENT_APPTERMINATE;End
+		
+		Case EVENT_GADGETACTION, EVENT_GADGETSELECT, EVENT_WINDOWMOVE, EVENT_WINDOWSIZE
+			
+			Select GadgetClass(TGadget(EventSource()))
+				Case GADGET_WINDOW;Print "Window Event"
+				Case GADGET_BUTTON;Print "Button Event"
+				Case GADGET_COMBOBOX;Print "ComboBox Event"
+				Case GADGET_SLIDER;Print "Slider Event"
+			EndSelect
+			
+	EndSelect
+	
+Forever
+	

+ 207 - 0
maxgui.mod/doc/intro.bbdoc

@@ -0,0 +1,207 @@
+The MaxGUI module contains commands to create and control user interfaces for developing applications in BlitzMax.
+
+Users should be familiar with the #WaitEvent command and BlitzMax #events which provide the basic communication mechanism 
+between user interface and program when developing MaxGUI applications.
+
++Gadgets
+MaxGUI provides numerous types of gadgets that can be created and arranged for the purposes of providing a user interface to
+BlitzMax applications.
+
+The position of gadgets in relation to their group (parent) gadget can be controlled with the #SetGadgetShape command and 
+monitored with the #GadgetX, #GadgetY, #GadgetWidth and #GadgetHeight commands. Gadgets that can act as group gadgets 
+(such as Windows, Tabbers and Panels) have an inner client region that contains their children, with an area that can be 
+found using #ClientWidth and #ClientHeight.
+
+Gadgets can be made to automatically reposition themselves when their group gadget changes size with the #SetGadgetLayout
+command.
+
+A gadget's group, or parent, gadget can be retrieved using the #GadgetGroup command. A gadget can be shown with #ShowGadget,
+hidden with #HideGadget, its visibility found with the #GadgetHidden function and removed completely from the system with
+the #FreeGadget command. It is now also possible to determine a gadget's class/type using the #GadgetClass command.
+
+#EnableGadget, #DisableGadget and #GadgetDisabled control and determine if a gadget is currently enabled.
+
+#ActivateGadget will set a particular gadget as active so that it is highlighted and receives any keyboard events while
+#ActiveGadget returns which gadget (if any) is currently active.
+
+#SetGadgetText, #SetGadgetFont, #SetGadgetColor and #SetGadgetTextColor change the appearance of many of the MaxGUI gadgets.
+
+Those wanting to store their own object with gadget can do so using the #SetGadgetExtra command - a reference to your object
+will be stored inside the @TGadget type and is retrievable using the matching #GadgetExtra command. The object reference will
+be overwritten by future calls to #SetGadgetExtra or when #FreeGadget is called.
+
+Recently, #SetGadgetTooltip and #GadgetTooltip have been added to MaxGUI to allow tooltips to be set on standard
+%{non list-based} gadgets, including Buttons, Labels, TextFields etc.
+
+Tooltips are set on an item-by-item basis for gadgets such as ListBoxes and Tabbers etc. 
+Attempting to set an overall gadget tooltip on a %{list-based} gadget will have no effect.
+
+Finally, a more generic #SetGadgetPixmap command has been added which will eventually allow you to set pixmaps for many 
+gadgets (not just for panels), depending on your platform. 
+
+<h2>Events</h2>
+Gadgets that allow user-interaction emit events that can be caught and processed in your main application
+loop (typically with the #WaitEvent command). The events a gadget can generate will be listed under the
+corresponding CreateGadget() documentation.
+
+It is important to note, however, that events are only emitted when @{the user} interacts with, or changes the
+state, of a gadget. Any changes made to gadget through MaxGUI command calls (such as #SelectGadgetItem) should 
+not result in events being emitted. 
+
+<h2>Windows</h2>
+<img src="win32window.png"><img src="fltkwindow.png"><img src="osxwindow.png">
+
+A Window is used to contain a collection of gadgets that make up the user interface of an application. The #CreateWindow 
+command creates a window of a specified size that can then be used as the @{group} parameter for the other gadget creation
+commands.
+
+The #WindowMenu command returns a handle that can be used as the parent parameter of the #CreateMenu command to add menus
+to a window. #UpdateWindowMenu should be called after adding/changing a window's menu for the changes to take effect.
+A window can be activated (bringing the window in front, with focus) with the #ActivateWindow command. 
+The text displayed in a window's optional status-bar can be set using the #SetStatusText command.
+
+If a window is created with the WINDOW_RESIZABLE style, its sizing can be restrained using #SetMinWindowSize and 
+#SetMaxWindowSize and it can be minimized, maximized and restored with the #MinimizeWindow, #MaximizeWindow and 
+#RestoreWindow commands. The state of a window can be dermined using #WindowMinimized and #WindowMaximized.
+
+<h2>Menus</h2>
+<img src="win32menu.png"><img src="fltkmenu.png"><img src="osxmenu.png">
+
+The #CreateMenu command is used to create menu-items. Menus can be attached either to a window's menu-bar by parenting them to a 
+#WindowMenu or can popup at the current mouse location if used with the #PopupWindowMenu command.
+
+#CheckMenu adds a tick next to a menu-item and #UncheckMenu removes it.  #DisableGadget will "gray out" a menu item, preventing it from
+being chosen by the user. #EnableGadget reverses this operation.
+
+<h2>Buttons</h2>
+<img src="win32buttons.png"><img src="fltkbuttons.png"><img src="osxbuttons.png">
+
+The #CreateButton command is used to add buttons to a group gadget. Buttons can be standard push buttons that emit a single
+event whenever clicked, or they can be created with the BUTTON_CHECKBOX or BUTTON_RADIO styles
+in which case they can be toggled by the user (or programatically with the #SetButtonState command). 
+Their current state can be found with the help of the #ButtonState function.
+
+<h2>Panels</h2>
+<img src="win32panels.png"><img src="fltkpanels.png"><img src="osxpanels.png">
+
+The #CreatePanel command is used to to create a Panel gadget. Panels can be used to group other gadgets together and
+can be optionally assigned a background color or image using the #SetPanelColor or #SetPanelPixmap commands.  They can
+be created with or without a border. Panels were one of the first gadgets that could emit mouse/key events by 
+specifying the optional PANEL_ACTIVE style upon creation.
+
+<h2>Text Fields</h2>
+<img src="win32textfield.png"><img src="fltktextfield.png"><img src="osxtextfield.png">
+
+A text-field allows the users to enter a single line of text. A text-field's characters can be masked by specifying an 
+optional TEXTFIELD_PASSWORD style flag upon the call to #CreateTextField.  This is useful for creating password-entry
+forms.  As with all other gadgets, #GadgetText and #SetGadgetText can be used to set and retrieve the text in the field.
+
+<h2>Text Areas</h2>
+<img src="win32textarea.png"><img src="fltktextarea.png"><img src="osxtextarea.png">
+
+The #CreateTextArea command creates a gadget for displaying formatted text, with optional TEXTAREA_WORDWRAP and 
+TEXTAREA_READONLY styles.  
+
+The MaxGUI commands specific to text-areas are summarised below:
+
+[ 
+* #SetTextAreaText and #AddTextAreaText allow for convenient editing of the text.
+* #TextAreaText returns either a specified portion or the entire contents of a text-area.
+* #TextAreaLen returns the number of characters or lines currently contained.
+* #TextAreaCursor and #TextAreaSelLen commands return the cursor position and selection length.
+* #SelectTextAreaText command provides a means to programatically select/highlight text.
+* #SetTextAreaFont and #SetTextAreaColor affect the style and appearance of the text displayed in a Text Area. 
+* #SetTextAreaTabs allows you to alter the position of tab stops.
+* #FormatTextAreaText allows sections of text to be formatted using their own colors and font styles. 
+* #LockTextArea and #UnlockTextArea commands should be used to improve performance when formatting lots of text.
+* #TextAreaChar and #TextAreaLine commands convert between line and character positions.
+* #TextAreaCharX and #TextAreaCharY find the x,y coordinates of a character position relative to the top-left corner
+of the gadget.
+]
+
+<h2>Combo Boxes</h2>
+<img src="win32combobox.png"><img src="fltkcombobox.png"><img src="osxcombobox.png">
+
+Combo-boxes provide a dropdown list of options to the user with an optional style that allows the user to enter 
+their own text in a similar manner to the TextField gadget. #CreateComboBox creates a ComboBox and the standard
+list based gadget commands #ClearGadgetItems, #AddGadgetItem, #ModifyGadgetItem, #RemoveGadgetItem, #SelectGadgetItem,
+#SelectedGadgetItem, #CountGadgetItems and #GadgetItemText can be used to manage the items contained by the ComboBox gadget.
+
+<h2>List Boxes</h2>
+<img src="win32listbox.png"><img src="fltklistbox.png"><img src="osxlistbox.png">
+
+List-boxes are similiar to ComboBoxes but features a scrolling list rather than a drop-down selection mechanism.
+The #CreateListBox command is used to create a ListBox gadget while the standard list based gadget commands listed
+in the previous ComboBox section are used to manage the items.
+
+<h2>Toolbars</h2>
+<img src="win32toolbar.png">
+
+Toolbars display a row of clickable icons at the top of a window. The #CreateToolbar command creates a window toolbar 
+using a previously loaded @TIconStrip or using a specified image file containing a strip of icons.
+
+#EnableGadgetItem and #DisableGadgetItem control the interactive state of individual items while #SetToolbarTips
+assigns a list of meaningful strings to the toolbar items.
+
+The recommended icon size for toolbars is 24x24 pixels which seems to work well on most platforms. Using a different
+image size may result in the pixmaps being scaled before being set depending on the OS.
+
+It is important to note that Toolbars should only ever be added to @{Window}s - adding ToolBars to other group gadgets may
+cause your program to crash on some platforms.
+
+<h2>Tabbers</h2>
+<img src="win32tabber.png"><img src="fltktabber.png"><img src="osxtabber.png">
+
+The #CreateTabber command creates a tab control gadget commonly used to group gadgets into a collection of pages. 
+The standard list based gadget commands #ClearGadgetItems, #AddGadgetItem, #ModifyGadgetItem, #RemoveGadgetItem, 
+#SelectGadgetItem, #SelectedGadgetItem, #CountGadgetItems and #GadgetItemText can be used to manage the items contained 
+in a Tabber gadget.
+
+<h2>TreeViews</h2>
+<img src="win32treeview.png"><img src="fltktreeview.png"><img src="osxtreeview.png">
+
+A TreeView is used to display hierarchical data where items are contained in nodes that can be children of other nodes.
+The #CreateTreeView command creates a new TreeView gadget that provides a #TreeViewRoot used to create a tree of nodes.
+
+#AddTreeViewNode, #InsertTreeViewNode, #ModifyTreeViewNode, #ExpandTreeViewNode, #CollapseTreeViewNode and
+#FreeTreeViewNode provide commands to control the the contents of a TreeView.
+
+#SelectedTreeViewNode and #SelectTreeViewNode return and set the currently highlighted node in a TreeView while 
+#CountTreeViewNodes returns the number  of nodes contained in a single TreeViewNode. #FreeTreeViewNode and #ClearTreeView
+can be used to remove nodes previously added to a TreeView gadget.
+
+<h2>HtmlViews</h2>
+<img src="win32htmlview.png">
+
+An HTMLView is a gadget containing a complete web browser display. The #CreateHTMLView command creates an HTMLView gadget
+while #HtmlViewGo, #HtmlViewBack and #HtmlViewForward control the page being displayed.
+
+#HtmlViewStatus and #HtmlViewCurrentURL provide extended information about the state of an HTMLView gadget while
+#HtmlViewRun allows scripts (i.e. javascript) to be run (on some platforms).
+
+<h2>Labels</h2>
+Labels are read-only regions of text on a user inteface that do not have a background and are created with the 
+#CreateLabel command.
+
+<h2>Sliders</h2>
+<img src="win32sliders.png"><img src="fltksliders.png"><img src="osxsliders.png">
+
+Sliders allow the user to control a numerical value by dragging a control inside a container. #CreateSlider can create 
+both a scroll-bar type slider (where the size of the knob represents the portion of the document being viewed) and 
+trackbar style sliders (where the knob is a fixed size and #SetSliderRange controls the minimum and maximum values 
+allowed by the control).
+
+#SetSliderValue and #SliderValue set and retrieve the position of a Slider control.
+
+<h2>Progress Bars</h2>
+<img src="win32progbar.png"><img src="fltkprogbar.png"><img src="osxprogbar.png">
+
+#CreateProgBar creates a progress bar gadget commonly used to display the progress of an operation. The 
+#UpdateProgBar command is used to update the progress bar with a floating point value between 0.0 and 1.0 and
+are typically used to represent how complete the current operation is.
+
+<h2>Desktop</h2>
+A gadget representing the user's desktop is returned by the #Desktop command. The Desktop gadget is particularly useful
+for finding primary screen and workspace resolutions using #GadgetWidth / #GadgetHeight or #ClientWidth / #ClientHeight respectively.
+
+The #LookupGuiFont and #LookupGuiColor commands can be used to retrieve system defined font and color information.

+ 38 - 0
maxgui.mod/doc/lookupguicolor.bmx

@@ -0,0 +1,38 @@
+' lookupguicolor.bmx
+
+Strict
+
+Import MaxGUI.Drivers
+
+AppTitle = "LookupGuiColor() Example"
+
+Global wndMain:TGadget = CreateWindow( AppTitle, 100, 100, 300, 200, Null, WINDOW_TITLEBAR|WINDOW_STATUS )
+
+	Global pnlMain:TGadget = CreatePanel( 0, 0, ClientWidth(wndMain), ClientHeight(wndMain), wndMain )
+	
+		Global cmbColors:TGadget = CreateComboBox( 5, 5, ClientWidth(wndMain) - 10, 28, pnlMain )
+		
+		' Populate combo-box with the available color constants
+		
+		AddGadgetItem cmbColors, "GUICOLOR_WINDOWBG", GADGETITEM_DEFAULT, GUICOLOR_WINDOWBG
+		AddGadgetItem cmbColors, "GUICOLOR_GADGETBG", 0, GUICOLOR_GADGETBG
+		AddGadgetItem cmbColors, "GUICOLOR_GADGETFG", 0, GUICOLOR_GADGETFG
+		AddGadgetItem cmbColors, "GUICOLOR_SELECTIONBG", 0, GUICOLOR_SELECTIONBG
+		AddGadgetItem cmbColors, "GUICOLOR_LINKFG", 0, GUICOLOR_LINKFG
+
+ActivateGadget cmbColors
+
+Repeat
+	Select WaitEvent()
+		
+		Case EVENT_APPTERMINATE, EVENT_WINDOWCLOSE
+			End
+			
+		Case EVENT_GADGETACTION
+			Local red:Byte, green:Byte, blue:Byte
+			LookupGuiColor( GadgetItemIcon( cmbColors, EventData() ), red, green, blue )
+			SetGadgetColor( pnlMain, red, green, blue )
+			SetStatusText( wndMain, "RGB( " + red + ", " + green + ", " + blue + " )" )
+			
+	EndSelect
+Forever

+ 50 - 0
maxgui.mod/doc/lookupguifont.bmx

@@ -0,0 +1,50 @@
+' lookupguifont.bmx
+
+Strict
+
+Import MaxGUI.Drivers
+
+AppTitle = "LookupGuiFont() Example"
+
+Const strSampleText$ = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla eget mauris quis dolor "+..
+"ullamcorper dapibus. Duis facilisis ullamcorper metus. Pellentesque eget enim. Vivamus auctor hendrerit turpis. " + ..
+"Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus tincidunt leo quis urna." 
+
+Const intWindowFlags% = WINDOW_TITLEBAR|WINDOW_RESIZABLE|WINDOW_STATUS|WINDOW_CLIENTCOORDS
+
+Global wndMain:TGadget = CreateWindow( AppTitle, 100, 100, 500, 300, Null, intWindowFlags )
+	SetMinWindowSize( wndMain, ClientWidth(wndMain), ClientHeight(wndMain) )
+Global lstFontTypes:TGadget = CreateListBox(0,0,200,ClientHeight(wndMain),wndMain)
+	SetGadgetLayout lstFontTypes,EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED,EDGE_ALIGNED
+	AddGadgetItem lstFontTypes, "GUIFONT_SYSTEM", GADGETITEM_DEFAULT, -1, "Default OS font.", LookupGuiFont(GUIFONT_SYSTEM)
+	AddGadgetItem lstFontTypes, "GUIFONT_SERIF", 0, -1, "Serif font.", LookupGuiFont(GUIFONT_SERIF)
+	AddGadgetItem lstFontTypes, "GUIFONT_SANSSERIF", 0, -1, "Sans serif font.", LookupGuiFont(GUIFONT_SANSSERIF)
+	AddGadgetItem lstFontTypes, "GUIFONT_SCRIPT", 0, -1, "Script/handwriting font.", LookupGuiFont(GUIFONT_SCRIPT)
+	AddGadgetItem lstFontTypes, "GUIFONT_MONOSPACED", 0, -1, "Fixed width/coding font.", LookupGuiFont(GUIFONT_MONOSPACED)
+
+Global txtPreview:TGadget = CreateTextArea(200,0,300,ClientHeight(wndMain),wndMain,TEXTAREA_WORDWRAP|TEXTAREA_READONLY)
+	SetGadgetLayout txtPreview,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+	SetTextAreaText( txtPreview, strSampleText )
+
+Global strFontString$
+
+ChooseFont( LookupGuiFont() )
+
+Repeat
+	Select WaitEvent()
+		Case EVENT_APPTERMINATE, EVENT_WINDOWCLOSE;End
+		Case EVENT_GADGETACTION, EVENT_GADGETSELECT
+			Select EventSource()
+				Case lstFontTypes
+					If EventData() >= 0 Then
+						ChooseFont( TGuiFont(GadgetItemExtra( lstFontTypes, EventData() )) )
+					EndIf
+			EndSelect
+	EndSelect
+	SetStatusText( wndMain, strFontString + "~t~t" + CurrentEvent.ToString() + "   " )
+Forever
+
+Function ChooseFont( pFont:TGuiFont )
+	SetGadgetFont( txtPreview, pFont )
+	strFontString$ = FontName(pFont) + ", " + Int(FontSize(pFont)) + "pt"
+EndFunction

BIN
maxgui.mod/doc/osxbuttons.png


BIN
maxgui.mod/doc/osxcombobox.png


BIN
maxgui.mod/doc/osxlistbox.png


BIN
maxgui.mod/doc/osxmenu.png


BIN
maxgui.mod/doc/osxpanels.png


BIN
maxgui.mod/doc/osxprogbar.png


BIN
maxgui.mod/doc/osxsliders.png


BIN
maxgui.mod/doc/osxtabber.png


BIN
maxgui.mod/doc/osxtextarea.png


BIN
maxgui.mod/doc/osxtextfield.png


BIN
maxgui.mod/doc/osxtreeview.png


BIN
maxgui.mod/doc/osxwindow.png


+ 30 - 0
maxgui.mod/doc/popupwindowmenu.bmx

@@ -0,0 +1,30 @@
+Strict
+
+Import MaxGui.Drivers
+
+Local menu:TGadget
+Local window:TGadget
+Local panel:TGadget
+
+menu=CreateMenu("popup",0,Null)
+CreateMenu("Load",101,menu)
+CreateMenu("Save",102,menu)
+
+window=CreateWindow("Test PopupWindowMenu",20,20,200,200)
+
+' create a panel to capture some mouse events
+
+panel=CreatePanel(0,0,ClientWidth(window),ClientHeight(window),window,PANEL_ACTIVE)
+
+While True
+	WaitEvent
+	Select EventID()
+		Case EVENT_MOUSEDOWN
+			If EventData()=2 PopupWindowMenu window,menu
+		Case EVENT_WINDOWCLOSE
+			End
+		Case EVENT_MENUACTION
+			Print "EVENT_MENUACTION: eventdata()="+EventData()
+	End Select
+Wend
+

+ 89 - 0
maxgui.mod/doc/redrawgadget.bmx

@@ -0,0 +1,89 @@
+' redrawgadget.bmx
+
+' version 3 - fixed to be compatible with virtual resolutions
+
+Import MaxGui.Drivers
+
+Strict
+
+Type TApplet 
+
+	Method OnEvent(Event:TEvent) Abstract
+
+	Method Run()
+		AddHook EmitEventHook,eventhook,Self
+	End Method
+
+	Function eventhook:Object(id,data:Object,context:Object)
+		Local event:TEvent = TEvent(data)
+		Local app:TApplet = TApplet(context)
+		app.OnEvent( event )
+		Return data
+	End Function
+
+End Type
+
+Type TSpinningApplet Extends TApplet
+	
+	Global image:TImage
+	
+	Field timer:TTimer
+	Field window:TGadget, canvas:TGadget
+	
+	Method Draw()
+		
+		SetGraphics CanvasGraphics(canvas)
+		SetVirtualResolution ClientWidth(canvas),ClientHeight(canvas)
+		SetViewport 0,0,ClientWidth(canvas), ClientHeight(canvas)
+		
+		SetBlend( ALPHABLEND )
+		SetRotation( MilliSecs()*.1 )
+		SetClsColor( 255, 0, 0 )
+		
+		Cls()
+		DrawImage( image, GraphicsWidth()/2, GraphicsHeight()/2 )
+		
+		Flip()
+		
+	End Method
+	
+	Method OnEvent(event:TEvent)
+		If Not event Then Return 
+		Select event.id
+			Case EVENT_WINDOWCLOSE, EVENT_APPTERMINATE
+				End
+			Case EVENT_TIMERTICK
+				RedrawGadget( canvas )
+			Case EVENT_GADGETPAINT
+				If (event.source = canvas) Then Draw()
+		End Select
+	End Method
+	
+	Method Create:TSpinningApplet(name$)
+		
+		If Not image Then image = LoadImage( "fltkwindow.png" )
+		
+		window = CreateWindow( name, 20, 20, 512, 512 )
+		
+		Local w = ClientWidth(window)
+		Local h = ClientHeight(window)
+		
+		canvas = CreateCanvas( 0, 0, w, h, window )
+		SetGadgetLayout( canvas, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED )
+		
+		timer = CreateTimer( 100 )
+		Run()
+		
+		Return Self
+		
+	End Method
+	
+End Type
+
+AutoMidHandle True
+
+Local spinner:TSpinningApplet = New TSpinningApplet.Create("Spinning Applet")
+
+Repeat
+	WaitSystem()
+Forever

+ 28 - 0
maxgui.mod/doc/requestcolor.bmx

@@ -0,0 +1,28 @@
+' requestcolor.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+Local window:TGadget
+Local panel:TGadget
+Local red,green,blue
+
+window=CreateWindow("RequestColor",40,40,320,240)
+panel=CreatePanel(20,20,32,32,window,PANEL_ACTIVE|PANEL_SUNKEN)
+
+While True
+	WaitEvent 
+	Select EventID()
+		Case EVENT_WINDOWCLOSE
+			End
+		Case EVENT_MOUSEDOWN
+			If RequestColor(red,green,blue)
+				red=RequestedRed()
+				green=RequestedGreen()
+				blue=RequestedBlue()
+				SetPanelColor panel,red,green,blue
+			EndIf				
+	End Select
+Wend
+

+ 33 - 0
maxgui.mod/doc/requestfont.bmx

@@ -0,0 +1,33 @@
+' requestfont.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+AppTitle = "RequestFont() Example"
+
+Const teststring:String = "The quick brown fox jumps over the lazy dog."
+
+Local window:TGadget = CreateWindow(AppTitle,50,50,300,200,Null,WINDOW_TITLEBAR|WINDOW_STATUS|WINDOW_RESIZABLE)
+	SetMinWindowSize window, GadgetWidth(window), GadgetHeight(window)
+	
+	Local label:TGadget = CreateLabel(teststring,0,0,ClientWidth(window),ClientHeight(window)-26,window)
+		SetGadgetLayout label, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_CENTERED
+	
+	Local button:TGadget = CreateButton("Select Font",0,ClientHeight(window)-26,ClientWidth(window),26,window)
+		SetGadgetLayout button, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_CENTERED, EDGE_ALIGNED
+
+Local font:TGUIFont
+
+Repeat
+	Select WaitEvent()
+		Case EVENT_WINDOWCLOSE, EVENT_APPTERMINATE
+			End
+		Case EVENT_GADGETACTION
+			font = RequestFont(font)
+			If font Then
+				SetGadgetFont label, font
+				SetStatusText window,FontName(font) + ": " + Int(FontSize(font)+0.5) + "pt"
+			EndIf
+	End Select
+Forever

+ 40 - 0
maxgui.mod/doc/setgadgetfilter.bmx

@@ -0,0 +1,40 @@
+' setgadgetfilter.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+Local window:TGadget
+Global textarea:TGadget
+
+window=CreateWindow("My Window",30,20,320,240)
+
+textarea=CreateTextArea(0,24,ClientWidth(window),ClientHeight(window)-24,window)
+
+SetGadgetLayout textarea,1,1,1,1
+SetGadgetText textarea,"A textarea gadget that filters out down arrows~nand tab keys."
+ActivateGadget textarea
+
+SetGadgetFilter textarea,filter
+
+Print "KEY_TAB="+KEY_TAB
+
+Function filter(event:TEvent,context:Object)
+	Select event.id
+		Case EVENT_KEYDOWN
+			Print "filtering keydown:"+event.data+","+event.mods
+			If event.data=KEY_DOWN Return 0
+			If event.data=13 Return 0
+		Case EVENT_KEYCHAR
+			Print "filtering charkey:"+event.data+","+event.mods
+			If event.data=KEY_TAB Return 0
+	End Select
+	Return 1
+End Function
+
+While WaitEvent()
+	Select EventID()
+		Case EVENT_WINDOWCLOSE
+			End
+	End Select
+Wend

+ 41 - 0
maxgui.mod/doc/setpointer.bmx

@@ -0,0 +1,41 @@
+' setpointer.bmx
+
+Import MaxGui.Drivers
+
+Strict 
+
+Local window:TGadget
+Local combo:TGadget
+
+window=CreateWindow("SetPointer",40,40,320,240,,WINDOW_TITLEBAR)
+
+CreateLabel "Select a pointer shape:",10,10,200,20,window
+
+combo=CreateComboBox(10,30,200,24,window)
+AddGadgetItem combo,"POINTER_DEFAULT"
+AddGadgetItem combo,"POINTER_ARROW"
+AddGadgetItem combo,"POINTER_IBEAM" 
+AddGadgetItem combo,"POINTER_WAIT" 
+AddGadgetItem combo,"POINTER_CROSS"
+AddGadgetItem combo,"POINTER_UPARROW" 
+AddGadgetItem combo,"POINTER_SIZENWSE" 
+AddGadgetItem combo,"POINTER_SIZENESW" 
+AddGadgetItem combo,"POINTER_SIZEWE" 
+AddGadgetItem combo,"POINTER_SIZENS" 
+AddGadgetItem combo,"POINTER_SIZEALL" 
+AddGadgetItem combo,"POINTER_NO" 
+AddGadgetItem combo,"POINTER_HAND"
+AddGadgetItem combo,"POINTER_APPSTARTING"
+AddGadgetItem combo,"POINTER_HELP"
+
+SelectGadgetItem combo,0
+
+While True
+	WaitEvent 
+	Select EventID()
+		Case EVENT_WINDOWCLOSE
+			End
+		Case EVENT_GADGETACTION
+			SetPointer EventData()
+	End Select
+Wend

BIN
maxgui.mod/doc/toolbar.png


BIN
maxgui.mod/doc/win32buttons.png


BIN
maxgui.mod/doc/win32combobox.png


BIN
maxgui.mod/doc/win32htmlview.png


BIN
maxgui.mod/doc/win32listbox.png


BIN
maxgui.mod/doc/win32menu.png


BIN
maxgui.mod/doc/win32panels.png


BIN
maxgui.mod/doc/win32progbar.png


BIN
maxgui.mod/doc/win32sliders.png


BIN
maxgui.mod/doc/win32tabber.png


BIN
maxgui.mod/doc/win32textarea.png


BIN
maxgui.mod/doc/win32textfield.png


BIN
maxgui.mod/doc/win32toolbar.png


BIN
maxgui.mod/doc/win32treeview.png


BIN
maxgui.mod/doc/win32window.png


+ 192 - 0
maxgui.mod/driver.bmx

@@ -0,0 +1,192 @@
+Strict
+
+Import "gadget.bmx"
+Import "guifont.bmx"
+
+Import MaxGUI.Localization
+Import Brl.Map
+
+Type TMaxGUIDriver
+	
+	Method UserName$() Abstract	
+	Method ComputerName$() Abstract
+	
+	Method LoadFont:TGuiFont(name$,size,flags) Abstract
+	Method CreateGadget:TGadget(GadgetClass,name$,x,y,w,h,group:TGadget,style) Abstract
+	Method ActiveGadget:TGadget() Abstract
+	Method RequestColor(r,g,b) Abstract
+	Method RequestFont:TGuiFont(font:TGuiFont) Abstract	
+	Method SetPointer(shape) Abstract
+	Method LoadIconStrip:TIconStrip(source:Object) Abstract
+	
+	Method LookupColor( colorindex:Int, pRed:Byte Var, pGreen:Byte Var, pBlue:Byte Var )
+		
+		Select colorindex
+			Case GUICOLOR_WINDOWBG
+				pRed = 240; pGreen = 240; pBlue = 240
+			Case GUICOLOR_GADGETBG
+				pRed = 255; pGreen = 255; pBlue = 255
+			Case GUICOLOR_GADGETFG
+				pRed = 0; pGreen = 0; pBlue = 0
+			Case GUICOLOR_SELECTIONBG
+				pRed = 50; pGreen = 150; pBlue = 255
+			Case GUICOLOR_LINKFG
+				pRed = 0; pGreen = 0; pBlue = 255
+		EndSelect
+		
+		Return False
+		
+	EndMethod
+	
+	Method LibraryFont:TGuiFont( pFontType% = GUIFONT_SYSTEM, pFontSize:Double = 0, pFontStyle% = FONT_NORMAL )
+		?Win32
+		If pFontSize <= 0 Then
+			Select pFontType
+				Case GUIFONT_SYSTEM;pFontSize = 8
+				Case GUIFONT_SERIF;pFontSize = 11
+				Default;pFontSize = 10
+			EndSelect
+		EndIf
+		?Not Win32
+		If pFontSize <= 0 Then
+			pFontSize = 12
+			?MacOs
+			If pFontType = GUIFONT_SYSTEM Then pFontSize = 11
+		?Not Win32
+		EndIf
+		?
+		Select pFontType
+			Case GUIFONT_MONOSPACED
+				?Linux
+				Return LoadFontWithDouble("Lucida",pFontSize,pFontStyle)
+				?MacOS
+				Return LoadFontWithDouble("Monaco",pFontSize,pFontStyle)
+				?Win32
+				'Let's give any Vista users the chance to use the new Consolas font.
+				Local tmpFont:TGuiFont = LoadFontWithDouble("Consolas",pFontSize,pFontStyle)
+				If tmpFont.name = "Consolas" Then Return tmpFont
+				Return LoadFontWithDouble("Courier New",pFontSize,pFontStyle)
+				?
+			Case GUIFONT_SANSSERIF
+				?Linux
+				Return LoadFontWithDouble("FreeSans",pFontSize,pFontStyle)
+				?MacOS
+				Return LoadFontWithDouble("Helvetica",pFontSize,pFontStyle)
+				?Win32
+				Return LoadFontWithDouble("Arial",pFontSize,pFontStyle)
+				?
+			Case GUIFONT_SERIF
+				?Linux
+				Return LoadFontWithDouble("FreeSerif",pFontSize,pFontStyle)
+				?MacOS
+				Return LoadFontWithDouble("Times New Roman",pFontSize,pFontStyle)
+				?Win32
+				Return LoadFontWithDouble("Times New Roman",pFontSize,pFontStyle)
+				?
+			Case GUIFONT_SCRIPT
+				?Linux
+				Return LoadFontWithDouble("TSCu_Comic",pFontSize,pFontStyle)
+				?MacOS
+				Return LoadFontWithDouble("Comic Sans MS",pFontSize,pFontStyle)
+				?Win32
+				Return LoadFontWithDouble("Comic Sans MS",pFontSize,pFontStyle)
+				?
+			Default	'GUIFONT_SYSTEM
+				?Linux
+				Return LoadFontWithDouble("FreeSans",pFontSize,pFontStyle)
+				?MacOS
+				Return LoadFontWithDouble("Lucida Grande",pFontSize,pFontStyle)
+				?Win32
+				Return LoadFontWithDouble("MS Shell Dlg",pFontSize,pFontStyle)
+				?
+		EndSelect
+	EndMethod
+	
+	Method LoadFontWithDouble:TGuiFont(name$,size:Double,flags)
+		Return LoadFont(name,Int(size+0.5),flags)
+	EndMethod
+	
+	' Localization Code
+	
+	Field _mapLocalized:TMap = CreateMap()
+	
+	Method SetLocalizationMode( Mode:Int )
+		Local tmpApply:Int = False
+		If (LocalizationMode() ~ Mode) & LOCALIZATION_ON Then tmpApply = True
+		engine_SetLocalizationMode(Mode)
+		If tmpApply Then ApplyLanguage()
+	EndMethod
+	
+	Method SetLanguage( language:TMaxGUILanguage )
+		engine_SetLocalizationLanguage(language)
+		ApplyLanguage()
+	EndMethod
+	
+	Method ApplyLanguage()
+		For Local tmpGadget:TGadget = EachIn MapKeys(_mapLocalized)
+			ApplyLocalization( tmpGadget )
+		Next
+	EndMethod
+	
+	Method SetGadgetLocalization( gadget:TGadget, text$, tooltip$ )
+		If gadget Then
+			MapInsert _mapLocalized, gadget, [text,tooltip]
+			ApplyLocalization( gadget )
+		EndIf
+	EndMethod
+	
+	Method ApplyLocalization( gadget:TGadget )
+		If gadget.Class() <> GADGET_CANVAS Then
+			Local tmpString$[] = String[](MapValueForKey( _mapLocalized, gadget ))
+			gadget.SetText(LocalizeString(tmpString[0]))
+			gadget.SetTooltip(LocalizeString(tmpString[1]))
+			For Local i:Int = 0 Until gadget.items.length
+				If Max(gadget.ItemFlags(i),0)&GADGETITEM_LOCALIZED Then
+					LocalizeGadgetItem( gadget, i )
+				EndIf
+			Next
+		EndIf
+	EndMethod
+	
+	Method LocalizeGadgetItem( gadget:TGadget, index:Int )
+		gadget.SetListItem(index,LocalizeString(gadget.ItemText(index)),LocalizeString(gadget.ItemTip(index)),gadget.ItemIcon(index),gadget.ItemExtra(index))
+	EndMethod
+	
+	Method GadgetLocalized:Int( gadget:TGadget )
+		Return MapContains( _mapLocalized, gadget )
+	EndMethod
+	
+	Method DelocalizeGadget( gadget:TGadget )
+		MapRemove _mapLocalized, gadget
+	EndMethod
+	
+End Type
+
+Global maxgui_driver:TMaxGUIDriver
+
+' Localization Handling
+
+Const LOCALIZATION_OVERRIDE:Int = 2
+
+Private
+
+Function DelocalizeGadget(gadget:TGadget)
+	maxgui_driver.DelocalizeGadget(gadget)
+EndFunction
+
+Function driver_SetLocalizationMode(Mode:Int)
+	maxgui_driver.SetLocalizationMode(Mode)
+EndFunction
+
+Function driver_SetLocalizationLanguage(language:TMaxGUILanguage)
+	maxgui_driver.SetLanguage(language)
+EndFunction
+
+Global engine_SetLocalizationMode( Mode:Int ) = _SetLocalizationMode
+Global engine_SetLocalizationLanguage( language:TMaxGUILanguage ) = _SetLocalizationLanguage
+
+_SetLocalizationMode = driver_SetLocalizationMode
+_SetLocalizationLanguage = driver_SetLocalizationLanguage
+
+TGadget.LocalizeString = LocalizeString
+TGadget.DelocalizeGadget = DelocalizeGadget

+ 43 - 0
maxgui.mod/event.bmx

@@ -0,0 +1,43 @@
+Strict
+
+Import BRL.Event
+
+Import "gadget.bmx"
+
+Function PostGuiEvent( id,source:TGadget=Null,data=0,mods=0,x=0,y=0,extra:Object=Null )
+
+	If source Then
+		While source.source
+			source=source.source
+		Wend
+	EndIf
+
+	EmitEvent CreateEvent( id,source,data,mods,x,y,extra )
+		
+End Function
+
+Function QueueGuiEvent( id,source:TGadget=Null,data=0,mods=0,x=0,y=0,extra:Object=Null )
+
+	If source Then
+		While source.source
+			source=source.source
+		Wend
+	EndIf
+
+	eventQueue.AddLast CreateEvent( id,source,data,mods,x,y,extra )
+		
+End Function
+
+Function DispatchGuiEvents()
+
+	For Local tmpEvent:TEvent = EachIn eventQueue
+		EmitEvent tmpEvent
+	Next
+	
+	eventQueue.Clear()
+	
+End Function
+
+Private
+
+Global eventQueue:TList = New TList

+ 1095 - 0
maxgui.mod/gadget.bmx

@@ -0,0 +1,1095 @@
+Strict
+
+Import BRL.LinkedList
+Import BRL.Graphics
+Import BRL.Pixmap
+
+Import "guifont.bmx"
+Import "iconstrip.bmx"
+Import "gadgetitem.bmx"
+
+Const GADGET_DESKTOP=0
+Const GADGET_WINDOW=1
+Const GADGET_BUTTON=2
+Const GADGET_PANEL=3
+Const GADGET_TEXTFIELD=4
+Const GADGET_TEXTAREA=5
+Const GADGET_COMBOBOX=6
+Const GADGET_LISTBOX=7
+Const GADGET_TOOLBAR=8
+Const GADGET_TABBER=9
+Const GADGET_TREEVIEW=10
+Const GADGET_HTMLVIEW=11
+Const GADGET_LABEL=12
+Const GADGET_SLIDER=13
+Const GADGET_PROGBAR=14
+Const GADGET_MENUITEM=15
+Const GADGET_NODE=16
+Const GADGET_CANVAS=17
+Const GADGET_TIMER=18
+
+Const ACTIVATE_FOCUS=0
+Const ACTIVATE_CUT=1
+Const ACTIVATE_COPY=2
+Const ACTIVATE_PASTE=3
+Const ACTIVATE_MINIMIZE=4
+Const ACTIVATE_MAXIMIZE=5
+Const ACTIVATE_RESTORE=6
+Const ACTIVATE_SELECT=7
+Const ACTIVATE_EXPAND=8
+Const ACTIVATE_COLLAPSE=9
+Const ACTIVATE_BACK=10
+Const ACTIVATE_FORWARD=11
+Const ACTIVATE_PRINT=12
+Const ACTIVATE_REDRAW=13
+Const ACTIVATE_UNDO=14
+Const ACTIVATE_REDO=15
+
+Const LAYOUT_NONE=0
+Const LAYOUT_ABSOLUTE=1
+Const LAYOUT_PROPORTIONAL=2
+
+Const GUICOLOR_WINDOWBG = 0
+Const GUICOLOR_GADGETBG = 1
+Const GUICOLOR_GADGETFG = 2
+Const GUICOLOR_SELECTIONBG = 3
+Const GUICOLOR_LINKFG = 4
+
+Const WINDOW_TITLEBAR=1
+Const WINDOW_RESIZABLE=2
+Const WINDOW_MENU=4
+Const WINDOW_STATUS=8
+Const WINDOW_TOOL=16
+Const WINDOW_CLIENTCOORDS=32
+Const WINDOW_HIDDEN=64
+Const WINDOW_ACCEPTFILES=128
+Const WINDOW_CHILD=256
+Const WINDOW_CENTER=512
+
+Const WINDOW_DEFAULT=WINDOW_TITLEBAR|WINDOW_RESIZABLE|WINDOW_MENU|WINDOW_STATUS
+
+Const LABEL_LEFT=0
+Const LABEL_FRAME=1
+Const LABEL_SUNKENFRAME=2
+Const LABEL_SEPARATOR=3
+Const LABEL_RIGHT=8
+Const LABEL_CENTER=16
+
+Const BUTTON_PUSH=8
+Const BUTTON_CHECKBOX=2
+Const BUTTON_RADIO=3
+Const BUTTON_OK=4
+Const BUTTON_CANCEL=5
+
+
+Const CHECK_CLEARED = 0
+Const CHECK_SELECTED = 1
+Const CHECK_INDETERMINATE = -1
+
+
+Const PANEL_SUNKEN=1
+Const PANEL_RAISED=2
+Const PANEL_GROUP=3
+Const PANEL_BORDER=PANEL_SUNKEN	'For backwards compatibility
+
+Const PANEL_ACTIVE=4
+Const PANEL_CANVAS=8
+	
+Const PANELPIXMAP_TILE=0
+Const PANELPIXMAP_CENTER=1
+Const PANELPIXMAP_FIT=2
+Const PANELPIXMAP_STRETCH=3
+Const PANELPIXMAP_FIT2=4
+
+Const GADGETPIXMAP_BACKGROUND = 0
+Const GADGETPIXMAP_ICON = 8
+Const GADGETPIXMAP_NOTEXT = 16
+
+Const TEXTAREA_ALL=-1
+
+Const TEXTAREA_CHARS=1
+Const TEXTAREA_LINES=2
+
+Const TEXTAREA_WORDWRAP=1
+Const TEXTAREA_READONLY=2
+
+Const TEXTFIELD_PASSWORD=1
+
+Const TEXTFORMAT_BOLD=1
+Const TEXTFORMAT_ITALIC=2
+Const TEXTFORMAT_UNDERLINE=4
+Const TEXTFORMAT_STRIKETHROUGH=8
+
+Const LISTBOX_MULTISELECT=1
+
+Const COMBOBOX_EDITABLE=1
+
+Const TREEVIEW_DRAGNDROP=1
+
+Const SLIDER_HORIZONTAL=1
+Const SLIDER_VERTICAL=2
+Const SLIDER_SCROLLBAR=0
+Const SLIDER_TRACKBAR=4
+Const SLIDER_STEPPER=8
+Const SLIDER_DIAL=12
+
+Const HTMLVIEW_NOCONTEXTMENU=1
+Const HTMLVIEW_NONAVIGATE=2
+
+Const STATE_MINIMIZED=1
+Const STATE_MAXIMIZED=2
+Const STATE_DISABLED=4
+Const STATE_HIDDEN=8
+Const STATE_SELECTED=16
+Const STATE_ACTIVE=32
+Const STATE_INDETERMINATE=64|STATE_SELECTED
+
+Const GADGETICON_SEPARATOR=-2
+Const GADGETICON_BLANK=-1
+
+Const GADGETITEM_NONE=-1
+Const GADGETITEM_NORMAL=0
+Const GADGETITEM_DEFAULT=1
+Const GADGETITEM_TOGGLE=2
+Const GADGETITEM_LOCALIZED=4
+
+Const SENSITIZE_MOUSE=1
+Const SENSITIZE_KEYS=2
+Const SENSITIZE_ALL=SENSITIZE_MOUSE|SENSITIZE_KEYS
+
+Const EDGE_CENTERED=0
+Const EDGE_ALIGNED=1
+Const EDGE_RELATIVE=2
+
+Const QUERY_HWND=1
+Const QUERY_HWND_CLIENT=2
+Const QUERY_NSVIEW=3
+Const QUERY_NSVIEW_CLIENT=4
+Const QUERY_FLWIDGET=5
+Const QUERY_FLWIDGET_CLIENT=6
+
+Const EVENT_GADGETDRAG% = $200A, EVENT_GADGETDROP% = $200B
+TEvent.RegisterId EVENT_GADGETDRAG, "GadgetDrag"
+TEvent.RegisterId EVENT_GADGETDROP, "GadgetDrop"
+
+' WARNING - struct nsgadget in brl.mod/cocoagui.mod/cocoa.macos.m must be modified if TGadget field count changes
+
+Type TGadget
+' event propagation
+	Field	source:TGadget
+' hierachy
+	Field	parent:TGadget
+	Field	kids:TList=New TList
+' properties
+	Field	xpos,ypos,width,height
+	Field	name$, extra:Object	'See GadgetExtra() and SetGadgetExtra()
+	Field	style, sensitivity
+' slider vars
+	Field	visible,total=1
+' layout
+	Field	lockl,lockr,lockt,lockb
+	Field	lockx,locky,lockw,lockh,lockcw,lockch
+' filters
+	Field	eventfilter(event:TEvent,context:Object)
+	Field	context:Object
+' items
+	Field	items:TGadgetItem[]
+
+	Global dragGadget:TGadget[3]
+	
+	Global LocalizeString$( text$ ) 'set at the bottom of maxgui.mod/driver.bmx
+	'Global LocalizeGadget( gadget:TGadget, text$ )
+	Global DelocalizeGadget( gadget:TGadget )
+	
+' core methods
+	
+	Method SetFilter(callback(event:TEvent,context:Object),user:Object)
+		eventfilter=callback
+		context=user
+	End Method
+	
+	Method HasDescendant(pGadget:TGadget)
+		If pGadget = Self Then Return True
+		For Local tmpGadget:TGadget = EachIn kids
+			Local tmpResult = tmpGadget.HasDescendant(pGadget)
+			If tmpResult Then Return tmpResult
+		Next
+	EndMethod
+	
+	Method _setparent(widget:TGadget,index=-1)	'private use setgroup
+		If parent parent.kids.remove Self
+		parent=widget
+		If parent
+			If index<0 Or index>=parent.kids.count()
+				parent.kids.addlast Self
+			Else
+				If index=0
+					parent.kids.addfirst Self
+				Else
+					Local link:TLink
+					link=parent.kids.findlink(parent.kids.valueatindex(index))
+					parent.kids.InsertBeforeLink Self,link
+				EndIf
+			EndIf
+		EndIf
+	End Method
+	
+	Field arrPrevSelection:Int[]
+	
+	'Private method for multi-select listbox event handling.
+	'Returns first item whose state has changed or -1 if selection has stayed the same.
+	
+	Method SelectionChanged()
+		Local i%, arrLastSelection:Int[] = arrPrevSelection, arrCurrSelection:Int[] = SelectedItems()
+		arrPrevSelection = arrCurrSelection
+		For i = 0 Until Min(arrLastSelection.length,arrCurrSelection.length)
+			If arrCurrSelection[i] <> arrLastSelection[i] Then Return Min(arrCurrSelection[i],arrLastSelection[i])
+		Next
+		If i < arrLastSelection.length Then Return arrLastSelection[i] ElseIf i < arrCurrSelection.length Then Return arrCurrSelection[i]
+		Return -1
+	EndMethod
+	
+	Method Handle:TGadget()
+		Return Self
+	End Method
+	
+' layout
+	
+	Method GetXPos%()
+		Return xpos
+	EndMethod
+	
+	Method GetYPos%()
+		Return ypos
+	EndMethod
+	
+	Method GetWidth%()
+		Return width
+	EndMethod
+	
+	Method GetHeight%()
+		Return height
+	EndMethod
+	
+	Method GetGroup:TGadget()
+		Return parent
+	EndMethod
+	
+	Method SetShape(x,y,w,h)
+		SetArea(x,y,w,h)
+		LockLayout
+	End Method
+
+	Method SetArea(x,y,w,h)
+	If w = 640 And h = 480 Then
+	'DebugStop
+	End If
+'DebugLog "Gadget :: SetArea(" + x + ", " + y + ", " + w + ", " + h + ")"
+		SetRect x,y,w,h
+		Rethink()
+		LayoutKids
+	End Method
+
+	Method SetRect(x,y,w,h)
+		xpos=x;ypos=y;width=Max(w,0);height=Max(h,0)
+	End Method
+
+	Method LockLayout()
+		lockx=xpos
+		locky=ypos
+		lockw=width
+		lockh=height
+		lockcw=1
+		lockch=1
+		If parent
+			lockcw=Max(parent.ClientWidth(),1)
+			lockch=Max(parent.ClientHeight(),1)
+		EndIf
+	End Method
+
+	Method SetLayout( lft,rht,top,bot )
+		lockl=lft
+		lockr=rht
+		lockt=top
+		lockb=bot
+		LockLayout
+	End Method
+
+	Method LayoutKids()
+		For Local	 w:TGadget = EachIn kids
+			w.DoLayout()
+		Next
+	End Method
+
+	Method DoLayout()
+		Local cw,ch,x,x2,y,y2
+
+		If Not parent Or Class() = GADGET_WINDOW Or Class() = GADGET_MENUITEM Or Class() = GADGET_NODE Then Return
+		
+' horizontal
+		cw=Max(parent.ClientWidth(),1)
+		x=xpos
+		x2=xpos+width
+		If lockl Or lockr
+			If lockl=LAYOUT_ABSOLUTE x=lockx Else If lockl=LAYOUT_PROPORTIONAL x=cw*lockx/lockcw
+			If lockr=LAYOUT_ABSOLUTE x2=lockx+lockw-lockcw+cw Else If lockr=LAYOUT_PROPORTIONAL x2=cw*(lockx+lockw)/lockcw
+			If Not lockl x=x2-lockw Else If Not lockr x2=x+lockw
+		Else
+			x=cw*(lockx+lockw/2)/lockcw-lockw/2
+			x2=x+lockw
+		EndIf
+' vertical
+		ch=Max(parent.ClientHeight(),1)		
+		y=ypos
+		y2=ypos+height
+		If lockt Or lockb
+			If lockt=LAYOUT_ABSOLUTE y=locky Else If lockt=LAYOUT_PROPORTIONAL y=ch*locky/lockch
+			If lockb=LAYOUT_ABSOLUTE y2=locky+lockh-lockch+ch Else If lockb=LAYOUT_PROPORTIONAL y2=ch*(locky+lockh)/lockch
+			If Not lockt y=y2-lockh Else If Not lockb y2=y+lockh
+		Else
+			y=ch*(locky+lockh/2)/lockch-lockh/2
+			y2=y+lockh
+		EndIf
+
+		SetArea( x,y,x2-x,y2-y )
+	End Method
+
+' datasource
+	Field datasource:Object
+	Field datakeys$[]
+
+'	Global	gadgetdatamap:TMap=New TMap	'need pollevent for automatic refresh
+
+	Method SetDataSource(data:Object)
+		Clear
+		datasource=data
+		datakeys=Null
+'		gadgetdatamap.insert Self,data
+		SyncDataSource
+	End Method
+	
+	Function KeysFromList$[](list:TList)
+		Local s:String[]
+		Local o:Object
+		Local i
+		s=New String[list.count()]
+		For o=EachIn list
+			s[i]=o.ToString()
+			i:+1
+		Next	
+		Return s
+	End Function
+
+	Function KeysFromObjectArray$[](list:Object[])
+		Local s:String[]
+		Local o:Object
+		Local i
+		s=New String[list.length]
+		For o=EachIn list
+			s[i]=o.ToString()
+			i:+1
+		Next	
+		Return s
+	End Function
+
+	Method SyncDataSource()	'returns true if items modified
+		Local newkeys$[]
+		If Not datasource Return False
+		Select True
+			Case TList(datasource)<>Null
+				newkeys=KeysFromList(TList(datasource))
+			Case String[](datasource)<>Null
+				newkeys=String[](datasource)
+			Case Object[](datasource)<>Null
+				newkeys=KeysFromObjectArray(Object[](datasource))
+		End Select		
+		If Not newkeys Or newkeys.length=0 'datasource is empty or unsupported
+			If items.length
+				Clear
+				Return True
+			EndIf
+			Return False
+		EndIf
+'		If newkeys.compare(datakeys)=0 Return False
+		SyncData newkeys
+		datakeys=newkeys[..newkeys.length]
+	End Method
+	
+' for each item
+' if same move on
+' if diff
+'   see when next occurance is and how big a match will occur from remove
+'   if deletes<newmatch do remove else do insert
+
+	Method SyncData(newkeys$[])
+		Local p1,p2,d1,d2,d3
+		Local same,diff,icount
+		Local item:TGadgetItem
+		Local k$
+		
+		For p1=0 Until newkeys.length
+			k$=newkeys[p1]
+
+			If d1>=datakeys.length
+				InsertItemFromKey(icount,k$)
+				icount:+1
+				Continue
+			EndIf
+
+			If k$=datakeys[d1]
+				d1:+1
+				icount:+1
+				Continue
+			EndIf
+			
+			diff=1
+			For d2=d1+1 Until datakeys.length
+				If k=datakeys[d2] Exit
+				diff:+1
+			Next
+			same=1
+			p2=p1+1
+			For d3=d2+1 Until datakeys.length
+				If p2>=newkeys.length Exit
+				If newkeys[p2]<>datakeys[d3] Exit
+				same:+1
+				p2:+1
+			Next
+			
+			If same>diff
+				d1:+diff
+				While diff
+					RemoveItem icount
+					diff:-1
+				Wend
+				d1:+1
+				icount:+1
+			Else
+				InsertItemFromKey(icount,k$)
+				icount:+1
+			EndIf
+		Next				
+		While icount<items.length
+			RemoveItem icount
+		Wend
+	End Method		
+	
+	Method InsertItemFromKey(index,key$)
+		Return InsertItem(index,key,"",0,datasource,0)
+	End Method
+
+	
+' item handlers
+		
+	Method Clear()
+		ClearListItems()
+		items=Null
+	End Method
+
+	Method InsertItem(index,text$,tip$,icon,extra:Object,flags)
+?debug
+		If index<0 Or index>items.length Throw "Gadget item index out of range."
+?
+		items=items[..items.length+1]
+		For Local i=items.length-2 To index Step -1
+			items[i+1]=items[i]
+		Next
+		items[index]=New TGadgetItem
+		items[index].Set(text,tip,icon,extra,flags)
+		If flags&GADGETITEM_LOCALIZED Then
+			InsertListItem(index,LocalizeString(text),LocalizeString(tip),icon,extra)
+		Else
+			InsertListItem(index,text,tip,icon,extra)
+		EndIf
+		If flags&GADGETITEM_DEFAULT SelectItem(index)
+'DebugLog "InsertItem length = " + items.length
+	End Method
+	
+	
+	Method SetItem(index,text$,tip$,icon,extra:Object,flags)
+?debug
+		If index<0 Or index>=items.length Throw "Gadget item index out of range."
+?
+		items[index].Set(text,tip,icon,extra,flags)
+		If flags&GADGETITEM_LOCALIZED Then
+			SetListItem(index,LocalizeString(text),LocalizeString(tip),icon,extra)
+		Else
+			SetListItem(index,text,tip,icon,extra)
+		EndIf
+		If flags&GADGETITEM_DEFAULT SelectItem(index)
+	End Method
+	
+	Method RemoveItem(index)
+?debug
+		If index<0 Or index>=items.length Throw "Gadget item index out of range."
+?
+		For Local i=index Until items.length-1
+			items[i]=items[i+1]
+		Next
+		items=items[..items.length-1]
+		RemoveListItem(index)
+	End Method
+	
+	Method ItemCount()
+		Return items.length
+	End Method
+
+	Method ItemText$(index)
+?debug
+		If index<0 Or index>=items.length Throw "Gadget item index out of range."
+?
+		Return items[index].text		
+	End Method
+
+	Method ItemTip$(index)
+?debug
+		If index<0 Or index>=items.length Throw "Gadget item index out of range."
+?
+		Return items[index].tip
+	End Method
+
+	Method ItemFlags(index)
+?debug
+		If index<0 Or index>=items.length Throw "Gadget item index out of range."
+?
+		Return items[index].flags
+	End Method
+
+	Method ItemIcon(index)
+?debug
+		If index<0 Or index>=items.length Throw "Gadget item index out of range."
+?
+		Return items[index].icon
+	End Method
+	
+	Method ItemExtra:Object(index)
+		If index = -1 Then Return Null
+?debug
+		If index<0 Or index>=items.length Throw "Gadget item index out of range."
+?
+		Return items[index].extra
+	End Method
+
+	Method SetItemState(index,state)
+?debug
+		If index<0 Or index>=items.length Throw "Gadget item index out of range."
+?
+		SetListItemState(index,state)
+	End Method
+	
+	Method ItemState(index)
+?debug
+		If index<0 Or index>=items.length Throw "Gadget item index out of range."
+?
+		Return ListItemState(index)
+	End Method
+	
+	Method SelectItem(index,op=1)	'0=deselect 1=select 2=toggle
+		Local	item:TGadgetItem
+		Local	state,icon	
+		Local	i
+		If index=-1
+			For i=0 Until items.length
+				SelectItem i,op
+			Next
+			Return
+		EndIf
+?debug
+		If index<0 Or index>=items.length Throw "Gadget item index out of range."
+?
+		state=ItemState(index)
+		Select op
+		Case 0
+			state:&~STATE_SELECTED
+		Case 1
+			state:|STATE_SELECTED
+		Case 2
+			state:~STATE_SELECTED
+		End Select
+		item=items[index]
+		icon=item.icon
+		If icon>-1 And item.flags&GADGETITEM_TOGGLE
+			If state&STATE_SELECTED	icon:+1
+			SetListItem index,item.text,item.tip,icon,item.extra	'toggle icon
+		EndIf
+		SetItemState index,state
+	End Method
+
+	Method SelectedItem()
+		Local selection:Int[] = SelectedItems()
+'DebugLog "SelectedItem length = " + selection.length
+		If selection.length = 1 Then Return selection[0] Else Return -1
+	End Method
+
+	Method SelectedItems[]()
+'DebugLog "SelectedItems length = " + items.length
+		Local	index,count,arr[items.length]
+		For index=0 Until items.length
+			If ListItemState(index)&STATE_SELECTED Then
+				arr[count] = index
+				count:+1
+			EndIf
+		Next
+		If count Then Return arr[..count]
+	End Method
+			
+' maxgui interface
+	Method Insert(group:TGadget,index=-1)
+	End Method
+	Method Query:Byte Ptr(queryid)
+	End Method
+	Method CleanUp()
+		For Local tmpChild:TGadget = EachIn kids.Copy()
+			tmpChild.CleanUp()
+		Next
+		Free()
+		
+		DelocalizeGadget( Self )
+		kids.Clear();parent = Null;extra = Null
+		eventfilter = Null;context = Null;items = Null
+		
+		For Local i% = 0 Until dragGadget.length
+			If dragGadget[i] = Self Then dragGadget[i] = Null
+		Next
+	End Method
+	Method Free()
+	End Method
+	Method Rethink()	'resize
+	End Method		
+	Method ClientWidth()
+	End Method
+	Method ClientHeight()
+	End Method
+	Method Activate(command)
+	End Method
+	Method State()
+	End Method
+	Method SetText(text$)
+	End Method
+	Method GetText$()
+	End Method
+	Method SetFont(font:TGuiFont)
+	End Method
+	Method SetColor(r,g,b)
+	End Method
+	Method RemoveColor()
+	End Method
+	Method SetAlpha(a#)
+	End Method
+	Method SetTextColor(r,g,b)
+	End Method
+	Method SetTooltip( pTip$ )
+	EndMethod
+	Method GetTooltip$()
+	EndMethod
+	Method SetPixmap(pixmap:TPixmap,flags)
+	End Method
+	Method SetIconStrip(iconstrip:TIconStrip)
+	End Method
+	Method SetShow(bool)
+	End Method
+	Method SetEnabled(bool)
+	End Method
+	Method SetSelected(bool)
+	End Method
+	Method SetHotKey(keycode,modifier)
+	End Method
+	Method SetSensitivity( flags )
+		sensitivity = flags
+	EndMethod
+	Method GetSensitivity()
+		Return sensitivity
+	EndMethod
+	Method Class()
+	EndMethod
+' window commands
+	Method GetStatusText$()
+	End Method
+	Method SetStatusText(text$)
+	End Method
+	Method GetMenu:TGadget()
+	End Method
+	Method PopupMenu(menu:TGadget,extra:Object=Null)
+	End Method
+	Method UpdateMenu()
+	End Method
+	Method SetMinimumSize(w,h)
+	End Method
+	Method SetMaximumSize(w,h)
+	End Method
+' list commands
+	Method ClearListItems()
+	End Method
+	Method InsertListItem(index,text$,tip$,icon,tag:Object)
+	End Method
+	Method SetListItem(index,text$,tip$,icon,tag:Object)
+	End Method
+	Method RemoveListItem(index)
+	End Method
+	Method SetListItemState(index,state)
+	End Method
+	Method ListItemState(index)
+	End Method
+' treeview commands
+	Method RootNode:TGadget()
+	End Method
+	Method InsertNode:TGadget(index,text$,icon)
+	End Method
+	Method ModifyNode(text$,icon)
+	End Method
+	Method SelectedNode:TGadget()
+	End Method
+	Method CountKids()
+	End Method
+' textarea commands
+	Method ReplaceText(pos,length,text$,units)
+	End Method
+	Method AddText(text$)
+	End Method
+	Method AreaText$(pos,length,units)
+	End Method
+	Method AreaLen(units)
+	End Method
+	Method LockText()
+	End Method
+	Method UnlockText()
+	End Method
+	Method SetTabs(tabwidth)
+	End Method
+	Method SetMargins(leftmargin)
+	End Method
+	Method GetCursorPos(units)
+	End Method
+	Method GetSelectionLength(units)
+	End Method
+	Method SetStyle(r,g,b,flags,pos,length,units)
+	End Method	
+	Method SetSelection(pos,length,units)
+	End Method
+	Method CharX(char)
+	EndMethod
+	Method CharY(char)
+	EndMethod
+	Method CharAt(line)
+	End Method
+	Method LineAt(index)
+	End Method
+' progbar
+	Method SetValue(value#)
+	End Method	
+' slider
+	Method SetRange(visible,total)
+	End Method
+	Method SetProp(value)
+	End Method
+	Method GetProp()
+	End Method
+' canvas
+	Method AttachGraphics:TGraphics( flags )
+	End Method
+	Method CanvasGraphics:TGraphics()
+	End Method
+' htmlview
+	Method Run$(script$)
+	End Method
+End Type
+
+Global NullProxy:TGadget=New TGadget
+
+Type TProxyGadget Extends TGadget
+	Field	proxy:TGadget=NullProxy
+	
+	Method SetProxy(gadget:TGadget)
+		If proxy And proxy.source = Self Then proxy.source = Null
+		proxy=gadget
+		If proxy Then proxy.source = Self
+	End Method
+	
+	Method GetProxy:TGadget()
+		Return proxy
+	End Method
+	
+' maxgui interface
+	Method GetXPos%()
+		Return proxy.GetXPos()
+	EndMethod
+	Method GetYPos%()
+		Return proxy.GetYPos()
+	EndMethod
+	Method GetWidth%()
+		Return proxy.GetWidth()
+	EndMethod
+	Method GetHeight%()
+		Return proxy.GetHeight()
+	EndMethod
+	Method GetGroup:TGadget()
+		Return proxy.GetGroup()
+	EndMethod
+	Method HasDescendant(pGadget:TGadget)
+		Return proxy.HasDescendant(pGadget)
+	EndMethod
+	Method Query:Byte Ptr(queryid)
+		Return proxy.Query(queryid)
+	End Method
+	Method CleanUp()
+		Return proxy.CleanUp()
+	End Method
+	Method Free()
+		Return proxy.Free()
+	End Method
+	Method SetShape(x,y,w,h)
+		proxy.SetShape(x,y,w,h)
+	End Method
+	Method Rethink()	'resize
+		Return proxy.Rethink()
+	End Method		
+	Method ClientWidth()
+		Return proxy.ClientWidth()
+	End Method
+	Method ClientHeight()
+		Return proxy.ClientHeight()
+	End Method
+	Method Activate(command)
+		Return proxy.Activate(command)
+	End Method
+	Method State()
+		Return proxy.State()
+	End Method
+	Method SetText(text$)
+		Return proxy.SetText(text)
+	End Method
+	Method GetText$()
+		Return proxy.GetText()
+	End Method
+	Method SetTooltip( pTip$ )
+		Return proxy.SetTooltip( pTip )
+	EndMethod
+	Method GetTooltip$()
+		Return proxy.GetTooltip()
+	EndMethod
+	Method SetFont(font:TGuiFont)
+		Return proxy.SetFont(font)
+	End Method
+	Method SetColor(r,g,b)
+		Return proxy.SetColor(r,g,b)
+	End Method
+	Method RemoveColor()
+		Return proxy.RemoveColor()
+	End Method
+	Method SetAlpha(a#)
+		Return proxy.SetAlpha(a)
+	End Method
+	Method SetTextColor(r,g,b)
+		Return proxy.SetTextColor(r,g,b)
+	End Method
+	Method SetShow(bool)
+		Return proxy.SetShow(bool)
+	End Method
+	Method SetSelected(bool)
+		Return proxy.SetSelected(bool)
+	End Method
+	Method SetEnabled(bool)
+		Return proxy.SetEnabled(bool)
+	End Method
+	Method SetSensitivity( flags )
+		Return proxy.SetSensitivity(flags)
+	EndMethod
+	Method GetSensitivity()
+		Return proxy.GetSensitivity()
+	EndMethod
+	Method SetHotKey(keycode,modifier)
+		Return proxy.SetHotKey(keycode,modifier)
+	End Method
+	Method SetIconStrip(iconstrip:TIconStrip)
+		Return proxy.SetIconStrip(iconstrip)
+	End Method
+	Method SetLayout( lft,rht,top,bot )
+		proxy.SetLayout lft,rht,top,bot
+	End Method
+	Method Class()
+		Return proxy.Class()
+	EndMethod
+' window commands
+	Method GetStatusText$()
+	End Method
+	Method SetStatusText(text$)
+		Return proxy.SetStatusText(text)
+	End Method
+	Method SetStatus(text$)
+		Return Self.SetStatusText(text)
+	EndMethod
+	Method GetMenu:TGadget()
+		Return proxy.GetMenu()
+	End Method
+	Method PopupMenu(menu:TGadget,extra:Object)
+		Return proxy.PopupMenu(menu,extra)
+	End Method
+	Method UpdateMenu()
+		Return proxy.UpdateMenu()
+	End Method
+	Method SetMinimumSize(w,h)
+		Return proxy.SetMinimumSize(w,h)
+	End Method
+	Method SetMaximumSize(w,h)
+		Return proxy.SetMaximumSize(w,h)
+	End Method
+' list commands
+	Method ClearListItems()
+		Return proxy.ClearListItems()
+	End Method
+	Method InsertListItem(index,text$,tip$,icon,extra:Object)
+		Return proxy.InsertListItem(index,text,tip,icon,extra)
+	End Method
+	Method SetListItem(index,text$,tip$,icon,extra:Object)
+		Return proxy.SetListItem(index,text,tip,icon,extra)
+	End Method
+	Method RemoveListItem(index)
+		Return proxy.RemoveListItem(index)
+	End Method
+	Method SetListItemState(index,state)
+		Return proxy.SetListItemState(index,state)
+	End Method
+	Method ListItemState(index)
+		Return proxy.ListItemState(index)
+	End Method
+' treeview commands
+	Method RootNode:TGadget()
+		Return proxy.RootNode()
+	End Method
+	Method InsertNode:TGadget(index,text$,icon)
+		Return proxy.InsertNode(index,text,icon)
+	End Method
+	Method ModifyNode(text$,icon)
+		Return proxy.ModifyNode(text,icon)
+	End Method
+	Method SelectedNode:TGadget()
+		Return proxy.SelectedNode()
+	End Method
+	Method CountKids()
+		Return proxy.CountKids()
+	End Method
+' textarea commands
+	Method ReplaceText(pos,length,text$,units)
+		Return proxy.ReplaceText(pos,length,text,units)
+	End Method
+	Method AddText(text$)
+		Return proxy.AddText(text)
+	End Method
+	Method AreaText$(pos,length,units)
+		Return proxy.AreaText(pos,length,units)
+	End Method
+	Method AreaLen(units)
+		Return proxy.AreaLen(units)
+	End Method
+	Method LockText()
+		Return proxy.LockText()
+	End Method
+	Method UnlockText()
+		Return proxy.UnlockText()
+	End Method
+	Method SetTabs(tabwidth)
+		Return proxy.SetTabs(tabwidth)
+	End Method
+	Method SetMargins(leftmargin)
+		Return proxy.SetMargins(leftmargin)
+	End Method
+	Method GetCursorPos(units)
+		Return proxy.GetCursorPos(units)
+	End Method
+	Method GetSelectionLength(units)
+		Return proxy.GetSelectionLength(units)
+	End Method
+	Method SetStyle(r,g,b,flags,pos,length,units)
+		Return proxy.SetStyle(r,g,b,flags,pos,length,units)
+	End Method	
+	Method SetSelection(pos,length,units)
+		Return proxy.SetSelection(pos,length,units)
+	End Method
+	Method CharX(char)
+		Return proxy.CharX(char)
+	End Method
+	Method CharY(char)
+		Return proxy.CharY(char)
+	End Method
+	Method CharAt(line)
+		Return proxy.CharAt(line)
+	End Method
+	Method LineAt(index)
+		Return proxy.LineAt(index)
+	End Method
+' progbar
+	Method SetValue(value#)
+		Return proxy.SetValue(value)
+	End Method	
+' slider
+	Method SetRange(visible,total)
+		Return proxy.SetRange(visible,total)
+	End Method
+	Method SetProp(value)
+		Return proxy.SetProp(value)
+	End Method
+	Method GetProp()
+		Return proxy.GetProp()
+	End Method
+' panel
+	Method SetPixmap(pixmap:TPixmap,flags)
+		Return proxy.SetPixmap(pixmap,flags)
+	End Method
+' canvas
+	Method AttachGraphics:TGraphics( flags )
+		Return proxy.AttachGraphics( flags )
+	End Method
+	Method CanvasGraphics:TGraphics()
+		Return proxy.CanvasGraphics()
+	End Method
+' htmlview
+	Method Run$(script$)
+		Return proxy.Run(script)
+	End Method
+'items	
+	Method Clear()
+		Return proxy.Clear()
+	End Method
+	Method InsertItem(index,text$,tip$,icon,extra:Object,flags)
+		Return proxy.InsertItem(index,text,tip,icon,extra,flags)
+	End Method
+	Method SetItem(index,text$,tip$,icon,extra:Object,flags)
+		Return proxy.SetItem(index,text,tip,icon,extra,flags)
+	End Method
+	Method RemoveItem(index)
+		Return proxy.RemoveItem(index)
+	End Method
+	Method ItemCount()
+		Return proxy.ItemCount()
+	End Method
+	Method ItemText$(index)
+		Return proxy.ItemText(index)	
+	End Method
+	Method ItemTip$(index)
+		Return proxy.ItemTip(index)
+	End Method
+	Method ItemFlags(index)
+		Return proxy.ItemFlags(index)
+	End Method
+	Method ItemIcon(index)
+		Return proxy.ItemIcon(index)
+	End Method
+	Method ItemExtra:Object(index)
+		Return proxy.ItemExtra(index)
+	End Method
+	Method SetItemState(index,state)
+		Return proxy.SetItemState(index,state)
+	End Method
+	Method ItemState(index)
+		Return proxy.ItemState(index)
+	End Method
+	Method SelectItem(index,op=1)	'0=deselect 1=select 2=toggle
+		Return proxy.SelectItem(index,op)
+	End Method
+	Method SelectedItem()
+		Return proxy.SelectedItem()
+	End Method
+	Method SelectedItems[]()
+		Return proxy.SelectedItems()
+	End Method
+End Type

+ 18 - 0
maxgui.mod/gadgetitem.bmx

@@ -0,0 +1,18 @@
+Strict
+
+Type TGadgetItem
+	
+	Field text$, tip$, icon, flags
+	Field extra:Object
+	
+	'Method Set:TGadgetItem(_text$,_tip$,_icon,_extra:Object,_flags)
+	Method Set(_text$,_tip$,_icon,_extra:Object,_flags)
+		text=_text
+		tip=_tip
+		icon=_icon
+		flags=_flags
+		extra=_extra
+		'Return Self
+	End Method
+	
+End Type

+ 23 - 0
maxgui.mod/guifont.bmx

@@ -0,0 +1,23 @@
+Strict
+
+Const FONT_NORMAL = 0
+Const FONT_BOLD = 1
+Const FONT_ITALIC = 2
+Const FONT_UNDERLINE = 4
+Const FONT_STRIKETHROUGH = 8	'Unsupported on some platforms
+
+Const GUIFONT_SYSTEM% = 1
+Const GUIFONT_MONOSPACED% = 2
+Const GUIFONT_SANSSERIF% = 3
+Const GUIFONT_SERIF% = 4
+Const GUIFONT_SCRIPT% = 5
+
+Type TGuiFont
+	Field name$
+	Field path$
+	Field style
+	Field size
+	Field handle:Byte Ptr
+	
+	Method CharWidth(charcode) Abstract
+End Type

+ 16 - 0
maxgui.mod/iconstrip.bmx

@@ -0,0 +1,16 @@
+Strict
+
+Import BRL.Pixmap
+
+Type TIconStrip
+	
+	Field pixmap:TPixmap
+	Field count
+	
+	Method ExtractIconPixmap:TPixmap(index:Int)
+		If (index>=count) Then Return Null
+		If (index < 0) Then Return pixmap.Copy()
+		Return pixmap.Window(index*pixmap.height,0,pixmap.height,pixmap.height)
+	EndMethod
+	
+EndType

+ 2492 - 0
maxgui.mod/maxgui.bmx

@@ -0,0 +1,2492 @@
+
+Strict
+
+Rem
+bbdoc: MaxGUI/MaxGUI
+End Rem
+Module MaxGUI.MaxGUI
+
+ModuleInfo "Version: 1.34"
+ModuleInfo "Author: Simon Armstrong, Mark Sibly"
+ModuleInfo "License: zlib/libpng"
+ModuleInfo "Copyright: Blitz Research Ltd"
+
+ModuleInfo "History: 1.34 Release"
+ModuleInfo "History: Left margin added to textareas through SetIndents (SetTextAreaTabs replacement)."
+ModuleInfo "History: 1.33 Release"
+ModuleInfo "History: Added WindowStatusText() command."
+ModuleInfo "History: Renamed TGadget.SetStatus() to more specific TGadget.SetStatusText()."
+ModuleInfo "History: 1.32 Release"
+ModuleInfo "History: Added PANEL_RAISED/PANEL_SUNKEN style flags (PANEL_BORDER now redundant)."
+ModuleInfo "History: 1.31 Release"
+ModuleInfo "History: Added optional 'extra' parameter to AddTreeViewNode/InsertTreeViewNode commands."
+ModuleInfo "History: 1.30 Release"
+ModuleInfo "History: Added LookupGuiColor() command."
+ModuleInfo "History: 1.29 Release"
+ModuleInfo "History: Added hack to better center windows by taking into account task-bars/docks."
+ModuleInfo "History: 1.28 Release"
+ModuleInfo "History: Changed default Mac OS X monospaced font to 'Monaco'."
+ModuleInfo "History: Added GetWidth() etc. methods to TGadget for TProxyGadget."
+ModuleInfo "History: Added recursive source.source handling to PostGuiEvent/QueueGuiEvent."
+ModuleInfo "History: 1.27 Release"
+ModuleInfo "History: Added some internal event queueing functions."
+ModuleInfo "History: Tweaked some docs."
+ModuleInfo "History: 1.26 Release"
+ModuleInfo "History: Added GetProxy() method to TProxyGadget."
+ModuleInfo "History: 1.25 Release"
+ModuleInfo "History: Item array is now cleared in CleanUp() to avoid potential cyclic memory references."
+ModuleInfo "History: Added CleanUp() method to free generic MaxGUI objects before calling API specific Free()."
+ModuleInfo "History: 1.24 Release"
+ModuleInfo "History: Added tooltip methods to TProxyGadget."
+ModuleInfo "History: 1.23 Release"
+ModuleInfo "History: Updated docs to include EVENT_GADGETMENU for tabbers."
+ModuleInfo "History: Added TextAreaCharX() and TextAreaCharY() commands."
+ModuleInfo "History: 1.22 Release"
+ModuleInfo "History: Corrected GADGETITEM_TOGGLE in docs."
+ModuleInfo "History: Added width and height constraints in SetRect() to enforce positive values."
+ModuleInfo "History: 1.21 Release"
+ModuleInfo "History: Changed LookupGuiFont()'s Linux default for GUIFONT_SYSTEM."
+ModuleInfo "History: 1.20 Release"
+ModuleInfo "History: Added SetShape() method to TProxyGadget."
+ModuleInfo "History: 1.19 Release"
+ModuleInfo "History: Added new BUTTON_PUSH flag support."
+ModuleInfo "History: Added new GadgetExtra()/SetGadgetExtra() functions."
+ModuleInfo "History: Renamed the infamous ExtractIconPixmapFromStrip() function to PixmapFromIconStrip()."
+ModuleInfo "History: LoadGuiFont now accepts a Double for the font size so that some platforms are able to handle non-integer font sizes."
+ModuleInfo "History: Added new LookupGuiFont() function, new strikethough parameter for LoadGuiFont, and copied font constants to maxgui.h."
+ModuleInfo "History: Moved HasDescendant() method from Win32MaxGUIEx driver as it is probably more useful here."
+ModuleInfo "History: 1.18 Release"
+ModuleInfo "History: Added new GadgetClass() function."
+ModuleInfo "History: 1.17 Release"
+ModuleInfo "History: Implemented framework for CHECK_INDETERMINATE button state."
+ModuleInfo "History: Added SetGadgetSensitivity() and GetGadgetSensitivity() for capturing mouse/key events on more gadgets."
+ModuleInfo "History: Added WINDOW_CENTER flag to CreateWindow to centralise windows automatically on the screen."
+ModuleInfo "History: 1.16 Release"
+ModuleInfo "History: Added SetGadgetTooltip() and GadgetTooltip() functions for setting tooltips on non-item based gadgets."
+ModuleInfo "History: Added ExtractIconPixmapFromStrip() function and corresponding TIconStrip method."
+ModuleInfo "History: Added SetGadgetPixmap() for push-button and menu icon support."
+ModuleInfo "History: Added Fabian's SetHotKeyEvent() fix so that the owner parameter must be the same also to overwrite."
+ModuleInfo "History: Added TProxyGadget.SetLayout() method."
+ModuleInfo "History: Added PANELPIXMAP_FIT2 constant."
+ModuleInfo "History: 1.15 Release"
+ModuleInfo "History: New SetDataSource method for TGadget"
+ModuleInfo "History: 1.14 Release"
+ModuleInfo "History: Bumped just in case..."
+ModuleInfo "History: 1.13 Release"
+ModuleInfo "History: Added RemoveHotKey Function"
+ModuleInfo "History: 1.12 Release"
+ModuleInfo "History: Bumped for popupmenu method change"
+ModuleInfo "History: 1.11 Release"
+ModuleInfo "History: Bumped for new TMap"
+ModuleInfo "History: 1.10 Release"
+ModuleInfo "History: Rebuilt under 10.3.9"
+ModuleInfo "History: 1.09 Release"
+ModuleInfo "History: Added extra detail to CreateListBox docs"
+ModuleInfo "History: Added TEXTFORMAT_UNDERLINE and TEXTFORMAT_STRIKETHROUGH constants"
+ModuleInfo "History: Added GadgetText function for accessing Gadget.GetText"
+ModuleInfo "History: 1.08 Release"
+ModuleInfo "History: Added SetGraphics requirement to CreateCanvas documentation"
+ModuleInfo "History: Replaced EnableToolBarItem references with Enable/DisableGadgetItem"
+ModuleInfo "History: 1.07 Release"
+ModuleInfo "History: Added optional owner window field to THotKey processing"
+ModuleInfo "History: 1.06 Release"
+ModuleInfo "History: GraphicsFlags removed from CreatePanel, panels now use Graphic's DefaultGraphicsFlags"
+ModuleInfo "History: 1.05 Release"
+ModuleInfo "History: Added range checking on gadget item parameters"
+ModuleInfo "History: 1.04 Release"
+ModuleInfo "History: Bumped version to restore missing docs on Apple modserver"
+ModuleInfo "History: 1.03 Release"
+ModuleInfo "History: Fixed some broken examples due to new 1.14 strict rules"
+ModuleInfo "History: New common MaxGUI.h header file for use by native drivers"
+ModuleInfo "Histroy: Documented TEXTAREA_ALL, TEXTAREA_CHARS and TEXTAREA_LINES constants"
+ModuleInfo "Histroy: TreeView now uses EventExtra to specify node involved"
+ModuleInfo "History: 1.02 Release"
+ModuleInfo "History: Renamed Query() to QueryGadget()"
+ModuleInfo "History: Added QUERY_HWND,QUERY_HWND_CLIENT,QUERY_NSVIEW, QUERY_NSVIEW_CLIENT,"
+ModuleInfo "History: QUERY_FLWIDGET, and QUERY_FLWIDGET_CLIENT constants"
+ModuleInfo "History: EventSource() fixed for TProxyGadgets"
+ModuleInfo "History: Removed SetGadgetTarget, see new Event.AddEventTarget"
+ModuleInfo "History: RedrawGadget now uses ACTIVATE_REDRAW"
+
+Import BRL.Map
+Import BRL.LinkedList
+Import BRL.FileSystem
+Import BRL.StandardIO
+
+Import "driver.bmx"
+Import "event.bmx"
+Import "gadget.bmx"
+Import "guifont.bmx"
+Import "iconstrip.bmx"
+
+Global RequestedColor
+
+Type THotKey
+	Field succ:THotKey
+	Field key,mods
+	Field event:TEvent
+	Field owner
+End Type
+
+Global hotKeys:THotKey
+
+Rem
+bbdoc: Set a hotkey event.
+about:
+When the specified hotkey combination is selected by the user, the specified
+@event will be emitted using #EmitEvent.
+
+If @event is #Null, an event with an @id equal to EVENT_HOTKEYHIT, @data equal
+to @key and @mods equal to @mods will be emitted.
+
+#SetHotKeyEvent will overwrite any existing hotkey event with the same @key, @mods and @owner.
+
+Please refer to the #{Key Codes} module for valid key and modifier codes.
+End Rem
+Function SetHotKeyEvent:THotKey( key,mods,event:TEvent=Null,owner=0 )
+	If Not event event=CreateEvent( EVENT_HOTKEYHIT,Null,key,mods )
+	Local t:THotKey=hotKeys
+	While t
+		If t.key=key And t.mods=mods And t.owner=owner Then Exit
+		t=t.succ
+	Wend
+	If Not t
+		t=New THotKey
+		t.key=key
+		t.mods=mods
+		t.succ=hotKeys
+		t.owner=owner
+		hotKeys=t
+	EndIf
+	t.event=event
+	Return t
+End Function
+
+Rem
+bbdoc: Remove a hotkey event.
+about:
+Clears a hotkey object created with #SetHotKeyEvent.
+End Rem
+Function RemoveHotKey(hotkey:THotKey)
+	Local t:THotKey,tt:THotKey
+	t=hotKeys
+	While t
+		If t=hotkey
+			If tt tt.succ=t.succ Else hotkeys=t.succ
+			t.succ=Null
+			Return
+		EndIf
+		tt=t
+		t=t.succ
+	Wend
+End Function
+
+Function HotKeyEvent:TEvent( key,mods,owner )
+	Local t:THotKey=hotKeys
+	While t
+		If t.key=key And t.mods=mods
+			If t.owner And t.owner<>owner
+			Else
+				Return t.event
+			EndIf
+		EndIf
+		t=t.succ
+	Wend
+	Return Null
+End Function
+
+Rem
+bbdoc: Look-up a system defined color.
+returns: #True if a matching color is retrieved from the system, #False if the hard-coded fall-back is used.
+about:
+@colorindex can be one of the following values:
+
+[ @Constant | @Description | @{Fall Back} 
+* GUICOLOR_WINDOWBG | Window/panel background color. | R: 240, G: 240, B: 240 
+* GUICOLOR_GADGETBG | Gadget background color (e.g. textfield). | R: 255, G: 255, B: 255 
+* GUICOLOR_GADGETFG | Gadget text color. | R: 0, G: 0, B: 0 
+* GUICOLOR_SELECTIONBG | Text selection background color. | R: 50, G: 150, B: 255 
+* GUICOLOR_LINKFG | Hyperlink text color. | R: 0, G: 0, B: 255 
+] 
+
+See Also: #LookupGuiFont, #RequestColor
+EndRem
+Function LookupGuiColor( colorindex, red:Byte Var, green:Byte Var, blue:Byte Var )
+	Return maxgui_driver.LookupColor( colorindex, red, green, blue )
+EndFunction
+
+Rem
+bbdoc: Prompts the user for a color.
+returns: #True if a color is selected, #False if the requester was cancelled.
+about:
+The parameters @red, @green, @blue are the initial color to display in the requester,
+with components in the range 0 to 255.
+
+After a color is selected, use the #RequestedRed, #RequestedGreen and #RequestedBlue
+functions to determine the color chosen by the user.
+
+See Also: #LookupGuiColor
+EndRem
+Function RequestColor(r,g,b)
+	Local	argb
+	argb=maxgui_driver.RequestColor(Byte(r),Byte(g),Byte(b))
+	If argb
+		RequestedColor=argb
+		Return True
+	EndIf
+End Function
+
+Rem
+bbdoc: Get the red component of the color previously chosen by the user.
+about: See #RequestColor for more information.
+EndRem
+Function RequestedRed()
+	Return (RequestedColor Shr 16) & $FF
+End Function
+
+Rem
+bbdoc: Get the green component of the color previously chosen by the user.
+about: See #RequestColor for more information.
+EndRem
+Function RequestedGreen()
+	Return (RequestedColor Shr 8) & $FF
+End Function
+
+Rem
+bbdoc: Get the blue component of the color previously chosen by the user.
+about: See #RequestColor for more information.
+EndRem
+Function RequestedBlue()
+	Return RequestedColor & $FF
+End Function
+
+Rem
+bbdoc: Prompts the user to select a system font.
+returns: A @TGuiFont object, or #Null if no font was selected.
+about:
+Prompts the user for a font and returns an object that can then be used with the #SetGadgetFont command.
+
+See Also: #LoadGuiFont, #LookupGuiFont, #FontName, #FontSize and #FontStyle
+EndRem
+Function RequestFont:TGuiFont(font:TGuiFont=Null)
+	Return maxgui_driver.RequestFont(font:TGuiFont)
+End Function
+
+Rem
+bbdoc: Load a system font by name.
+returns: A @TGuiFont object, or #Null if a suitable matching font was not found on the system.
+about:
+Loads a system font by name and returns an object that can then be used with the #SetGadgetFont command.
+
+Depending on the platform, some gadgets may not respond to all or any of the attributes specified in the function
+parameters.
+
+See Also: #RequestFont, #LookupGuiFont, #FontName, #FontSize and #FontStyle
+EndRem
+Function LoadGuiFont:TGuiFont(name$,height:Double,bold=False,italic=False,underline=False,strikethrough=False)
+	Local	flags = FONT_NORMAL
+	If bold flags:|FONT_BOLD
+	If italic flags:|FONT_ITALIC
+	If underline flags:|FONT_UNDERLINE
+	If strikethrough flags:|FONT_STRIKETHROUGH
+	Return maxgui_driver.LoadFontWithDouble(name,height,flags)
+End Function
+
+Rem
+bbdoc: Loads a suitable GUI font that best matches the supplied font characteristics.
+returns: A new @TGuiFont instance chosen using the supplied parameters.
+about: If the current MaxGUI driver doesn't return a suitable GUI font, then
+a hard-coded fall-back font is returned instead, depending upon the platform.
+
+@pFontType can take one of the following constants:
+
+[ @Constant | @{Windows Fall-Back} | @{Mac OS X Fall-Back} | @{Linux Fall-Back} | @Description
+* GUIFONT_SYSTEM | MS Shell Dlg | Lucida Grande | FreeSerif | Default font used to draw gadgets by the OS.
+* GUIFONT_SERIF | Times New Roman | Times New Roman | FreeSerif | Serif font.
+* GUIFONT_SANSSERIF | Arial | Helvetica | FreeSans | Sans Serif font.
+* GUIFONT_SCRIPT | Comic Sans MS | Comic Sans MS | TSCu_Comic | Handwriting style font.
+* GUIFONT_MONOSPACED | Consolas/Courier New | Courier | Courier | Fixed width font typically used for coding.
+]
+
+@pFontSize specifies the point size the font should be loaded with. If this value is less than or equal to 0, then
+a suitable size is automatically chosen, or a hard-coded alternative is used (usually between 8-13pt).
+
+@pFontStyle should specify any additional font styles that the font should be loaded with. A combination of any of the
+following flags can be used:
+
+[ @Constant | @{Font Style}
+* FONT_BOLD | Bold
+* FONT_ITALIC | Italic
+* FONT_UNDERLINE | Underlined
+* FONT_STRIKETHROUGH | *Strikethrough
+]
+
+%{Note: FONT_STRIKETHROUGH isn't fully supported by all gadgets/platforms.}
+
+See Also: #LookupGuiColor, #RequestFont, #FontName, #FontSize and #FontStyle
+EndRem
+Function LookupGuiFont:TGuiFont( pFontType% = GUIFONT_SYSTEM, pFontSize:Double = 0, pFontStyle% = 0 )
+	Return maxgui_driver.LibraryFont( pFontType, pFontSize, pFontStyle )
+End Function
+
+Rem
+bbdoc: Retrieves the corresponding property from the @TGuiFont type instance.
+returns: A string representing the name of the font.
+about: See Also: #LoadGuiFont, #LookupGuiFont, #RequestFont, #FontSize and #FontStyle
+EndRem
+Function FontName$(font:TGuiFont)
+	Return font.name	
+End Function
+
+Rem
+bbdoc: Retrieves the corresponding property from the @TGuiFont type instance.
+returns: A double representing the size (in points) of the font.
+about: See Also: #LoadGuiFont, #LookupGuiFont, #RequestFont, #FontName and #FontStyle
+EndRem
+Function FontSize:Double(font:TGuiFont)
+	Return font.size
+End Function
+
+Rem
+bbdoc: Retrieves the corresponding property from the @TGuiFont type instance.
+returns: An integer representing the style of the font (e.g. Bold, Underlined, Italics, Strikethrough).
+about: The returned value will be a combination of the following bit flags:
+
+[ @Constant | @{Font Style}
+* FONT_BOLD | Bold
+* FONT_ITALIC | Italic
+* FONT_UNDERLINE | Underlined
+* FONT_STRIKETHROUGH | *Strikethrough
+]
+
+%{Note: FONT_STRIKETHROUGH isn't fully supported by all gadgets/platforms.}
+
+See Also: #LoadGuiFont, #RequestFont, #FontName and #FontSize
+EndRem
+Function FontStyle(font:TGuiFont)
+	Return font.style
+End Function
+
+Const POINTER_DEFAULT=0
+Const POINTER_ARROW=1
+Const POINTER_IBEAM=2
+Const POINTER_WAIT=3
+Const POINTER_CROSS=4
+Const POINTER_UPARROW=5
+Const POINTER_SIZENWSE=6
+Const POINTER_SIZENESW=7
+Const POINTER_SIZEWE=8
+Const POINTER_SIZENS=9
+Const POINTER_SIZEALL=10
+Const POINTER_NO=11
+Const POINTER_HAND=12
+Const POINTER_APPSTARTING=13
+Const POINTER_HELP=14
+
+Global lastPointer% = -1
+
+Rem
+bbdoc: Changes the applcation's mouse cursor.
+about:
+The shape of the system mouse pointer can be one of the following:
+
+[ @Constant | @Description
+* POINTER_DEFAULT | Default OS pointer.
+* POINTER_ARROW | Arrow pointer.
+* POINTER_IBEAM | Typically used when making text selections.
+* POINTER_WAIT | Hourglass animation.
+* POINTER_CROSS | Typically used for precise drawing.
+* POINTER_UPARROW | Typically used for selections.
+* POINTER_SIZENWSE | Typically used over sizing handles.
+* POINTER_SIZENESW | Typically used over sizing handles.
+* POINTER_SIZEWE | Typically used over sizing handles.
+* POINTER_SIZENS | Typically used over sizing handles.
+* POINTER_SIZEALL | Typically shown when moving an item.
+* POINTER_NO | Typically shown when an action is prohibited.
+* POINTER_HAND | Typically used for links.
+* POINTER_APPSTARTING | Usually shows a pointer and miniature hourglass animation.
+* POINTER_HELP | Usually shows an arrow pointer, with an adjacent question mark.
+]
+
+%{Note: Some pointers may not be supported on all platforms.}
+EndRem
+Function SetPointer(shape)
+	If shape <> lastPointer Then
+		lastPointer = shape
+		maxgui_driver.SetPointer(shape)
+	EndIf
+End Function
+
+Function 	UserName$()
+	Return maxgui_driver.UserName()
+End Function	
+
+Function 	ComputerName$()
+	Return maxgui_driver.ComputerName()
+End Function
+
+' gadget
+
+Rem
+bbdoc: Remove a gadget and free its resources.
+EndRem
+Function FreeGadget( gadget:TGadget )
+	gadget.CleanUp()
+End Function
+
+Rem
+bbdoc: Client area dimensions of a gadget.
+returns: The width of the client area (in pixels) of the specified container gadget.
+EndRem
+Function ClientWidth( gadget:TGadget )
+	Return gadget.ClientWidth()
+End Function
+
+Rem
+bbdoc: Client area dimensions of a gadget.
+returns: The height of the client area (in pixels) of the specified container gadget.
+EndRem
+Function ClientHeight( gadget:TGadget )
+	Return gadget.ClientHeight()
+End Function
+
+Rem
+bbdoc: Horizontal position of gadget.
+returns: The horizontal position (in pixels) of a gadget relative to the top-left corner of the parent's client area.
+EndRem
+Function GadgetX( gadget:TGadget )
+	Return gadget.GetXPos()
+End Function
+
+Rem
+bbdoc: Vertical position of gadget.
+returns: The vertical position (in pixels) of a gadget relative to the top-left corner of the parent's client area.
+EndRem
+Function GadgetY( gadget:TGadget )
+	Return gadget.GetYPos()
+End Function
+
+Rem
+bbdoc: Gadget width.
+returns: The current width (in pixels) of a gadget.
+EndRem
+Function GadgetWidth( gadget:TGadget )
+	Return gadget.GetWidth()
+End Function
+
+Rem
+bbdoc: Gadget height.
+returns: The current height (in pixels) of a gadget.
+EndRem
+Function GadgetHeight( gadget:TGadget )
+	Return gadget.GetHeight()
+End Function
+
+Rem
+bbdoc: Return a gadget's group or parent.
+returns: The @TGadget instance of the parent or group gadget.
+EndRem
+Function GadgetGroup:TGadget( gadget:TGadget )
+	Return gadget.GetGroup()
+End Function
+
+Rem
+bbdoc: Returns an integer representing a gadget's class.
+about: The returned integer will match one of the following constants:
+
+[ @Constant | @{Corresponding Gadget Class}
+* GADGET_DESKTOP | Desktop
+* GADGET_WINDOW | Window
+* GADGET_BUTTON | Button
+* GADGET_PANEL | Panel
+* GADGET_TEXTFIELD | TextField
+* GADGET_TEXTAREA | TextArea
+* GADGET_COMBOBOX | ComboBox
+* GADGET_LISTBOX | ListBox
+* GADGET_TOOLBAR | Toolbar
+* GADGET_TABBER | Tabber
+* GADGET_TREEVIEW | Treeview
+* GADGET_HTMLVIEW | HtmlView
+* GADGET_LABEL | Label
+* GADGET_SLIDER | Slider
+* GADGET_PROGBAR | Progress Bar
+* GADGET_MENUITEM | Menu
+* GADGET_NODE | Treeview Node
+* GADGET_CANVAS | Canvas Gadget
+]
+
+EndRem
+Function GadgetClass( gadget:TGadget )
+	Return gadget.Class()
+End Function
+
+Rem
+bbdoc: Make a gadget visible.
+about: See Also: #HideGadget and #GadgetHidden.
+EndRem
+Function ShowGadget( gadget:TGadget )
+	gadget.SetShow True
+End Function
+
+Rem
+bbdoc: Hide a gadget.
+about: See Also: #ShowGadget and #GadgetHidden.
+EndRem
+Function HideGadget( gadget:TGadget )
+	gadget.SetShow False
+End Function
+
+Rem
+bbdoc: Enable a gadget, allowing user interaction.
+about: See Also: #DisableGadget and #GadgetDisabled.
+EndRem
+Function EnableGadget( gadget:TGadget )
+	gadget.SetEnabled True
+End Function
+
+Rem
+bbdoc: Disable a gadget, blocking user interaction.
+about: See Also: #EnableGadget and #GadgetDisabled.
+EndRem
+Function DisableGadget( gadget:TGadget )
+	gadget.SetEnabled False
+End Function
+
+Rem
+bbdoc: Determines whether a gadget is marked as hidden.
+returns: #True if the gadget is set to be hidden, #False otherwise.
+about: If the optional @recursive parameter is set to #True, the function will only return #False
+if the gadget and all of its ancestors are visible, otherwise the function simply returns the
+property of the individual gadget.
+
+See Also: #ShowGadget and #HideGadget.
+EndRem
+Function GadgetHidden( gadget:TGadget, recursive% = False )
+	If recursive Then
+		While Not (gadget.State()&STATE_HIDDEN)
+			gadget = gadget.parent
+			If Not gadget Return False
+		Wend
+		Return True
+	EndIf	
+	Return (gadget.State()&STATE_HIDDEN)
+End Function
+
+Rem
+bbdoc: Determines whether a gadget is marked as enabled.
+returns: #True if the gadget is set to be disabled, #False otherwise.
+about: If the optional @recursive parameter is set to #True, the function will only return #False
+if the gadget and all of its ancestors are enabled, otherwise the function simply returns the
+property of the individual gadget.
+
+See Also: #EnableGadget and #DisableGadget.
+EndRem
+Function GadgetDisabled( gadget:TGadget, recursive% = False )
+	If recursive Then
+		While Not (gadget.State()&STATE_DISABLED)
+			gadget = gadget.parent
+			If Not gadget Return False
+		Wend
+		Return True
+	EndIf	
+	Return (gadget.State()&STATE_DISABLED)
+End Function
+
+Rem
+bbdoc: Set a gadget's size and position.
+about: The position and size should be given in pixels, and are relative to the upper-left corner of its parent's client-area.
+
+The @w and @h parameters set the gadget width or height, unless the gadget concerned is a window with the WINDOW_CLIENTCOORDS flag,
+in which case, they represent the client-area dimensions.
+EndRem
+Function SetGadgetShape( gadget:TGadget,x,y,w,h )
+	gadget.SetShape x,y,w,h
+End Function
+
+Rem
+bbdoc: Set the layout rules for a gadget when its parent is resized.
+about:
+#SetGadgetLayout lets you control the automatic layout of a gadget in the event that its parent is resized.
+
+This will happen either if a window is resized, or if #SetGadgetShape is called on a group gadget.
+
+Each edge of a @Gadget has an alignment setting that fixes it in place in the following manner:
+
+[ @Constant | @Description
+* EDGE_CENTERED | The edge of the gadget is kept a fixed distance from the center of its parent.
+* EDGE_ALIGNED | The edge of the gadget stays a fixed distance from its parent's corresponding edge.
+* EDGE_RELATIVE | The edge of the gadget remains a proportional distance from both of its parent's edges.
+]
+
+The default behaviour may vary between platforms, so it is highly recommended that you set this for gadgets on resizable windows.
+EndRem
+Function SetGadgetLayout( gadget:TGadget,Left,Right,Top,Bottom )
+	gadget.SetLayout Left,Right,Top,Bottom
+End Function
+
+Rem
+bbdoc: Sets whether a standard MaxGUI gadget emits events from the keyboard or mouse.
+about: This functions attempts to provide similar functionality for all gadgets to that of @Panels created with the PANEL_ACTIVE flag.
+
+The @flags parameter can be any combination of the following:
+
+SENSITIZE_MOUSE: The gadget will emit the following events:
+
+[ @{Event ID} | @Description
+* EVENT_MOUSEDOWN | Mouse button pressed. Event data contains mouse button code.
+* EVENT_MOUSEUP | Mouse button released. Event data contains mouse button code.
+* EVENT_MOUSEMOVE | Mouse moved. Event x and y contain mouse coordinates.
+* EVENT_MOUSEWHEEL | Mouse wheel spun. Event data contains delta clicks.
+* EVENT_MOUSEENTER | Mouse entered gadget area.
+* EVENT_MOUSELEAVE | Mouse left gadget area.
+]
+
+SENSITIZE_KEYS: The gadget will emit the following events:
+
+[ @{Event ID} | @Description
+* EVENT_KEYDOWN | Key pressed. Event data contains keycode.
+* EVENT_KEYUP | Key released. Event data contains keycode.
+* EVENT_KEYREPEAT | Key is being held down. Event data contains keycode.
+]
+
+SENSITIZE_ALL: Exactly the same as combining SENSITIZE_MOUSE and SENSITIZE_KEYS.
+
+Gadgets that have been disabled should not emit key events, although they may still emit mouse events.
+
+Not all gadgets will be able to emit all of the events, particularly those that don't receive typical focus
+such as labels or htmlviews, but even this may differ depending on the platform.
+
+%{ @{Warning:} This is a powerful new function that possibly involves hooking into the system's message queue
+to ask for mouse/key events before they are processed even by the OS's GUI library. As such, using this function
+on certain controls may cause them to be behave differently. In addition, care should be taken when using
+this function to avoid infinite loops, for example repositioning gadgets in an event hook that processes the
+message as it is received.
+
+It is therefore recommended that this function is only used by advanced MaxGUI users.}
+
+See Also: #GadgetSensitivity
+EndRem
+Function SetGadgetSensitivity( gadget:TGadget, flags )
+	Return gadget.SetSensitivity( flags )
+End Function
+
+Rem
+bbdoc: Returns flags specifying whether a gadget emits events from the keyboard or mouse.
+about: The function will return a combination of the following flags:
+
+[
+* SENSITIZE_MOUSE: The gadget will emit mouse events.
+* SENSITIZE_KEYS: The gadget will emit keyboard events.
+]
+
+See #SetGadgetSensitivity for more information.
+EndRem
+Function GadgetSensitivity( gadget:TGadget )
+	Return gadget.GetSensitivity()
+End Function
+
+
+Rem
+bbdoc: Stores a pointer to a related object, that can later be retrieved using #GadgetExtra.
+about:
+This function has many uses - you may want to store a custom type instance to the treeview node that
+represents it, or you may want to store a hidden string value that represents a gadget's action.
+
+However, it is important to note that this function will result in a pointer being stored to that object
+which will only be released when a new object or #Null is passed to this function, or when the gadget is freed
+using #FreeGadget.
+End Rem
+Function SetGadgetExtra( gadget:TGadget, extra:Object )
+	gadget.extra = extra
+End Function
+
+Rem
+bbdoc: Retrieves the object instance previously stored using #SetGadgetExtra.
+End Rem
+Function GadgetExtra:Object( gadget:TGadget )
+	Return gadget.extra
+End Function
+
+Rem
+bbdoc: Request focus for a gadget.
+about: See Also: #ActiveGadget()
+EndRem
+Function ActivateGadget( gadget:TGadget )
+	gadget.Activate ACTIVATE_FOCUS
+End Function
+
+Rem
+bbdoc: Return the currently active gadget.
+returns: The gadget that currently has the keyboard focus. Returns #Null if no MaxGUI gadget has focus.
+about: See Also: #ActivateGadget.
+EndRem
+Function ActiveGadget:TGadget()
+	Return maxgui_driver.ActiveGadget()
+End Function
+
+Rem
+bbdoc: Perform a cut operation on a gadget.
+about: This is most commonly used on @TextAreas to cut text that is currently selected.
+EndRem
+Function GadgetCut( gadget:TGadget )
+	gadget.Activate ACTIVATE_CUT
+End Function
+
+Rem
+bbdoc: Perform a copy operation on a gadget.
+about: This is most commonly used on @TextAreas to copy text that is currently selected.
+EndRem
+Function GadgetCopy( gadget:TGadget )
+	gadget.Activate ACTIVATE_COPY
+End Function
+
+Rem
+bbdoc: Perform a paste operation on a gadget.
+about: This is most commonly used on @TextAreas to paste text into the gadget from the clipboard.
+EndRem
+Function GadgetPaste( gadget:TGadget )
+	gadget.Activate ACTIVATE_PASTE
+End Function
+
+Rem
+bbdoc: Perform a print operation on a gadget.
+about: This function is currently only supported on @TextAreas and @HTMLViews.
+EndRem
+Function GadgetPrint( gadget:TGadget )
+	gadget.Activate ACTIVATE_PRINT
+End Function
+
+Rem
+bbdoc: Redraws a gadget.
+about:
+The RedrawGadget command requests that the gadget should be redrawn by the underlying
+Operating System but is not necessarily guaranteed to happen immediately.
+
+In the case of a @Canvas gadget an EVENT_GADGETPAINT event is emitted
+when the Operating System begins the actual redraw. The following example
+illustrates how to manage this feature:
+EndRem
+Function RedrawGadget( gadget:TGadget )
+	gadget.Activate ACTIVATE_REDRAW
+End Function
+
+Rem
+bbdoc: Set a gadget's pixmap.
+about: This is a more generic form of old backwards-compatible #SetPanelPixmap function which now allows icons
+to be set for other gadgets as well as just backgrounds for panels.
+
+For setting background pixmaps on panels, @flags should still be one of the following:
+
+[ @Flag | @Description
+* PANELPIXMAP_TILE | The panel is filled with repeating tiles.
+* PANELPIXMAP_CENTER | The pixmap is positioned at the center of the panel.
+* PANELPIXMAP_FIT | The pixmap is scaled proportionally to best fit the panel size.
+* PANELPIXMAP_FIT2 | A variant of PANELPIXMAP_FIT where clipping can occur to achieve a better fit.
+* PANELPIXMAP_STRETCH | The pixmap is stretched to fit the entire panel.
+]
+
+Alternatively, to set a push-button or menu's icon, use the following constants:
+
+[ @Flag | @Description
+* GADGETPIXMAP_ICON | Places an icon-sized pixmap onto a push-button/menu.
+* GADGETPIXMAP_NOTEXT | Removes text on buttons when used in conjunction with GADGETPIXMAP_ICON.
+]
+
+Each platform allows slightly different maximum icon sizes for their menus. Therefore, the recommended
+size for menu icons is 12x12 pixels which appears to work well on all supported platforms.
+
+Note: At present, OK buttons do not support icons as a cross-platform solution is unavailable. Icons
+are also not supported for radio buttons or checkbox style buttons.
+
+Passing #Null as the value for the @pixmap parameter will remove the pixmap from the gadget.
+EndRem
+Function SetGadgetPixmap( gadget:TGadget, pixmap:TPixmap, flags% = GADGETPIXMAP_ICON )
+	Return gadget.SetPixmap( pixmap, flags )
+End Function
+
+Rem
+bbdoc: Set the transparency of a gadget.
+about: Alpha should be in the range 0.0 (invisible) to 1.0 (solid). Very few gadgets support this functionality,
+but some Mac OS X gadgets do, in addition to @Windows when running Windows XP+. In certain circumstances, window
+transparency may be disabled (for example, when a canvas is added to a window) to prevent redraw issues on some
+platforms.
+
+Using the function on windows with @Canvases on them may cause undesired effects, particularly on Windows 2000/XP
+because of conflicts between the software based window manager and the hardware accelerated graphics contexts.
+EndRem
+Function SetGadgetAlpha( gadget:TGadget,alpha# )
+	gadget.SetAlpha(alpha)
+End Function
+
+Rem
+bbdoc: Sets a gadget's text.
+about: For the @Label, @Button, @TextField, @ComboBox, @TextArea and Group @Panel gadgets, the contents
+of the gadget are replaced with the new @text$.
+
+For a @Window gadget, #SetGadgetText changes the title. For @{Window}s with a status bar, #SetStatusText
+should be used to independently set the status bar text.
+
+This command will automatically delocalize the gadget - to set localized gadget text, see #LocalizeGadget.
+EndRem
+Function SetGadgetText( gadget:TGadget,Text$ )
+	maxgui_driver.DelocalizeGadget( gadget )
+	gadget.SetText( Text )
+End Function
+
+Rem
+bbdoc: Returns a gadget's text.
+about: For the @Label, @Button, @TextField, @ComboBox, @TextArea and Group @Panel gadgets, the contents
+of the gadget are returned with the new gadget's text.
+
+For a @Window gadget, #GadgetText returns the title of the @Window.
+EndRem
+Function GadgetText$( gadget:TGadget )
+	Return gadget.GetText()
+End Function
+
+Rem
+bbdoc: Set a gadget's tooltip.
+about: Sets the tooltip for a %{non-item based} positionable MaxGUI gadget. This function will have no effect on the following gadget types:
+
+[
+* Windows
+* Menus
+* Tree-view nodes
+* List-boxes
+* Toolbars
+* Tabbers
+* Desktops
+]
+
+This command will automatically delocalize the gadget - to set a localized gadget tooltip, see #LocalizeGadget.
+
+See Also: #GadgetTooltip()
+EndRem
+Function SetGadgetToolTip( gadget:TGadget, tip$ )
+	maxgui_driver.DelocalizeGadget( gadget )
+	gadget.SetTooltip( tip )
+End Function
+
+Rem
+bbdoc: Returns the gadget tooltip previously set with #SetGadgetTooltip.
+about: Returns the tooltip for a %{non-item based} positionable MaxGUI gadget. As such, this function will have no effect on the following gadget types:
+
+[
+* Windows
+* Menus
+* Tree-view nodes
+* List-boxes
+* Toolbars
+* Tabbers
+* Desktops
+]
+
+See Also: #SetGadgetTooltip()
+EndRem
+Function GadgetTooltip$( gadget:TGadget )
+	Return gadget.GetTooltip()
+End Function
+
+Rem
+bbdoc: Set a gadget's font.
+about: See #LoadGuiFont and #RequestFont for creating a @TGuiFont.
+EndRem
+Function SetGadgetFont( gadget:TGadget,font:TGuiFont )
+	gadget.SetFont( font )
+End Function
+
+Rem
+bbdoc: Set a gadget's foreground color.
+about: The @{r}ed, @{g}reen and @{b}lue components should be in the range 0 to 255.
+See Also: #SetGadgetColor()
+EndRem
+Function SetGadgetTextColor( gadget:TGadget,r,g,b )
+	gadget.SetTextColor( r,g,b )
+End Function
+
+Rem
+bbdoc: Set a gadget's background color.
+about: The @{r}ed, @{g}reen and @{b}lue components should be in the range 0 to 255.
+This command is not supported for all Gadget types on all platforms.
+See Also: #SetGadgetTextColor() #SetGadgetAlpha #RemoveGadgetColor
+EndRem
+Function SetGadgetColor( gadget:TGadget,r,g,b,bg=True )
+	If bg
+		gadget.SetColor r,g,b
+	Else
+		gadget.SetTextColor( r,g,b )
+	EndIf
+End Function
+
+Rem
+bbdoc: Removes a gadget's background color.
+about: Restores a gadget to it's default color.
+See Also: #SetGadgetColor()
+EndRem
+Function RemoveGadgetColor( gadget:TGadget )
+	gadget.RemoveColor
+End Function
+
+
+Rem
+bbdoc: Set the hot-key combination for a gadget.
+End Rem
+Function SetGadgetHotKey( gadget:TGadget,hotkey,modifier )
+	gadget.SetHotKey hotkey,modifier
+End Function
+
+Rem
+bbdoc: Attaches an event filter function to a MaxGUI gadget.
+about:
+The filter function supplied is called by the gadget with a #TEvent
+and optional user context object. If the function returns zero the event
+is filtered and not processed further by the system whereas a non zero
+return indicates event processing should proceed as normal.
+
+The TextArea/TextField events currently supported:
+
+[ @{Event ID} | @Description
+* EVENT_KEYDOWN | Key pressed. Event data contains keycode.
+* EVENT_KEYCHAR | Key character. Event data contains unicode value.
+]
+
+Currently only the EVENT_KEYDOWN, EVENT_KEYCHAR events produced by
+TextArea and TextField gadgets can be filtered with the SetGadgetFilter
+command.
+End Rem
+Function SetGadgetFilter( gadget:TGadget,callback(event:TEvent,context:Object),context:Object=Null )
+	gadget.SetFilter callback,context
+End Function
+
+
+' localization (constants declared in maxgui.mod/driver.bmx)
+
+Rem
+bbdoc: Localize a gadget using the supplied localization strings.
+about: The function will use the supplied localization strings to localize a gadget and its text.  The gadget
+will also be marked so that changing the language will update the text.  Calling #DelocalizeGadget or
+#SetGadgetText will disable this behaviour.
+
+Localization strings and their structure are described in #LocalizeString function documentation.
+
+Item-based gadgets should mark any items, whose strings are also wanted to be localized, with the
+GADGETITEM_LOCALIZED flag.  See the @flags parameter of the #AddGadgetItem / #InsertGadgetItem
+/ #ModifyGadgetItem calls.
+
+See Also: #GadgetLocalized, #SetLocalizationMode and #SetLocalizationLanguage.
+EndRem
+Function LocalizeGadget( gadget:TGadget, localizationtext$, localizationtooltip$ = "" )
+	maxgui_driver.SetGadgetLocalization( gadget, localizationtext, localizationtooltip )
+EndFunction
+
+Rem
+bbdoc: Determines whether a gadget is registered as being 'localized'.
+about: See #LocalizeGadget and #SetLocalizationMode for more information.
+EndRem
+Function GadgetLocalized:Int( gadget:TGadget )
+	Return maxgui_driver.GadgetLocalized(gadget)
+EndFunction
+
+Rem
+bbdoc: Delocalizes a gadget so that it's no longer updated if the localization language/mode changes.
+about: See Also: #LocalizeGadget, #SetLocalizationLanguage and #SetLocalizationMode.
+EndRem
+Function DelocalizeGadget( gadget:TGadget )
+	maxgui_driver.DelocalizeGadget( gadget )
+EndFunction
+
+
+' menus
+
+Rem
+bbdoc: Creates a new menu item.
+about: Menu gadgets should be attached to either a #WindowMenu, other Menu gadgets
+or used with the #PopupWindowMenu command. The tag field should be a unique identifier
+that will be present in the #EventData field of EVENT_MENUACTION events.
+
+Keyboard shortcuts can be associated with a Menu by using the optional hotKey and
+modifier parameters.
+
+Please refer to the #{key codes} module for valid key and modifier codes.
+The MODIFIER_COMMAND value should be used instead of MODIFIER_CONTROL
+with Menu hotkeys for best crossplatform compatability.
+
+Menus now also support icons on most platforms through the use of #SetGadgetPixmap.
+
+See Also: #FreeMenu, #SetMenuText, #CheckMenu, #UncheckMenu, #EnableMenu, #DisableMenu,
+#MenuText, #MenuChecked, #MenuEnabled and #SetGadgetPixmap.
+EndRem
+Function CreateMenu:TGadget( Text$,tag,parent:TGadget,hotkey=0,modifier=0 )
+	Local gadget:TGadget=maxgui_driver.CreateGadget(GADGET_MENUITEM,Text,0,0,0,0,GetGroup(parent),tag)
+	If gadget And hotKey SetGadgetHotKey gadget,hotKey,modifier
+	Return gadget
+End Function
+
+Rem
+bbdoc: Remove a menu.
+about: This function has been superseded by #FreeGadget, but is available for backwards compatability.
+EndRem
+Function FreeMenu( menu:TGadget )
+	menu.CleanUp()
+End Function
+
+Rem
+bbdoc: Modify a menu's text.
+about: This function has been superseded by #SetGadgetText, but is available for backwards compatability.
+EndRem
+Function SetMenuText( menu:TGadget,Text$ )
+	SetGadgetText( menu, Text )
+End Function
+
+Rem
+bbdoc: Set a menu's checked state.
+about: #UpdateWindowMenu should be called where appropriate after changing a menu's state for the changes
+to become visible.
+EndRem
+Function CheckMenu( menu:TGadget )
+	menu.SetSelected True
+End Function
+
+Rem
+bbdoc: Clear a menu's checked state.
+about: #UpdateWindowMenu should be called where appropriate after changing a menu's state for the changes
+to become visible.
+EndRem
+Function UncheckMenu( menu:TGadget )
+	menu.SetSelected False
+End Function
+
+Rem
+bbdoc: Enable a menu for selection.
+about: #UpdateWindowMenu should be called where appropriate after changing a menu's status for the changes
+to become visible.
+EndRem
+Function EnableMenu( menu:TGadget )
+	menu.SetEnabled True
+End Function
+
+Rem
+bbdoc: Disable a menu so it cannot be selected.
+about: #UpdateWindowMenu should be called where appropriate after changing a menu's status for the changes
+to become visible.
+EndRem
+Function DisableMenu( menu:TGadget )
+	menu.SetEnabled False
+End Function
+
+Rem
+bbdoc: Return a menu's text.
+about: This function has been superseded by #GadgetText, but is available for backwards compatability.
+EndRem
+Function MenuText$( menu:TGadget )
+	Return menu.GetText()
+End Function
+
+Rem
+bbdoc: Return a menu's checked state.
+EndRem
+Function MenuChecked( menu:TGadget )
+	Return (menu.State()&STATE_SELECTED)<>0
+End Function
+
+Rem
+bbdoc: Return a menu's enabled state.
+EndRem
+Function MenuEnabled( menu:TGadget )
+	Return Not (menu.State()&STATE_DISABLED)
+End Function
+
+' desktop
+
+Rem
+bbdoc: Return a gadget representing the system's desktop.
+about: This is particularly useful for finding the resolution of the desktop using #GadgetWidth / #ClientWidth or #GadgetHeight / #ClientHeight.
+EndRem
+Function Desktop:TGadget()
+	Return maxgui_driver.CreateGadget(GADGET_DESKTOP,"",0,0,0,0,Null,0)
+End Function
+
+' window
+
+Rem
+bbdoc: Create a Window gadget.
+about:
+A Window is the primary gadget of MaxGUI. Windows should be used as the primary
+group gadgets in MaxGUI applications to contain the gadgets that make up the program's
+user interface.
+
+The following style flags are supported when creating a Window. Any of the
+style flags can be combined using the bitwise operator '|'.
+
+[ @Style | @Meaning
+* WINDOW_TITLEBAR | The Window has a titlebar that displays the @titletext$.
+* WINDOW_RESIZABLE | The Window can be resized by the user.
+* WINDOW_MENU | The Window has an associated window menu (retrieve menu handle using #WindowMenu).
+* WINDOW_STATUS | The Window has a statusbar.
+* WINDOW_TOOL | A window style commonly used for toolbars and other tool windows.
+* WINDOW_CLIENTCOORDS | The dimensions specified relate to the client area as opposed to the window frame.
+* WINDOW_CENTER | The x and y parameters are ignored, and the Window is positioned either in the middle of the screen or the middle of the parent gadget.
+* WINDOW_HIDDEN | The Window is created in a hidden state and can be revealed later using #ShowGadget.
+* WINDOW_ACCEPTFILES | Enable file drag and drop operations (emits the EVENT_WINDOWACCEPT events).
+]
+
+Note: For cross-platform projects, it is highly recommended that the WINDOW_CLIENTCOORDS style is used to maintain
+similar layouts with different operating systems and window managers.
+
+The default window style (WINDOW_DEFAULT) is equivalent to WINDOW_TITLEBAR | WINDOW_RESIZABLE | WINDOW_MENU | WINDOW_STATUS.
+
+A Window emits the following events:
+
+[ @{Event ID} | @Description
+* EVENT_WINDOWMOVE | Window has been moved.
+* EVENT_WINDOWSIZE | Window has been resized.
+* EVENT_WINDOWCLOSE | Window close icon clicked.
+* EVENT_WINDOWACTIVATE | Window has been activated.
+* EVENT_WINDOWACCEPT | A file was dropped onto a Window with the WINDOW_ACCEPTFILES style. The event @Extra object holds the filepath.
+]
+
+See Also: #WindowMenu, #UpdateWindowMenu, #PopupWindowMenu, #ActivateWindow, #SetStatusText, #WindowStatusText, 
+#SetMinWindowSize, #SetMaxWindowSize, #MinimizeWindow, #MaximizeWindow, #RestoreWindow, #WindowMinimized
+and #WindowMaximized.
+EndRem
+Function CreateWindow:TGadget( titletext$,x,y,w,h,group:TGadget=Null,style=WINDOW_DEFAULT )
+	If (style&WINDOW_CENTER) Then
+		If group Then
+			x = GadgetX(group) + (GadgetWidth(group)-w)/2
+			y = GadgetY(group) + (GadgetHeight(group)-h)/2
+		Else
+			x = (Min(GadgetWidth(Desktop()), ClientWidth(Desktop()))-w)/2
+			y = (Min(GadgetHeight(Desktop()), ClientHeight(Desktop()))-h)/2
+		EndIf
+	EndIf
+	Return maxgui_driver.CreateGadget(GADGET_WINDOW,titletext,x,y,w,h,GetGroup(group),style)
+End Function
+
+Rem
+bbdoc: Returns a window's main-menu handle.
+about: Required when a root menu is to be added to a window using #CreateMenu. This function
+should %not be used for sub-menus - the sub-menu should be parented directly to its parent menu.
+
+It should also be mentioned that this function isn't required when creating popup menus - #Null should
+instead be passed as the parent of the root menu.
+
+To avoid any unexpected behavior, make sure that the window specified was created with the WINDOW_MENU
+style flag.
+
+See Also: #CreateMenu and #UpdateWindowMenu
+EndRem
+Function WindowMenu:TGadget( window:TGadget )
+	Return window.GetMenu()
+End Function
+
+Rem
+bbdoc: Update a window's menu hierachy.
+about: Required after changing a window's menu properties/structure for the changes to become visible.
+
+To avoid any unexpected behavior, make sure that the window specified was created with the WINDOW_MENU
+style flag.
+
+See Also: #WindowMenu and #CreateMenu
+EndRem
+Function UpdateWindowMenu( window:TGadget )
+	window.UpdateMenu()
+End Function
+
+Rem
+bbdoc: Display a popup menu.
+about: A popup context-menu is displayed on the screen at the user's current mouse position.
+See Also: #CreateMenu
+EndRem
+Function PopupWindowMenu( window:TGadget,menu:TGadget,extra:Object=Null )
+	window.PopupMenu(menu,extra)
+End Function
+
+Rem
+bbdoc: Activate a window gadget.
+about: This function has been superseded by #ActivateGadget, but is available for backwards compatability.
+EndRem
+Function ActivateWindow( window:TGadget )
+	window.Activate ACTIVATE_FOCUS
+End Function
+
+Rem
+bbdoc: Retrieve a window's status-bar text.
+about: Can only be used with windows created with the WINDOW_STATUS flag (see #CreateWindow). Tab characters
+delimit between the three alignments of text.  See #SetStatusText for more information.
+EndRem
+Function WindowStatusText$( window:TGadget )
+	Return window.GetStatusText()
+End Function
+
+Rem
+bbdoc: Set a window's status bar text.
+about: Can only be used with windows created with the WINDOW_STATUS flag (see #CreateWindow). Use tab characters
+to delimit between the three alignments of text.  For example:
+
+{{
+SetStatusText( window, "Left Aligned Only" )
+SetStatusText( window, "Left Aligned~tCenter Aligned~tRight Aligned" )
+SetStatusText( window, "~tCenter Aligned Only" )
+SetStatusText( window, "~t~tRight Aligned Only" )
+}}
+
+See Also: #WindowStatusText
+EndRem
+Function SetStatusText( window:TGadget,Text$ )
+	window.SetStatusText Text
+End Function
+
+Rem
+bbdoc: Set a window's minimum size.
+about: Only useful for resizable windows (i.e. windows created with the WINDOW_RESIZABLE flag, see #CreateWindow).
+EndRem
+Function SetMinWindowSize( window:TGadget,w,h )
+	window.SetMinimumSize( w,h )
+End Function
+
+Rem
+bbdoc: Set a window's maximum size.
+about: Only useful for resizable windows (i.e. windows created with the WINDOW_RESIZABLE flag, see #CreateWindow).
+
+Calling this function will disable the Maximize button window hint on Windows, and will limit the window zoom size on Mac OS X.
+EndRem
+Function SetMaxWindowSize( window:TGadget,w,h )
+	window.SetMaximumSize( w,h )
+End Function
+
+Rem
+bbdoc: Minimize a window.
+about: A minimized window can be restored by the user to its previous state, typically by clicking on the icon representation
+of the window in the taskbar or dock.  The same effect can be obtained programatically by calling #RestoreWindow.
+
+See Also: #WindowMinimized.
+EndRem
+Function MinimizeWindow( window:TGadget )
+	window.Activate ACTIVATE_MINIMIZE
+End Function
+
+Rem
+bbdoc: Maximize a window.
+about:
+Maximizing a window makes the window visible and sizes it to fill the current desktop.  #RestoreWindow can be used to
+programatically restore a window to its previous unmaximized state, although the window will still remain unhidden.
+
+See Also: #WindowMaximized.
+EndRem
+Function MaximizeWindow( window:TGadget )
+	window.Activate ACTIVATE_MAXIMIZE
+End Function
+
+Rem
+bbdoc: Restore a window from a minimized or maximized state.
+about: See Also: #MinimizeWindow and #MaximizeWindow.
+EndRem
+Function RestoreWindow( window:TGadget )
+	window.Activate ACTIVATE_RESTORE
+End Function
+
+Rem
+bbdoc: Detect if a window is minimized.
+returns: #True if the window is currently minimized, #False if not.
+EndRem
+Function WindowMinimized( window:TGadget )
+	Return (window.State()&STATE_MINIMIZED)<>0
+End Function
+
+Rem
+bbdoc: Detect if a window is maximized.
+returns: #True if the window is currently maximized, #False if not.
+about: A maximized window fills the entire desktop. A window may
+be maximized with the #MaximizeWindow command or by the user if
+#CreateWindow was called with the WINDOW_RESIZABLE flag.
+EndRem
+Function WindowMaximized( window:TGadget )
+	Return (window.State()&STATE_MAXIMIZED)<>0
+End Function
+
+' button
+
+Rem
+bbdoc: Create a Button gadget.
+about:
+A Button generates an EVENT_GADGETACTION #TEvent whenever it is pushed.
+
+[ @Style | @Meaning
+* BUTTON_PUSH | Standard push button.
+* BUTTON_CHECKBOX | A check box button that displays a tick when its state is #True.
+* BUTTON_RADIO | A radio button is accompanied by a small circular indicator, filled when its state is #True.
+* BUTTON_OK | Standard push button that is also activated when the user presses the RETURN key.
+* BUTTON_CANCEL | Standard push button that is also activated when the user presses the ESCAPE key.
+]
+
+On certain platforms, the BUTTON_PUSH flag can be combined with either BUTTON_CHECKBOX or BUTTON_RADIO to obtain
+a button looking similar to standard push-buttons, but mimicking the behaviour of the checkbox or radio button.
+
+See Also: #SetGadgetText, #SetButtonState, #ButtonState and #SetGadgetPixmap.
+EndRem
+Function CreateButton:TGadget(label$,x,y,w,h,group:TGadget,style=BUTTON_PUSH)
+	Return maxgui_driver.CreateGadget(GADGET_BUTTON,label,x,y,w,h,GetGroup(group),style)
+End Function
+
+Rem
+bbdoc: Set a button's state.
+about:
+Buttons created with the BUTTON_CHECKBOX and BUTTON_RADIO styles are able to show a selected state.
+In addition, the BUTTON_CHECKBOX style may also be able to distinguish an indeterminate state from that
+of a checked state through the use of the CHECK_INDETERMINATE (-1) constant, depending on the platform.
+
+See Also: #CreateButton, #SetGadgetText, #ButtonState and #SetGadgetPixmap.
+EndRem
+Function SetButtonState( button:TGadget,checked )
+	button.SetSelected checked
+End Function
+
+Rem
+bbdoc: Retrieve a button's state.
+about:
+Returns a non-zero value if a checkbox or radio button is selected or false if it isn't.
+On certain platforms, if a checkbox is set using #SetButtonState to have an indeterminant
+state (CHECK_INDETERMINATE), then this function will return CHECK_INDETERMINATE too.
+See Also: #CreateButton, #SetGadgetText, #SetButtonState and #SetGadgetPixmap.
+EndRem
+Function ButtonState( button:TGadget )
+	Local tmpResult% = button.State()&STATE_INDETERMINATE
+	If (tmpResult&~STATE_SELECTED) Then Return -1 Else Return (tmpResult <> 0)
+End Function
+
+' panel
+
+Rem
+bbdoc: Create a Panel gadget.
+about:
+A Panel is a general purpose gadget that can be used to group other gadgets.
+
+Background colours and images can be set using #SetGadgetColor and #SetPanelPixmap.
+
+A panel can be created with any one of the following %optional styles:
+
+[ @Style | @Meaning
+* PANEL_SUNKEN | Panel is drawn with a sunken border (or just a simple border on OS X).
+* PANEL_RAISED | Panel is drawn with a raised border (or just a simple border on OS X).
+* PANEL_GROUP | Panel is drawn with a titled etched border.
+]
+
+The PANEL_ACTIVE flag can be combined with any other style flags, or specified on its own,
+to generate mouse and key events (equivalent to calling #SetGadgetSensitivity immediately
+after creation):
+
+[ @{Event ID} | @Description
+* EVENT_MOUSEDOWN | Mouse button pressed. Event data contains mouse button code.
+* EVENT_MOUSEUP | Mouse button released. Event data contains mouse button code.
+* EVENT_MOUSEMOVE | Mouse moved. Event x and y contain mouse coordinates.
+* EVENT_MOUSEWHEEL | Mouse wheel spun. Event data contains delta clicks.
+* EVENT_MOUSEENTER | Mouse entered gadget area.
+* EVENT_MOUSELEAVE | Mouse left gadget area.
+* EVENT_KEYDOWN | Key pressed. Event data contains keycode.
+* EVENT_KEYUP | Key released. Event data contains keycode.
+* EVENT_KEYCHAR | Key character. Event data contains unicode value.
+]
+
+%{Note: The PANEL_SUNKEN / PANEL_RAISED style flags cannot be used with PANEL_GROUP.}
+
+See Also: #SetPanelColor and #SetPanelPixmap.
+EndRem
+Function CreatePanel:TGadget(x,y,w,h,group:TGadget,style=0,title$="")
+	Return maxgui_driver.CreateGadget(GADGET_PANEL,title,x,y,w,h,GetGroup(group),style)
+End Function
+
+Rem
+bbdoc: Set the color of a Panel.
+about: This function has been superseded by #SetGadgetColor, but is available for backwards compatability.
+See Also: #CreatePanel and #SetPanelPixmap
+EndRem
+Function SetPanelColor( panel:TGadget,r,g,b )
+	panel.SetColor(r,g,b)
+End Function
+
+Rem
+bbdoc: Set panel's background image to a pixmap.
+about: This function has been superseded by #SetGadgetPixmap, but is available for backwards compatability.
+
+[ @Flags | @Description
+* PANELPIXMAP_TILE | The panel is filled with repeating tiles.
+* PANELPIXMAP_CENTER | The pixmap is positioned at the center of the panel.
+* PANELPIXMAP_FIT | The pixmap is scaled to best fit the panel size.
+* PANELPIXMAP_FIT2 | A variant of PANELPIXMAP_FIT where clipping can occur to achieve a better fit.
+* PANELPIXMAP_STRETCH | The pixmap is stretched to fit the entire panel.
+]
+
+The function can be passed 'Null' as the parameter for @pixmap, in which case the pixmap should be removed.
+
+See Also: #CreatePanel and #SetPanelColor
+EndRem
+Function SetPanelPixmap( panel:TGadget,pixmap:TPixmap,flags=PANELPIXMAP_TILE)
+	Return SetGadgetPixmap( panel,pixmap,flags)
+End Function
+
+' textfield
+
+Rem
+bbdoc: Create a TextField gadget.
+about: A TextField is a single line text entry gadget and currently has only one style flag:
+
+[ @Flags | @Description
+* TEXTFIELD_PASSWORD | Masks characters being typed as a string as asterisks.
+]
+
+Irrespective of the flag used, the TextField gadget will emit the following event(s):
+
+[ @{Event ID} | @Description
+* EVENT_GADGETACTION | The user has edited the text in the TextField.
+]
+
+It is also possible to validate any typed input before it reaches the TextArea using
+the #SetGadgetFilter command.
+
+See Also: #GadgetText, #SetGadgetText, #SetGadgetFilter.
+EndRem
+Function CreateTextField:TGadget(x,y,w,h,group:TGadget,style=0)
+	Return maxgui_driver.CreateGadget(GADGET_TEXTFIELD,"",x,y,w,h,GetGroup(group),style)
+End Function
+
+Rem
+bbdoc: Get the current text in a TextField gadget.
+about: This function has been superseded by #GadgetText, but is available for backwards compatability.
+See Also: #CreateTextField and #SetGadgetText
+EndRem
+Function TextFieldText$( textfield:TGadget )
+	Return textfield.GetText()
+End Function
+
+' textarea
+
+Rem
+bbdoc: Create a TextArea gadget.
+about:
+A TextArea gadget is a multiline text editor with commands that allow control
+over the contents, style and selection of the text it contains.
+
+A TextArea gadget may have the following optional styles:
+
+[ @Style | @Meaning
+* TEXTAREA_WORDWRAP | Long lines of text 'wrap round' onto the next lines.
+* TEXTAREA_READONLY | The text cannot be edited by the user.
+]
+
+A TextArea gadget can generate the following events:
+
+[ @{Event ID} | @Description
+* EVENT_GADGETACTION | The user has modified the text in a TextArea.
+* EVENT_GADGETSELECT | The text-cursor has moved or a selection of text is made by the user.
+* EVENT_GADGETMENU | The user has right-clicked somewhere in the TextArea.
+]
+
+It is also possible to validate any typed input before it reaches the TextArea using
+the #SetGadgetFilter command.
+
+See Also: #SetTextAreaText, #AddTextAreaText, #TextAreaText, #TextAreaLen, #LockTextArea,
+#UnlockTextArea, #SetTextAreaTabs, #SetGadgetFont, #SetGadgetColor, #TextAreaCursor,
+#TextAreaSelLen, #FormatTextAreaText, #SelectTextAreaText, #TextAreaChar, #TextAreaLine,
+#TextAreaCharX and #TextAreaCharY.
+EndRem
+Function CreateTextArea:TGadget(x,y,w,h,group:TGadget,style=0)
+	Return maxgui_driver.CreateGadget(GADGET_TEXTAREA,"",x,y,w,h,GetGroup(group),style)
+End Function
+
+Rem
+bbdoc: Set the contents of a TextArea gadget.
+about:
+See Also: #CreateTextArea, #AddTextAreaText and #SetGadgetText
+EndRem
+Function SetTextAreaText( textarea:TGadget,Text$,pos=0,length=TEXTAREA_ALL,units=TEXTAREA_CHARS )
+	textarea.ReplaceText(pos,length,Text,units)
+End Function
+
+Rem
+bbdoc: Append text to the contents of a TextArea gadget.
+about:
+See Also: #CreateTextArea, #SetTextAreaText and #SetGadgetText
+EndRem
+Function AddTextAreaText( textarea:TGadget,Text$ )
+	textarea.AddText(Text)
+End Function
+
+Rem
+bbdoc: Get the contents of a TextArea gadget.
+about:
+See Also: #CreateTextArea, #AddTextAreaText, #SetTextAreaText and #SetGadgetText
+EndRem
+Function TextAreaText$( textarea:TGadget,pos=0,length=TEXTAREA_ALL,units=TEXTAREA_CHARS )
+	Return textarea.AreaText(pos,length,units)
+End Function
+
+Rem
+bbdoc: Get the number of characters in a TextArea gadget.
+about:
+See Also: #CreateTextArea
+EndRem
+Function TextAreaLen( textarea:TGadget,units=TEXTAREA_CHARS )
+	Return textarea.AreaLen(units)
+End Function
+
+Rem
+bbdoc: Lock a TextArea gadget for improved performance when formatting.
+about:
+See Also: #UnlockTextArea and #CreateTextArea
+EndRem
+Function LockTextArea( textarea:TGadget )
+	textarea.locktext
+End Function
+
+Rem
+bbdoc: Unlock a previously locked TextArea gadget.
+about:
+See Also: #LockTextArea and #CreateTextArea
+EndRem
+Function UnlockTextArea( textarea:TGadget )
+	textarea.unlocktext
+End Function
+
+Rem
+bbdoc: Set the tab stops of a TextArea gadget measured in pixels.
+about:
+See Also: #CreateTextArea #SetIndents
+EndRem
+Function SetTextAreaTabs( textarea:TGadget,tabwidth )
+	textarea.SetTabs tabwidth
+End Function
+
+Rem
+bbdoc: Set left margin of a TextArea measured in pixels.
+about:
+See Also: #CreateTextArea and #SetTextAreaTabs
+EndRem
+Function SetMargins( textarea:TGadget,leftmargin )
+	textarea.SetMargins leftmargin
+End Function
+
+
+Rem
+bbdoc: Set the font of a TextArea gadget.
+about: This function has been superseded by #SetGadgetFont, but is available for backwards compatability.
+See Also: #CreateTextArea
+EndRem
+Function SetTextAreaFont( textarea:TGadget,font:TGuiFont )
+	textarea.SetFont font
+End Function
+
+Rem
+bbdoc: Set the background or foreground colors of a TextArea gadget.
+about: This function has been superseded by #SetGadgetColor, but is available for backwards compatability.
+See Also: #CreateTextArea
+EndRem
+Function SetTextAreaColor( textarea:TGadget,r,g,b,bg=False )
+	If bg
+		textarea.SetColor r,g,b
+	Else
+		textarea.SetTextColor r,g,b
+	EndIf
+End Function
+
+Rem
+bbdoc: Find the position of the cursor in a TextArea gadget.
+about:
+Use the default TEXTAREA_CHARS units argument to find out which character
+(column) in the line the cursor is on and use TEXTAREA_LINES to find out
+which line (row) the cursor is on.
+
+See Also: #TextAreaSelLen and #CreateTextArea
+EndRem
+Function TextAreaCursor( textarea:TGadget,units=TEXTAREA_CHARS )
+	Return textarea.GetCursorPos(units)
+End Function
+
+Rem
+bbdoc: Find the size of the selected text in a TextArea gadget.
+about:
+The TEXTAREA_CHARS option returns the number of characters currently
+highlighted by the user where as TEXTAREA_LINES will specify the
+function returns the number of lines selected.
+
+See Also: #TextAreaCursor and #CreateTextArea
+EndRem
+Function TextAreaSelLen( textarea:TGadget,units=TEXTAREA_CHARS )
+	Return textarea.GetSelectionLength( units )
+End Function
+
+Rem
+bbdoc: Format the color and style of some text in a TextArea gadget.
+about:
+The @r, @g and @b parameters represent the @{r}ed, @{g}reen and @{b}lue components (0..255)
+which, when combined, represent the new text color for the the sepecified region
+of characters.
+
+The @flags parameter can be a combination of the following values:
+
+[ @Constant | @Meaning
+* TEXTFORMAT_BOLD | Bold
+* TEXTFORMAT_ITALIC | Italic
+* TEXTFORMAT_UNDERLINE | Underline
+* TEXTFORMAT_STRIKETHROUGH | StrikeThrough
+]
+
+Depending on the value of the units parameter the position and length parameters specify
+the character position and number of characters or the starting line and the number
+of lines that FormatTextAreaText will modify.
+
+See Also: #LockTextArea and #CreateTextArea
+EndRem
+Function FormatTextAreaText( textarea:TGadget,r,g,b,flags,pos=0,length=TEXTAREA_ALL,units=TEXTAREA_CHARS )
+	textarea.SetStyle(r,g,b,flags,pos,length,units)	
+End Function
+
+Rem
+bbdoc: Select a range of text in a TextArea gadget.
+about:
+Depending on the value of the units the position and length parameters specify
+the character position and number of characters or the starting line and the number
+of lines that SelextTextAreaText will highlight.
+
+See Also: #TextAreaCursor, #TextAreaSelLen and #CreateTextArea
+EndRem
+Function SelectTextAreaText( textarea:TGadget,pos=0,length=TEXTAREA_ALL,units=TEXTAREA_CHARS )
+	textarea.SetSelection(pos,length,units)	
+End Function
+
+Rem
+bbdoc: Find the character position of a given line in a TextArea gadget.
+endrem
+Function TextAreaChar( textarea:TGadget,Line )
+	Return textarea.CharAt(Line)
+End Function
+
+Rem
+bbdoc: Find the line of a given character position in a TextArea gadget.
+endrem
+Function TextAreaLine( textarea:TGadget,index )
+	Return textarea.LineAt(index)
+End Function
+
+Rem
+bbdoc: Find the x-coordinate of a textarea character position, relative to the upper left corner of the gadget.
+about: The returned value may be greater than the width of the gadget (or even negative) if the specified character
+index is positioned outside the immediately visible area of a scrollable TextArea.
+EndRem
+Function TextAreaCharX( textarea:TGadget, char )
+	Return textarea.CharX(char)
+End Function
+
+Rem
+bbdoc: Find the y-coordinate of a textarea character position, relative to the upper left corner of the gadget.
+about: The returned value may be greater than the height of the gadget (or even negative) if the specified character
+index is positioned outside the immediately visible area of a scrollable TextArea.
+EndRem
+Function TextAreaCharY( textarea:TGadget, char )
+	Return textarea.CharY(char)
+End Function
+
+' gadget lists
+
+Rem
+bbdoc: Create a ComboBox gadget.
+about:
+A ComboBox gadget provides a dropdown list of items to the user.
+
+The ComboBox supports the following styles:
+
+[ @Style | @Meaning
+* COMBOBOX_EDITABLE | Allows the ComboBox to behave similar to a TextField, by allowing typed user input also.
+]
+
+And emits the following events:
+
+[ @{Event ID} | @Description
+* EVENT_GADGETACTION | The selection has been cleared, or the text has changed.
+]
+
+See Also: #AddGadgetItem, #ClearGadgetItems, #ModifyGadgetItem, #SelectGadgetItem,
+#RemoveGadgetItem, #SelectedGadgetItem and #SetGadgetIconStrip.
+EndRem
+Function CreateComboBox:TGadget(x,y,w,h,group:TGadget,style=0)
+	Return maxgui_driver.CreateGadget(GADGET_COMBOBOX,"",x,y,w,h,GetGroup(group),style)
+End Function
+
+Rem
+bbdoc: Create a ListBox gadget.
+about:
+A ListBox gadget displays a scrollable list of items and generates the following events:
+
+[ @{Event ID} | @Description
+* EVENT_GADGETSELECT | An item has been selected, or the selection has been cleared.
+* EVENT_GADGETACTION | An item has been double-clicked.
+* EVENT_GADGETMENU | The user has right-clicked somewhere in the listbox.
+]
+
+See Also: #AddGadgetItem, #ClearGadgetItems, #ModifyGadgetItem, #SelectGadgetItem,
+#RemoveGadgetItem, #SelectedGadgetItem, #SelectedGadgetItems and #SetGadgetIconStrip.
+EndRem
+Function CreateListBox:TGadget(x,y,w,h,group:TGadget,style=0)
+	Return maxgui_driver.CreateGadget(GADGET_LISTBOX,"",x,y,w,h,GetGroup(group),style)
+End Function
+
+Rem
+bbdoc: Create a Tabber gadget.
+about:
+A Tabber gadget shows a list of tabs above a client area, typically used for
+handling multiple documents/panels.
+
+[ @{Event ID} | @Description
+* EVENT_GADGETACTION | A new tab has been selected. Event data contains the tab index.
+* EVENT_GADGETMENU | A tab has been right-clicked. Event data contains the tab index.
+]
+
+Event extra for both events point to the #GadgetItemExtra object set for the corresponding tab item index in the latest call
+to #AddGadgetItem / #InsertGadgetItem or #ModifyGadgetItem.
+
+It is important to note also that, similar to #SelectedGadgetItem, either event may be emitted with the event
+data set to '-1'. This either means that somehow the user has deselected a tab, or that the user
+has right-clicked on an area of the tabber which doesn't represent a particular tab item index. As
+such, your MaxGUI applications should check the value before proceeding to use it with any of the
+standard #GadgetItemText, #GadgetItemExtra etc. commands.
+
+See Also: #AddGadgetItem, #ClearGadgetItems, #ModifyGadgetItem, #SelectGadgetItem,
+#RemoveGadgetItem, #SelectedGadgetItem and #SetGadgetIconStrip.
+EndRem
+Function CreateTabber:TGadget(x,y,w,h,group:TGadget,style=0)
+	Return maxgui_driver.CreateGadget(GADGET_TABBER,"",x,y,w,h,GetGroup(group),style)
+End Function
+
+Rem
+bbdoc: Remove all items added to a list based gadget.
+about:
+See Also: #CreateComboBox, #CreateListBox, #CreateToolbar and #CreateTabber
+EndRem
+Function ClearGadgetItems(gadget:TGadget)
+	gadget.Clear()
+End Function
+
+Rem
+bbdoc: Add an item to a list based gadget.
+about:
+An item can be added to the ComboBox, ListBox, Tabber and Toolbar list based gadgets.
+
+Its @text parameter is used as its label.
+
+The @flags parameter can be a combination of the following values:
+
+[ @Flag | @Meaning
+* GADGETITEM_NORMAL | A plain gadget item.
+* GADGETITEM_DEFAULT | The item defaults to a selected state.
+* GADGETITEM_TOGGLE | The item alternates between selected states when pressed.
+* GADGETITEM_LOCALIZED | The item text and tooltip are localization strings.
+]
+
+The @tip$ parameter attaches an optional tooltip to the item.
+
+The optional @icon parameter specifies an icon from the gadget's IconStrip (see #SetGadgetIconStrip).
+
+The @extra parameter is supplied in the EventExtra field of any Event generated by the Item.
+
+See Also: #InsertGadgetItem, #CreateComboBox, #CreateListBox, #CreateTabber, #CreateToolbar and #SetGadgetIconStrip.
+EndRem
+Function AddGadgetItem(gadget:TGadget,Text$,flags=0,icon=-1,tip$="",extra:Object=Null)
+	gadget.InsertItem(gadget.ItemCount(),Text,tip,icon,extra,flags)
+End Function
+
+Rem
+bbdoc: Inserts an item in a list based gadget at the specified index.
+about:
+An item can be inserted in a ComboBox, ListBox, Tabber and Toolbar list based gadgets.
+
+See #AddGadgetItem for a description of the parameters.
+
+See Also: #CreateComboBox, #CreateListBox, #CreateTabber and #CreateToolbar
+EndRem
+Function InsertGadgetItem(gadget:TGadget,index,Text$,flags=0,icon=-1,tip$="",extra:Object=Null)
+	gadget.InsertItem(index,Text,tip,icon,extra,flags)
+End Function
+
+Rem
+bbdoc: Modify the properties of a gadget-item.
+about:
+See #AddGadgetItem for a description of the parameters.
+
+See Also: #CreateComboBox, #CreateListBox, #CreateTabber and #CreateToolbar
+EndRem
+Function ModifyGadgetItem( gadget:TGadget,index,Text$,flags=0,icon=-1,tip$="",extra:Object=Null )
+	gadget.SetItem(index,Text,tip,icon,extra,flags)
+End Function
+
+Rem
+bbdoc: Remove a gadget-item from a list based gadget.
+about:
+See Also: #CreateComboBox, #CreateListBox, #CreateTabber and #CreateToolbar
+EndRem
+Function RemoveGadgetItem( gadget:TGadget,index )
+	gadget.RemoveItem index
+End Function
+
+Rem
+bbdoc: Enable a particular item in a list based gadget.
+about: Typically, this can only be used on toolbars.
+See Also: #CreateToolbar
+EndRem
+Function EnableGadgetItem( gadget:TGadget,index )
+	Local state=gadget.ItemState(index)&~STATE_DISABLED
+	gadget.SetItemState(index,state)
+End Function
+
+Rem
+bbdoc: Disable a particular item in a list based gadget.
+about: Typically, this can only be used on toolbars.
+See Also: #CreateToolbar
+EndRem
+Function DisableGadgetItem( gadget:TGadget,index )
+	Local state=gadget.ItemState(index)|STATE_DISABLED
+	gadget.SetItemState(index,state)
+End Function
+
+Rem
+bbdoc: Select an item in a list based gadget.
+about:
+See Also: #DeselectGadgetItem, #ToggleGadgetItem, #CreateComboBox, #CreateListBox, #CreateToolbar and #CreateTabber
+EndRem
+Function SelectGadgetItem(gadget:TGadget,index)
+	gadget.SelectItem(index,1)
+End Function
+
+Rem
+bbdoc: Deselect an item in a list based gadget.
+about:
+See Also: #SelectGadgetItem, #ToggleGadgetItem, #CreateComboBox, #CreateListBox, #CreateToolbar and #CreateTabber
+EndRem
+Function DeselectGadgetItem(gadget:TGadget,index)
+	gadget.SelectItem(index,0)
+End Function
+
+Rem
+bbdoc: Invert the selected state of an item in a list based gadget.
+about:
+See Also: #SelectGadgetItem, #DeselectGadgetItem and #CreateToolbar
+EndRem
+Function ToggleGadgetItem(gadget:TGadget,index)
+	gadget.SelectItem(index,2)
+End Function
+
+
+Rem
+bbdoc: Get the index of the first selected item in a list based gadget.
+about:
+SelectedGadgetItem will return -1 if the list based gadget has no selected items.
+
+See Also: #CreateComboBox, #CreateListBox and #CreateTabber
+EndRem
+Function SelectedGadgetItem(gadget:TGadget)
+	Return gadget.SelectedItem()
+End Function
+
+Rem
+bbdoc: Returns an integer array of the selected item indexes in a list based gadget.
+about:
+See Also: #CreateComboBox, #CreateListBox and #CreateTabber
+EndRem
+Function SelectedGadgetItems[](gadget:TGadget)
+	Return gadget.SelectedItems()
+End Function
+
+Rem
+bbdoc: Get the number of items in a list based gadget.
+about:
+See Also: #CreateComboBox, #CreateListBox, #CreateTabber and #CreateToolbar
+EndRem
+Function CountGadgetItems( gadget:TGadget )
+	Return gadget.ItemCount()
+End Function
+
+Rem
+bbdoc: Get the text of a given item in a list based gadget.
+about:
+See Also: #CreateComboBox, #CreateListBox, #CreateToolbar and #CreateTabber
+EndRem
+Function GadgetItemText$( gadget:TGadget,index )
+	Return gadget.ItemText(index)
+End Function
+
+Rem
+bbdoc: Get the tooltip of a given item in a list based gadget.
+about:
+See Also: #CreateComboBox, #CreateListBox, #CreateToolbar and #CreateTabber
+EndRem
+Function GadgetItemTooltip$( gadget:TGadget,index )
+	Return gadget.ItemTip(index)
+End Function
+
+Rem
+bbdoc: Get the icon of a given item in a list based gadget.
+about:
+See Also: #CreateComboBox, #CreateListBox, #CreateToolbar and #CreateTabber
+EndRem
+Function GadgetItemIcon( gadget:TGadget,index )
+	Return gadget.ItemIcon(index)
+End Function
+
+Rem
+bbdoc: Get the extra data of a given item in a list based gadget.
+about:
+See Also: #CreateComboBox, #CreateListBox, #CreateToolbar and #CreateTabber
+EndRem
+Function GadgetItemExtra:Object( gadget:TGadget,index )
+	Return gadget.ItemExtra(index)
+End Function
+
+Rem
+bbdoc: Get the flags parameter of a given item in a list based gadget.
+about:
+See Also: #AddGadgetItem
+EndRem
+Function GadgetItemFlags( gadget:TGadget,index )
+	Return gadget.ItemFlags(index)
+End Function
+
+
+
+' toolbar
+
+Rem
+bbdoc: Creates a window toolbar.
+about:
+A Toolbar is created from an iconstrip - an image that contains a row of equally shaped icons.
+Any images in the row left blank are treated as Toolbar separators.
+
+Toolbars are positioned along the top of the @window and either the client-area and/or window frame will be
+resized so that the client area of the window will begin just below the toolbar.
+
+At present, MaxGUI windows only support one toolbar at a time.
+
+A Toolbar generates the following events:
+
+[ @{Event ID} | @Description
+* EVENT_GADGETACTION | A toolbar item has been selected/clicked. Event data contains the item index.
+]
+
+The @source parameter can be a previously loaded @TIconStrip, a #TPixmap or a URL to an image
+file which @CreateToolBar will attempt to load an icon-strip from automatically.
+
+The recommended icon size is 24x24 pixels which seems to work well on most platforms. Using a
+different icon size may result in the pixmaps being scaled before being set depending on the OS.
+
+The @x, @y, @w, @h parameters are all ignored and are simply there to make the CreateToolbar() system call
+consistent with the other @{CreateGadget()} calls.
+
+The toolbar can be alterted during runtime using the #ClearGadgetItems, #InsertGadgetItem, #ModifyGadgetItem etc.
+functions.  Use the GADGETICON_SEPARATOR constant as an item's icon if you want it to be a separator, or
+GADGETICON_BLANK if you would like a blank square icon instead.
+
+%{IMPORTANT: Toolbars should only be parented to window gadgets.  Parenting a toolbar to a panel is not
+officially supported - users are strongly advised to instead use push-buttons with pixmap icons set.  Debug builds
+will output a warning message to standard error if toolbars are parented otherwise.}
+
+See Also: #AddGadgetItem, #EnableGadgetItem, #DisableGadgetItem and #SetToolbarTips.
+EndRem
+Function CreateToolBar:TGadget(source:Object,x,y,w,h,window:TGadget,style=0)
+	Local flags:Int = 0
+	Local iconstrip:TIconStrip = TIconStrip(source)
+	?Debug
+	If window.Class() <> GADGET_WINDOW Then
+		DebugLog "WARNING: Toolbars should *only* be parented to window gadgets."
+	EndIf
+	?
+	Local toolbar:TGadget = maxgui_driver.CreateGadget(GADGET_TOOLBAR,"",x,y,w,h,window,style)
+	If toolbar
+		If Not iconstrip Then iconstrip = LoadIconStrip(source)
+		If (LocalizationMode()&LOCALIZATION_OVERRIDE) Then flags:|GADGETITEM_LOCALIZED
+		If iconstrip
+			toolbar.SetIconStrip iconstrip
+			For Local icon=0 Until iconstrip.count
+				AddGadgetItem toolbar,"",flags,icon
+			Next
+		EndIf
+	EndIf
+	Return toolbar
+End Function
+
+Rem
+bbdoc: Attach a list of tips to a Toolbar gadget.
+about: Simply provides a quick way to set the tooltips of a toolbar's items after them being added.
+See Also: #CreateToolbar
+EndRem
+Function SetToolBarTips( toolbar:TGadget,tips$[] )
+	Local Text$,icon,extra:Object,flags,index
+	For Local tip$ = EachIn tips
+		Text=GadgetItemText(toolbar,index)
+		icon=GadgetItemIcon(toolbar,index)
+		extra=GadgetItemExtra(toolbar,index)
+		flags=GadgetItemFlags(toolbar,index)
+		ModifyGadgetItem toolbar,index,Text,flags,icon,tip,extra
+		index:+1
+	Next
+End Function
+'index,text$,icon=-1,tip$,extra:Object=Null
+
+' treeview
+
+Rem
+bbdoc: Create a TreeView gadget.
+about:
+A TreeView provides a view of an expandable list of nodes populated with the
+#AddTreeViewNode command. TreeView nodes can themselves contain nodes providing
+a flexible method of displaying a hierachy of information.
+
+[ @{Event ID} | @Description
+* EVENT_GADGETSELECT | The user has selected a node.
+* EVENT_GADGETACTION | The user has double-clicked a node.
+* EVENT_GADGETOPEN | The user has expanded a node, revealing its children.
+* EVENT_GADGETCLOSE | The user has collapsed a node, hiding its children.
+* EVENT_GADGETMENU | The user has right-clicked somewhere in the TreeView.
+]
+
+Each event will have the containing TreeView gadget as the event source and the concerned
+node gadget in the EventExtra field of the #TEvent.
+
+See Also: #AddTreeViewNode, #InsertTreeViewNode, #ModifyTreeViewNode, #TreeViewRoot,
+#SelectedTreeViewNode and #CountTreeViewNodes, #SelectTreeViewNode, #ExpandTreeViewNode,
+#CollapseTreeViewNode and #FreeTreeViewNode.
+EndRem
+Function CreateTreeView:TGadget(x,y,w,h,group:TGadget,style=0)
+	Return maxgui_driver.CreateGadget(GADGET_TREEVIEW,"",x,y,w,h,GetGroup(group),style)
+End Function
+
+Rem
+bbdoc: Add a node to a TreeView gadget.
+about: The optional @extra parameter is for convenience and is equivalent to calling 
+#SetGadgetExtra immediately after the node is created.
+
+See Also: #CreateTreeView, #InsertTreeViewNode
+EndRem
+Function AddTreeViewNode:TGadget( Text$,node:TGadget,icon=-1,extra:Object=Null )
+	Local tmpNode:TGadget = node.InsertNode(-1,Text,icon)
+	SetGadgetExtra tmpNode, extra
+	Return tmpNode
+End Function
+
+Rem
+bbdoc: Insert a node at a given index in a TreeView gadget.
+about: The optional @extra parameter is for convenience and is equivalent to calling 
+#SetGadgetExtra immediately after the node is created.
+
+See Also: #CreateTreeView, #AddTreeViewNode
+EndRem
+Function InsertTreeViewNode:TGadget( index,Text$,node:TGadget,icon=-1,extra:Object=Null )
+	Local tmpNode:TGadget = node.InsertNode(index,Text,icon)
+	SetGadgetExtra tmpNode, extra
+	Return tmpNode
+End Function
+
+Rem
+bbdoc: Modify a node.
+about:
+See Also: #CreateTreeView
+EndRem
+Function ModifyTreeViewNode( node:TGadget,Text$,icon=-1 )
+	node.ModifyNode Text,icon
+End Function
+
+Rem
+bbdoc: Frees all the nodes of a TreeView.
+about:
+See Also: #CreateTreeView
+EndRem
+Function ClearTreeView( treeview:TGadget )
+	For Local tmpNode:TGadget=EachIn treeview.RootNode().kids.Copy()
+		FreeGadget(tmpNode)
+	Next
+End Function
+
+Rem
+bbdoc: Get the root node of a TreeView gadget.
+about: This is required to parent the first nodes of a blank treeview to.
+
+A treeview's root node can also be used to deselect any currently selected
+nodes (see #SelectTreeViewNode for more information).
+
+See Also: #CreateTreeView
+EndRem
+Function TreeViewRoot:TGadget( treeview:TGadget )
+	Return treeview.RootNode()
+End Function
+
+Rem
+bbdoc: Get the node currently selected in a TreeView gadget.
+about: Will return #Null if there aren't any nodes currently selected.
+
+See Also: #CreateTreeView, #SelectTreeViewNode
+EndRem
+Function SelectedTreeViewNode:TGadget( treeview:TGadget )
+	Return treeview.SelectedNode()
+End Function
+
+Rem
+bbdoc: Get the number of children of a Node gadget.
+about:
+See Also: #CreateTreeView
+EndRem
+Function CountTreeViewNodes( node:TGadget )
+	Return node.CountKids()
+End Function
+
+Rem
+bbdoc: Selects/highlights a treeview node.
+about: It is possible to deselect a selection by selecting a treeview's root node.
+For example:
+
+{{
+SelectTreeViewNode( TreeViewRoot( myTree ) )
+}}
+
+See Also: #CreateTreeView, #SelectedTreeViewNode
+EndRem
+Function SelectTreeViewNode( node:TGadget )
+	node.Activate ACTIVATE_SELECT
+End Function
+
+Rem
+bbdoc: Expands a treeview node in a TreeView gadget.
+about:
+See Also: #CreateTreeView, #CollapseTreeViewNode
+EndRem
+Function ExpandTreeViewNode( node:TGadget )
+	node.Activate ACTIVATE_EXPAND
+End Function
+
+Rem
+bbdoc: Collapses a treeview node in a TreeView gadget.
+about:
+See Also: #CreateTreeView, #ExpandTreeViewNode
+EndRem
+Function CollapseTreeViewNode( node:TGadget )
+	node.Activate ACTIVATE_COLLAPSE
+End Function
+
+Rem
+bbdoc: Removes a treeview node from a TreeView gadget.
+about: This function has been superseded by #FreeGadget, but is available for backwards compatability.
+
+See Also: #CreateTreeView
+EndRem
+Function FreeTreeViewNode( node:TGadget )
+	node.CleanUp
+End Function
+
+' htmlview
+
+Rem
+bbdoc: Create an HTMLView gadget.
+about:
+The HTMLView is a complete web browser object inside a MaxGUI gadget. The HTML
+page displayed is controlled with the #HTMLViewGo command or from the user navigating
+from within the currently viewed page.
+
+#CreateHTMLView supports the following styles:
+
+[ @Style | @Meaning
+* HTMLVIEW_NOCONTEXTMENU | The webpage's default context menu is disabled.
+* HTMLVIEW_NONAVIGATE | User navigation is disabled and EVENT_GADGETACTION is generated instead.
+]
+
+[ @{Event ID} | @Description
+* EVENT_GADGETDONE | Generated when a webpage has finished loading or a page anchor has been scrolled to.
+* EVENT_GADGETACTION | Generated when a user clicks a link. Event Text contains the requested URL.
+]
+
+%{Note: EVENT_GADGETACTION requires the HTMLVIEW_NONAVIGATE style flag.}
+
+See Also: #HtmlViewGo, #HtmlViewBack, #HtmlViewForward, #HtmlViewStatus and #HtmlViewCurrentURL.
+EndRem
+Function CreateHTMLView:TGadget(x,y,w,h,group:TGadget,style=0)
+	Return maxgui_driver.CreateGadget(GADGET_HTMLVIEW,"",x,y,w,h,GetGroup(group),style)
+End Function
+
+Rem
+bbdoc: Direct the HTMLView gadget to a new URL.
+about:
+See Also: #CreateHTMLView
+EndRem
+Function HtmlViewGo( view:TGadget,url$ )
+	view.SetText url
+End Function
+
+Rem
+bbdoc: Go back a page in an HTMLView gadget.
+about:
+See Also: #CreateHTMLView
+EndRem
+Function HtmlViewBack( view:TGadget )
+	view.Activate ACTIVATE_BACK
+End Function
+
+Rem
+bbdoc: Go forward a page in an HTMLView gadget.
+about:
+See Also: #CreateHTMLView
+EndRem
+Function HtmlViewForward( view:TGadget )
+	view.Activate ACTIVATE_FORWARD
+End Function
+
+Rem
+bbdoc: Get the status of an HTMLView gadget.
+about:
+See Also: #CreateHTMLView
+EndRem
+Function HtmlViewStatus( view:TGadget )
+	Return view.State()
+End Function
+
+Rem
+bbdoc: Get the current URL of an HTMLView gadget.
+about:
+See Also: #CreateHTMLView
+EndRem
+Function HtmlViewCurrentURL$( view:TGadget )
+	Return view.GetText()
+End Function
+
+Rem
+bbdoc: Run a script in an HTMLView gadget.
+about:
+See Also: #CreateHTMLView
+EndRem
+Function HtmlViewRun$( view:TGadget,script$ )
+	Return view.Run(script)
+End Function
+
+' label
+
+Rem
+bbdoc: Create a Label gadget.
+about:
+A Label gadget is used to place static text or frames in a MaxGUI user interface. They do not
+generate any events.
+
+Labels support these optional styles:
+
+[ @Style | @Meaning
+* LABEL_FRAME | The label has a simple border.
+* LABEL_SUNKENFRAME | The label has a sunken border.
+* LABEL_SEPARATOR | The label is an etched box with no text useful for drawing separators.
+* LABEL_LEFT | The label's text is left-aligned. This is the default.
+* LABEL_CENTER | The label's text is center-aligned.
+* LABEL_RIGHT | The label's text is right-aligned.
+]
+
+See Also: #SetGadgetText, #SetGadgetTextColor, #SetGadgetFont and #SetGadgetColor.
+EndRem
+Function CreateLabel:TGadget( name$,x,y,w,h,group:TGadget,style=LABEL_LEFT )
+	Return maxgui_driver.CreateGadget(GADGET_LABEL,name,x,y,w,h,GetGroup(group),style)
+End Function
+
+' slider
+
+Rem
+bbdoc: Create a Slider gadget.
+about:
+A Slider gadget supports the following styles:
+
+[ @Style | @Meaning
+* SLIDER_HORIZONTAL | The slider is moved left and right.
+* SLIDER_VERTICAL | The  slider is moved up and down.
+* SLIDER_SCROLLBAR | The slider uses a proportional size knob.
+* SLIDER_TRACKBAR | The slider uses a fixed size knob.
+* SLIDER_STEPPER | The slider has no knob, just arrow buttons.
+]
+
+A slider only emits one type of event:
+
+[ @{Event ID} | @Description
+* EVENT_GADGETACTION | The user has changed the slider's value. Event Data contains the SliderValue.
+]
+
+See Also: #SetSliderRange, #SetSliderValue and #SliderValue
+EndRem
+Function CreateSlider:TGadget( x,y,w,h,group:TGadget,style=0 )
+	Return maxgui_driver.CreateGadget(GADGET_SLIDER,"",x,y,w,h,GetGroup(group),style)
+End Function
+
+Rem
+bbdoc: Set the range of a Slider gadget.
+about: For the default SLIDER_SCROLLBAR style the range0,range1 parameters are treated
+as a visible / total ratio which dictates both the size of the knob and it's
+maximum value. The default value is 1,10 which displays a Slider with a knob
+that occupies 1/10th the area and with a #SliderValue range of 0..9.
+
+For the SLIDER_TRACKBAR and SLIDER_STEPPER styles the range0,range1 parameters
+are treated as the minimum and maximum #SliderValue range inclusive.
+
+See Also: #CreateSlider, #SliderValue and #SetSliderValue
+EndRem
+Function SetSliderRange( slider:TGadget,range0,range1 )
+	slider.SetRange(range0,range1)
+End Function
+
+Rem
+bbdoc: Set the position of a Slider gadget.
+about:
+See Also: #CreateSlider, #SetSliderRange and #SliderValue
+EndRem
+Function SetSliderValue( slider:TGadget,value )
+	slider.SetProp value
+End Function
+
+Rem
+bbdoc: Get the position of a Slider gadget.
+about:
+See Also: #CreateSlider, #SetSliderRange and #SetSliderValue
+EndRem
+Function SliderValue( slider:TGadget )
+	Return slider.GetProp()
+End Function
+
+' progress
+
+Rem
+bbdoc: Create a Progress Bar gadget.
+about: Similar to Labels, Progress Bar gadgets do not generate any events themselves.
+See Also: #UpdateProgBar
+EndRem
+Function CreateProgBar:TGadget( x,y,w,h,group:TGadget,style=0 )
+	Return maxgui_driver.CreateGadget(GADGET_PROGBAR,"",x,y,w,h,GetGroup(group),style)
+End Function
+
+Rem
+bbdoc: Update the display of a ProgressBar gadget.
+about:
+See Also: #CreateProgBar
+EndRem
+Function UpdateProgBar( progbar:TGadget,value# )
+	progbar.SetValue value
+End Function
+
+Rem
+bbdoc: Creates an icon strip from an image file.
+about:
+An icon strip is a series of small images that can be attached to item-based gadgets.
+
+Icons must be square, and arranged in a single horizontal strip across the source image.
+
+The number of icons in an iconstrip is determined by dividing the image width by its height. For example,
+an iconstrip 64 wide by 8 high is assumed to contain 64/8=8 icons.
+
+Once an icon strip has been loaded, it can be attached to item-based gadgets using #SetGadgetIconStrip.
+
+See Also: #SetGadgetIconStrip and #PixmapFromIconStrip
+EndRem
+Function LoadIconStrip:TIconStrip( source:Object )
+	Return maxgui_driver.LoadIconStrip(source)
+End Function
+
+Rem
+bbdoc: Attaches an icon strip to an item-based gadget.
+about: Once attached, icons can be specified when items are added or modified with the #AddGadgetItem,
+#InsertGadgetItem and #ModifyGadgetItem commands.
+
+This command may only be used with the @ComboBox, @ListBox, @Tabber and @TreeNode gadgets.
+
+%{Note: It is highly recommended that icon-strips are set before any items are added to a gadget.}
+
+See Also: #LoadIconStrip
+EndRem
+Function SetGadgetIconStrip( gadget:TGadget,iconstrip:TIconStrip )
+	gadget.SetIconStrip(iconstrip)
+End Function
+
+Rem
+bbdoc: Returns a pixmap containing either a copy of the original icon-strip or just the specified icon.
+about: @iconstrip: The icon-strip to return a pixmap from.
+
+@index: The index (base 0) of the icon to extract. If this is negative, a %copy of the
+original pixmap used to create the iconstrip is returned.
+
+This function will return #Null if no iconstrip is passed, or if the icon index is invalid.
+
+See Also: #LoadIconStrip
+EndRem
+Function PixmapFromIconStrip:TPixmap( iconstrip:TIconStrip, index = -1 )
+	If iconstrip Then Return iconstrip.ExtractIconPixmap(index)
+End Function
+
+
+Rem
+bbdoc: Create a Canvas gadget.
+about:
+A Canvas provides a #Graphics interface for realtime drawing purposes.
+
+Once a Canvas is created, the #CanvasGraphics() Function can be used with the
+#SetGraphics command to direct #Max2D drawing commands to be
+drawn directly on the Canvas.
+
+An EVENT_GADGETPAINT event is generated whenever the gadget must be redrawn by either
+the system (for instance when it is first shown) or due to the #RedrawGadget command.
+
+An EVENT_GADGETPAINT handler should always call #SetGraphics
+with the canvas's Max2D graphics context to ensure the viewport and similar
+properties are in their correct state.
+
+When a Canvas is active using either the #ActivateGadget command or clicking
+on the Canvas when the application is running, the following events will also
+be sent from the Canvas:
+
+[ @{Event ID} | @Description
+* EVENT_MOUSEDOWN | Mouse button pressed. Event data contains mouse button code.
+* EVENT_MOUSEUP | Mouse button released. Event data contains mouse button code.
+* EVENT_MOUSEMOVE | Mouse moved. Event x and y contain mouse coordinates.
+* EVENT_MOUSEWHEEL | Mouse wheel spun. Event data contains delta clicks.
+* EVENT_MOUSEENTER | Mouse entered gadget area.
+* EVENT_MOUSELEAVE | Mouse left gadget area.
+* EVENT_KEYDOWN | Key pressed. Event data contains keycode.
+* EVENT_KEYUP | Key released. Event data contains keycode.
+* EVENT_KEYCHAR | Key character. Event data contains unicode value.
+]
+
+See Also: #ActivateGadget, #RedrawGadget, #CanvasGraphics
+EndRem
+Function CreateCanvas:TGadget( x,y,w,h,group:TGadget,style=0 )
+	Local t:TGadget=maxgui_driver.CreateGadget(GADGET_CANVAS,"",x,y,w,h,GetGroup(group),style)
+	t.AttachGraphics DefaultGraphicsFlags()	'gfxFlags
+	Return t
+End Function
+
+Rem
+bbdoc: Retrieve a Canvas gadget's Graphics context.
+about: The #RedrawGadget example shows an alternative method for drawing to Canvas
+gadgets utilizing the EVENT_GADGETPAINT event.
+
+See Also: #CreateCanvas
+EndRem
+Function CanvasGraphics:TGraphics( gadget:TGadget )
+	Return gadget.CanvasGraphics()
+End Function
+
+Rem
+bbdoc: Return internal gadget handle.
+about: #QueryGadget retrieves system handles for use with API specific functions.
+
+[ @Constant | @{Return Value}
+* QUERY_HWND | A Windows API HWND handle.
+* QUERY_HWND_CLIENT | A Windows API HWND handle representing a gadget's client area.
+* QUERY_NSVIEW | A Cocoa NSView handle.
+* QUERY_NSVIEW_CLIENT | A Cocoa NSView representing a gadget's client area.
+* QUERY_FLWIDGET | An FL_WIDGET handle.
+* QUERY_FLWIDGET_CLIENT | An FL_WIDGET handle representing a gadget's client area.
+]
+EndRem
+Function QueryGadget( gadget:TGadget,queryid )
+	Return gadget.Query(queryid)
+End Function
+
+Private
+
+Function GetGroup:TGadget( gadget:TGadget )
+	Local tmpProxy:TProxyGadget = TProxyGadget(gadget)
+	If tmpProxy Then Return GetGroup(tmpProxy.proxy)
+	Return gadget
+EndFunction

+ 174 - 0
maxgui.mod/maxgui.h

@@ -0,0 +1,174 @@
+#ifndef BB_BRL_MAXGUI_H
+#define BB_BRL_MAXGUI_H
+
+#include <brl.mod/system.mod/system.h>
+
+#define ACTIVATE_FOCUS 0
+#define ACTIVATE_CUT 1
+#define ACTIVATE_COPY 2
+#define ACTIVATE_PASTE 3
+#define ACTIVATE_MINIMIZE 4
+#define ACTIVATE_MAXIMIZE 5
+#define ACTIVATE_RESTORE 6
+#define ACTIVATE_SELECT 7
+#define ACTIVATE_EXPAND 8
+#define ACTIVATE_COLLAPSE 9
+#define ACTIVATE_BACK 10
+#define ACTIVATE_FORWARD 11
+#define ACTIVATE_PRINT 12
+#define ACTIVATE_REDRAW 13
+
+#define GADGET_DESKTOP 0
+#define GADGET_WINDOW 1
+#define GADGET_BUTTON 2
+#define GADGET_PANEL 3
+#define GADGET_TEXTFIELD 4
+#define GADGET_TEXTAREA 5
+#define GADGET_COMBOBOX 6
+#define GADGET_LISTBOX 7
+#define GADGET_TOOLBAR 8
+#define GADGET_TABBER 9
+#define GADGET_TREEVIEW 10
+#define GADGET_HTMLVIEW 11
+#define GADGET_LABEL 12
+#define GADGET_SLIDER 13
+#define GADGET_PROGBAR 14
+#define GADGET_MENUITEM 15
+#define GADGET_NODE 16
+#define GADGET_CANVAS 17
+#define GADGET_TIMER 18
+
+#define GUICOLOR_WINDOWBG 0
+#define GUICOLOR_GADGETBG 1
+#define GUICOLOR_GADGETFG 2
+#define GUICOLOR_SELECTIONBG 3
+#define GUICOLOR_LINKFG 4
+
+#define FONT_NORMAL 0
+#define FONT_BOLD 1
+#define FONT_ITALIC 2
+#define FONT_UNDERLINE 4
+#define FONT_STRIKETHROUGH 8
+
+#define CHECK_CLEARED 0
+#define CHECK_SELECTED 1
+#define CHECK_INDETERMINATE -1
+
+#define STATE_MINIMIZED 1
+#define STATE_MAXIMIZED 2
+#define STATE_DISABLED 4
+#define STATE_HIDDEN 8
+#define STATE_SELECTED 16
+#define STATE_ACTIVE 32
+#define STATE_INDETERMINATE 80
+
+#define GADGETICON_SEPARATOR -2
+#define GADGETICON_BLANK -1
+
+#define GADGETITEM_NONE -1
+#define GADGETITEM_NORMAL 0
+#define GADGETITEM_DEFAULT 1
+#define GADGETITEM_TOGGLE 2
+#define GADGETITEM_LOCALIZED 4
+
+#define WINDOW_TITLEBAR 1
+#define WINDOW_RESIZABLE 2
+#define WINDOW_MENU 4
+#define WINDOW_STATUS 8
+#define WINDOW_TOOL 16
+#define WINDOW_CLIENTCOORDS 32
+#define WINDOW_HIDDEN 64
+#define WINDOW_ACCEPTFILES 128
+#define WINDOW_CHILD 256
+#define WINDOW_CENTER 512
+
+#define LABEL_LEFT 0
+#define LABEL_FRAME 1
+#define LABEL_SUNKENFRAME 2
+#define LABEL_SEPARATOR 3
+#define LABEL_RIGHT 8
+#define LABEL_CENTER 16
+
+#define BUTTON_CHECKBOX 2
+#define BUTTON_RADIO 3
+#define BUTTON_OK 4
+#define BUTTON_CANCEL 5
+#define BUTTON_PUSH 8
+
+#define PANEL_SUNKEN 1
+#define PANEL_RAISED 2
+#define PANEL_GROUP 3
+#define PANEL_BORDER PANEL_SUNKEN
+
+#define PANEL_ACTIVE 4
+#define PANEL_CANVAS 8
+
+#define TEXTAREA_ALL -1
+
+#define TEXTAREA_CHARS 1
+#define TEXTAREA_LINES 2
+
+#define TEXTAREA_WORDWRAP 1
+#define TEXTAREA_READONLY 2
+
+#define TEXTFIELD_PASSWORD 1
+
+#define TEXTFORMAT_BOLD 1
+#define TEXTFORMAT_ITALIC 2
+#define TEXTFORMAT_UNDERLINE 4
+#define TEXTFORMAT_STRIKETHROUGH 8
+
+#define SLIDER_HORIZONTAL 1
+#define SLIDER_VERTICAL 2
+#define SLIDER_SCROLLBAR 0
+#define SLIDER_TRACKBAR 4
+#define SLIDER_STEPPER 8
+#define SLIDER_DIAL 12
+
+#define LISTBOX_MULTISELECT 1
+
+#define COMBOBOX_EDITABLE 1
+
+#define TREEVIEW_DRAGNDROP 1
+
+#define HTMLVIEW_NOCONTEXTMENU 1
+#define HTMLVIEW_NONAVIGATE 2
+
+#define SENSITIZE_MOUSE 1
+#define SENSITIZE_KEYS 2
+#define SENSITIZE_ALL 3
+
+#define PANELPIXMAP_TILE 0
+#define PANELPIXMAP_CENTER 1
+#define PANELPIXMAP_FIT 2
+#define PANELPIXMAP_STRETCH 3
+#define PANELPIXMAP_FIT2 4
+
+#define GADGETPIXMAP_BACKGROUND 0
+#define GADGETPIXMAP_ICON 8
+#define GADGETPIXMAP_NOTEXT 16
+
+#define POINTER_DEFAULT 0
+#define POINTER_ARROW 1 
+#define POINTER_IBEAM 2 
+#define POINTER_WAIT 3 
+#define POINTER_CROSS 4 
+#define POINTER_UPARROW 5 
+#define POINTER_SIZENWSE 6 
+#define POINTER_SIZENESW 7
+#define POINTER_SIZEWE 8 
+#define POINTER_SIZENS 9 
+#define POINTER_SIZEALL 10 
+#define POINTER_NO 11 
+#define POINTER_HAND 12 
+#define POINTER_APPSTARTING 13 
+#define POINTER_HELP 14 
+
+#define QUERY_HWND 1
+#define QUERY_HWND_CLIENT 2
+#define QUERY_NSVIEW 3
+#define QUERY_NSVIEW_CLIENT 4
+#define QUERY_FLWIDGET 5
+#define QUERY_FLWIDGET_CLIENT 6
+
+#endif