aboutsummaryrefslogtreecommitdiff
path: root/Src/Wasabi/api/wnd
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Wasabi/api/wnd')
-rw-r--r--Src/Wasabi/api/wnd/PaintCanvas.h3
-rw-r--r--Src/Wasabi/api/wnd/accessible.cpp16
-rw-r--r--Src/Wasabi/api/wnd/accessible.h622
-rw-r--r--Src/Wasabi/api/wnd/api_canvas.cpp2
-rw-r--r--Src/Wasabi/api/wnd/api_canvas.h163
-rw-r--r--Src/Wasabi/api/wnd/api_region.cpp2
-rw-r--r--Src/Wasabi/api/wnd/api_region.h200
-rw-r--r--Src/Wasabi/api/wnd/api_window.cpp3
-rw-r--r--Src/Wasabi/api/wnd/api_window.h1277
-rw-r--r--Src/Wasabi/api/wnd/api_wnd.cpp57
-rw-r--r--Src/Wasabi/api/wnd/api_wnd.h390
-rw-r--r--Src/Wasabi/api/wnd/basewnd.cpp5743
-rw-r--r--Src/Wasabi/api/wnd/basewnd.h944
-rw-r--r--Src/Wasabi/api/wnd/bitmap.cpp1584
-rw-r--r--Src/Wasabi/api/wnd/bitmap.h7
-rw-r--r--Src/Wasabi/api/wnd/blending.cpp56
-rw-r--r--Src/Wasabi/api/wnd/blending.h536
-rw-r--r--Src/Wasabi/api/wnd/bltcanvas.h5
-rw-r--r--Src/Wasabi/api/wnd/bucketitem.h76
-rw-r--r--Src/Wasabi/api/wnd/canvas.cpp3
-rw-r--r--Src/Wasabi/api/wnd/canvas.h5
-rw-r--r--Src/Wasabi/api/wnd/contextmenu.cpp170
-rw-r--r--Src/Wasabi/api/wnd/contextmenu.h42
-rw-r--r--Src/Wasabi/api/wnd/cursor.cpp48
-rw-r--r--Src/Wasabi/api/wnd/cursor.h62
-rw-r--r--Src/Wasabi/api/wnd/cwndtrack.h11
-rw-r--r--Src/Wasabi/api/wnd/deactivatemgr.cpp55
-rw-r--r--Src/Wasabi/api/wnd/deactivatemgr.h22
-rw-r--r--Src/Wasabi/api/wnd/di.cpp46
-rw-r--r--Src/Wasabi/api/wnd/drag.h75
-rw-r--r--Src/Wasabi/api/wnd/dragitem.h23
-rw-r--r--Src/Wasabi/api/wnd/dragitemi.cpp36
-rw-r--r--Src/Wasabi/api/wnd/dragitemi.h58
-rw-r--r--Src/Wasabi/api/wnd/fakedrag.h12
-rw-r--r--Src/Wasabi/api/wnd/findobjectcb.cpp8
-rw-r--r--Src/Wasabi/api/wnd/findobjectcb.h44
-rw-r--r--Src/Wasabi/api/wnd/fontdef.h15
-rw-r--r--Src/Wasabi/api/wnd/ifc_bitmap.h51
-rw-r--r--Src/Wasabi/api/wnd/keyboard.cpp570
-rw-r--r--Src/Wasabi/api/wnd/keyboard.h77
-rw-r--r--Src/Wasabi/api/wnd/minibrowser.cpp28
-rw-r--r--Src/Wasabi/api/wnd/minibrowser.h1
-rw-r--r--Src/Wasabi/api/wnd/notifmsg.h109
-rw-r--r--Src/Wasabi/api/wnd/paintcb.cpp52
-rw-r--r--Src/Wasabi/api/wnd/paintcb.h73
-rw-r--r--Src/Wasabi/api/wnd/paintset.cpp603
-rw-r--r--Src/Wasabi/api/wnd/paintset.h18
-rw-r--r--Src/Wasabi/api/wnd/paintsets.h18
-rw-r--r--Src/Wasabi/api/wnd/platform/osx/PaintCanvas.cpp51
-rw-r--r--Src/Wasabi/api/wnd/platform/osx/PaintCanvas.h45
-rw-r--r--Src/Wasabi/api/wnd/platform/osx/bltcanvas.h26
-rw-r--r--Src/Wasabi/api/wnd/platform/osx/canvas.h69
-rw-r--r--Src/Wasabi/api/wnd/platform/osx/osx_bitmap_cgimage.cpp220
-rw-r--r--Src/Wasabi/api/wnd/platform/osx/osx_bitmap_cgimage.h47
-rw-r--r--Src/Wasabi/api/wnd/platform/osx/osx_canvas_layer.cpp95
-rw-r--r--Src/Wasabi/api/wnd/platform/osx/osx_canvas_quartz.cpp275
-rw-r--r--Src/Wasabi/api/wnd/platform/osx/osx_region_hishape.cpp217
-rw-r--r--Src/Wasabi/api/wnd/platform/osx/region.h115
-rw-r--r--Src/Wasabi/api/wnd/platform/win32/bitmap.h81
-rw-r--r--Src/Wasabi/api/wnd/platform/win32/canvas.h1
-rw-r--r--Src/Wasabi/api/wnd/platform/win32/region.h135
-rw-r--r--Src/Wasabi/api/wnd/popexitcb.cpp8
-rw-r--r--Src/Wasabi/api/wnd/popexitcb.h40
-rw-r--r--Src/Wasabi/api/wnd/popexitchecker.cpp79
-rw-r--r--Src/Wasabi/api/wnd/popexitchecker.h39
-rw-r--r--Src/Wasabi/api/wnd/popup.cpp1720
-rw-r--r--Src/Wasabi/api/wnd/popup.h341
-rw-r--r--Src/Wasabi/api/wnd/region.cpp1
-rw-r--r--Src/Wasabi/api/wnd/region.h5
-rw-r--r--Src/Wasabi/api/wnd/resizable.h21
-rw-r--r--Src/Wasabi/api/wnd/rootwnd.cpp197
-rw-r--r--Src/Wasabi/api/wnd/rootwnd.h275
-rw-r--r--Src/Wasabi/api/wnd/textalign.h32
-rw-r--r--Src/Wasabi/api/wnd/usermsg.h23
-rw-r--r--Src/Wasabi/api/wnd/virtualwnd.cpp672
-rw-r--r--Src/Wasabi/api/wnd/virtualwnd.h84
-rw-r--r--Src/Wasabi/api/wnd/wndapi.cpp384
-rw-r--r--Src/Wasabi/api/wnd/wndapi.h101
-rw-r--r--Src/Wasabi/api/wnd/wndclass/SelItemList.cpp72
-rw-r--r--Src/Wasabi/api/wnd/wndclass/SelItemList.h31
-rw-r--r--Src/Wasabi/api/wnd/wndclass/abstractwndhold.cpp287
-rw-r--r--Src/Wasabi/api/wnd/wndclass/abstractwndhold.h267
-rw-r--r--Src/Wasabi/api/wnd/wndclass/appbarwnd.cpp1113
-rw-r--r--Src/Wasabi/api/wnd/wndclass/appbarwnd.h155
-rw-r--r--Src/Wasabi/api/wnd/wndclass/backbufferwnd.cpp86
-rw-r--r--Src/Wasabi/api/wnd/wndclass/backbufferwnd.h53
-rw-r--r--Src/Wasabi/api/wnd/wndclass/blankwnd.cpp24
-rw-r--r--Src/Wasabi/api/wnd/wndclass/blankwnd.h41
-rw-r--r--Src/Wasabi/api/wnd/wndclass/bufferpaintwnd.cpp113
-rw-r--r--Src/Wasabi/api/wnd/wndclass/bufferpaintwnd.h40
-rw-r--r--Src/Wasabi/api/wnd/wndclass/buttbar.cpp208
-rw-r--r--Src/Wasabi/api/wnd/wndclass/buttbar.h168
-rw-r--r--Src/Wasabi/api/wnd/wndclass/buttwnd.cpp761
-rw-r--r--Src/Wasabi/api/wnd/wndclass/buttwnd.h602
-rw-r--r--Src/Wasabi/api/wnd/wndclass/clickwnd.cpp319
-rw-r--r--Src/Wasabi/api/wnd/wndclass/clickwnd.h74
-rw-r--r--Src/Wasabi/api/wnd/wndclass/ddrawwnd.cpp219
-rw-r--r--Src/Wasabi/api/wnd/wndclass/ddrawwnd.h60
-rw-r--r--Src/Wasabi/api/wnd/wndclass/editwnd.cpp1001
-rw-r--r--Src/Wasabi/api/wnd/wndclass/editwnd.h134
-rw-r--r--Src/Wasabi/api/wnd/wndclass/editwndstring.cpp17
-rw-r--r--Src/Wasabi/api/wnd/wndclass/editwndstring.h24
-rw-r--r--Src/Wasabi/api/wnd/wndclass/embeddedxui.cpp143
-rw-r--r--Src/Wasabi/api/wnd/wndclass/embeddedxui.h88
-rw-r--r--Src/Wasabi/api/wnd/wndclass/foreignwnd.cpp60
-rw-r--r--Src/Wasabi/api/wnd/wndclass/foreignwnd.h56
-rw-r--r--Src/Wasabi/api/wnd/wndclass/framewnd.cpp777
-rw-r--r--Src/Wasabi/api/wnd/wndclass/framewnd.h124
-rw-r--r--Src/Wasabi/api/wnd/wndclass/gradientwnd.cpp82
-rw-r--r--Src/Wasabi/api/wnd/wndclass/gradientwnd.h31
-rw-r--r--Src/Wasabi/api/wnd/wndclass/guiobjwnd.cpp476
-rw-r--r--Src/Wasabi/api/wnd/wndclass/guiobjwnd.h237
-rw-r--r--Src/Wasabi/api/wnd/wndclass/itemlistwnd.cpp286
-rw-r--r--Src/Wasabi/api/wnd/wndclass/itemlistwnd.h426
-rw-r--r--Src/Wasabi/api/wnd/wndclass/labelwnd.cpp203
-rw-r--r--Src/Wasabi/api/wnd/wndclass/labelwnd.h46
-rw-r--r--Src/Wasabi/api/wnd/wndclass/listwnd.cpp2151
-rw-r--r--Src/Wasabi/api/wnd/wndclass/listwnd.h459
-rw-r--r--Src/Wasabi/api/wnd/wndclass/oswnd.cpp32
-rw-r--r--Src/Wasabi/api/wnd/wndclass/oswnd.h19
-rw-r--r--Src/Wasabi/api/wnd/wndclass/oswndhost.cpp14
-rw-r--r--Src/Wasabi/api/wnd/wndclass/oswndhost.h53
-rw-r--r--Src/Wasabi/api/wnd/wndclass/qpaintwnd.cpp357
-rw-r--r--Src/Wasabi/api/wnd/wndclass/qpaintwnd.h154
-rw-r--r--Src/Wasabi/api/wnd/wndclass/rootwndholder.cpp113
-rw-r--r--Src/Wasabi/api/wnd/wndclass/rootwndholder.h41
-rw-r--r--Src/Wasabi/api/wnd/wndclass/scbkgwnd.cpp869
-rw-r--r--Src/Wasabi/api/wnd/wndclass/scbkgwnd.h463
-rw-r--r--Src/Wasabi/api/wnd/wndclass/scrollbar.cpp679
-rw-r--r--Src/Wasabi/api/wnd/wndclass/scrollbar.h423
-rw-r--r--Src/Wasabi/api/wnd/wndclass/sepwnd.cpp63
-rw-r--r--Src/Wasabi/api/wnd/wndclass/sepwnd.h27
-rw-r--r--Src/Wasabi/api/wnd/wndclass/slider.cpp705
-rw-r--r--Src/Wasabi/api/wnd/wndclass/slider.h451
-rw-r--r--Src/Wasabi/api/wnd/wndclass/status.cpp242
-rw-r--r--Src/Wasabi/api/wnd/wndclass/status.h178
-rw-r--r--Src/Wasabi/api/wnd/wndclass/svcwndhold.cpp53
-rw-r--r--Src/Wasabi/api/wnd/wndclass/svcwndhold.h51
-rw-r--r--Src/Wasabi/api/wnd/wndclass/tabsheet.cpp544
-rw-r--r--Src/Wasabi/api/wnd/wndclass/tabsheet.h268
-rw-r--r--Src/Wasabi/api/wnd/wndclass/tabsheetbar.cpp130
-rw-r--r--Src/Wasabi/api/wnd/wndclass/tabsheetbar.h39
-rw-r--r--Src/Wasabi/api/wnd/wndclass/textbar.cpp148
-rw-r--r--Src/Wasabi/api/wnd/wndclass/textbar.h219
-rw-r--r--Src/Wasabi/api/wnd/wndclass/tooltip.cpp47
-rw-r--r--Src/Wasabi/api/wnd/wndclass/tooltip.h18
-rw-r--r--Src/Wasabi/api/wnd/wndclass/treewnd.cpp1645
-rw-r--r--Src/Wasabi/api/wnd/wndclass/treewnd.h624
-rw-r--r--Src/Wasabi/api/wnd/wndclass/typesheet.cpp38
-rw-r--r--Src/Wasabi/api/wnd/wndclass/typesheet.h49
-rw-r--r--Src/Wasabi/api/wnd/wndclass/virtualhostwnd.cpp198
-rw-r--r--Src/Wasabi/api/wnd/wndclass/virtualhostwnd.h51
-rw-r--r--Src/Wasabi/api/wnd/wndclass/wndholder.cpp369
-rw-r--r--Src/Wasabi/api/wnd/wndclass/wndholder.h285
-rw-r--r--Src/Wasabi/api/wnd/wndevent.h5
-rw-r--r--Src/Wasabi/api/wnd/wndtrack.cpp945
-rw-r--r--Src/Wasabi/api/wnd/wndtrack.h104
157 files changed, 41647 insertions, 0 deletions
diff --git a/Src/Wasabi/api/wnd/PaintCanvas.h b/Src/Wasabi/api/wnd/PaintCanvas.h
new file mode 100644
index 00000000..165dcd23
--- /dev/null
+++ b/Src/Wasabi/api/wnd/PaintCanvas.h
@@ -0,0 +1,3 @@
+#ifdef __APPLE__
+#include <api/wnd/platform/osx/PaintCanvas.h>
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/accessible.cpp b/Src/Wasabi/api/wnd/accessible.cpp
new file mode 100644
index 00000000..2cefc41b
--- /dev/null
+++ b/Src/Wasabi/api/wnd/accessible.cpp
@@ -0,0 +1,16 @@
+#include "precomp.h"
+#include "accessible.h"
+
+#define CBCLASS AccessibleI
+START_DISPATCH;
+ CB(ACCESSIBLE_GETIACCESSIBLE, getIAccessible);
+ CB(ACCESSIBLE_GETOSHANDLE, getOSHandle);
+ VCB(ACCESSIBLE_RELEASE, release);
+ VCB(ACCESSIBLE_ADDREF, addRef);
+ CB(ACCESSIBLE_GETNUMREFS, getNumRefs);
+ VCB(ACCESSIBLE_ONGETFOCUS, onGetFocus);
+ VCB(ACCESSIBLE_ONSETNAME, onSetName);
+ CB(ACCESSIBLE_GETOSWND, getOSWnd);
+ VCB(ACCESSIBLE_ONSTATECHANGE, onStateChange);
+ CB(ACCESSIBLE_FLATTENCONTENT, flattenContent);
+END_DISPATCH;
diff --git a/Src/Wasabi/api/wnd/accessible.h b/Src/Wasabi/api/wnd/accessible.h
new file mode 100644
index 00000000..13e544bb
--- /dev/null
+++ b/Src/Wasabi/api/wnd/accessible.h
@@ -0,0 +1,622 @@
+#ifndef __ACCESSIBLE_H
+#define __ACCESSIBLE_H
+
+#include <bfc/common.h>
+
+// Message sent to the OS window in order to retrieve an accessibility interface
+#define WM_GETOBJECT 0x003D
+
+// undef some stuff we're gonna #define ourselves
+#ifdef OBJID_WINDOW
+#undef OBJID_WINDOW
+#endif
+#ifdef OBJID_SYSMENU
+#undef OBJID_SYSMENU
+#endif
+#ifdef OBJID_TITLEBAR
+#undef OBJID_TITLEBAR
+#endif
+#ifdef OBJID_MENU
+#undef OBJID_MENU
+#endif
+#ifdef OBJID_CLIENT
+#undef OBJID_CLIENT
+#endif
+#ifdef OBJID_VSCROLL
+#undef OBJID_VSCROLL
+#endif
+#ifdef OBJID_HSCROLL
+#undef OBJID_HSCROLL
+#endif
+#ifdef OBJID_SIZEGRIP
+#undef OBJID_SIZEGRIP
+#endif
+#ifdef OBJID_CARET
+#undef OBJID_CARET
+#endif
+#ifdef OBJID_CURSOR
+#undef OBJID_CURSOR
+#endif
+#ifdef OBJID_ALERT
+#undef OBJID_ALERT
+#endif
+#ifdef OBJID_SOUND
+#undef OBJID_SOUND
+#endif
+#ifdef STATE_SYSTEM_VALID
+#undef STATE_SYSTEM_VALID
+#endif // STATE_SYSTEM_VALID
+
+// Accessibility system object IDs
+#define OBJID_WINDOW 0x00000000
+#define OBJID_SYSMENU 0xFFFFFFFF
+#define OBJID_TITLEBAR 0xFFFFFFFE
+#define OBJID_MENU 0xFFFFFFFD
+#define OBJID_CLIENT 0xFFFFFFFC
+#define OBJID_VSCROLL 0xFFFFFFFB
+#define OBJID_HSCROLL 0xFFFFFFFA
+#define OBJID_SIZEGRIP 0xFFFFFFF9
+#define OBJID_CARET 0xFFFFFFF8
+#define OBJID_CURSOR 0xFFFFFFF7
+#define OBJID_ALERT 0xFFFFFFF6
+#define OBJID_SOUND 0xFFFFFFF5
+
+#if 0
+#define ROLE_SYSTEM_TITLEBAR 0x00000001
+#define ROLE_SYSTEM_MENUBAR 0x00000002
+#define ROLE_SYSTEM_SCROLLBAR 0x00000003
+#define ROLE_SYSTEM_GRIP 0x00000004
+#define ROLE_SYSTEM_SOUND 0x00000005
+#define ROLE_SYSTEM_CURSOR 0x00000006
+#define ROLE_SYSTEM_CARET 0x00000007
+#define ROLE_SYSTEM_ALERT 0x00000008
+#define ROLE_SYSTEM_WINDOW 0x00000009
+#define ROLE_SYSTEM_CLIENT 0x0000000A
+#define ROLE_SYSTEM_MENUPOPUP 0x0000000B
+#define ROLE_SYSTEM_MENUITEM 0x0000000C
+#define ROLE_SYSTEM_TOOLTIP 0x0000000D
+#define ROLE_SYSTEM_APPLICATION 0x0000000E
+#define ROLE_SYSTEM_DOCUMENT 0x0000000F
+#define ROLE_SYSTEM_PANE 0x00000010
+#define ROLE_SYSTEM_CHART 0x00000011
+#define ROLE_SYSTEM_DIALOG 0x00000012
+#define ROLE_SYSTEM_BORDER 0x00000013
+#define ROLE_SYSTEM_GROUPING 0x00000014
+#define ROLE_SYSTEM_SEPARATOR 0x00000015
+#define ROLE_SYSTEM_TOOLBAR 0x00000016
+#define ROLE_SYSTEM_STATUSBAR 0x00000017
+#define ROLE_SYSTEM_TABLE 0x00000018
+#define ROLE_SYSTEM_COLUMNHEADER 0x00000019
+#define ROLE_SYSTEM_ROWHEADER 0x0000001A
+#define ROLE_SYSTEM_COLUMN 0x0000001B
+#define ROLE_SYSTEM_ROW 0x0000001C
+#define ROLE_SYSTEM_CELL 0x0000001D
+#define ROLE_SYSTEM_LINK 0x0000001E
+#define ROLE_SYSTEM_HELPBALLOON 0x0000001F
+#define ROLE_SYSTEM_CHARACTER 0x00000020
+#define ROLE_SYSTEM_LIST 0x00000021
+#define ROLE_SYSTEM_LISTITEM 0x00000022
+#define ROLE_SYSTEM_OUTLINE 0x00000023
+#define ROLE_SYSTEM_OUTLINEITEM 0x00000024
+#define ROLE_SYSTEM_PAGETAB 0x00000025
+#define ROLE_SYSTEM_PROPERTYPAGE 0x00000026
+#define ROLE_SYSTEM_INDICATOR 0x00000027
+#define ROLE_SYSTEM_GRAPHIC 0x00000028
+#define ROLE_SYSTEM_STATICTEXT 0x00000029
+#define ROLE_SYSTEM_TEXT 0x0000002A // Editable, selectable, etc.
+#define ROLE_SYSTEM_PUSHBUTTON 0x0000002B
+#define ROLE_SYSTEM_CHECKBUTTON 0x0000002C
+#define ROLE_SYSTEM_RADIOBUTTON 0x0000002D
+#define ROLE_SYSTEM_COMBOBOX 0x0000002E
+#define ROLE_SYSTEM_DROPLIST 0x0000002F
+#define ROLE_SYSTEM_PROGRESSBAR 0x00000030
+#define ROLE_SYSTEM_DIAL 0x00000031
+#define ROLE_SYSTEM_HOTKEYFIELD 0x00000032
+#define ROLE_SYSTEM_SLIDER 0x00000033
+#define ROLE_SYSTEM_SPINBUTTON 0x00000034
+#define ROLE_SYSTEM_DIAGRAM 0x00000035
+#define ROLE_SYSTEM_ANIMATION 0x00000036
+#define ROLE_SYSTEM_EQUATION 0x00000037
+#define ROLE_SYSTEM_BUTTONDROPDOWN 0x00000038
+#define ROLE_SYSTEM_BUTTONMENU 0x00000039
+#define ROLE_SYSTEM_BUTTONDROPDOWNGRID 0x0000003A
+#define ROLE_SYSTEM_WHITESPACE 0x0000003B
+#define ROLE_SYSTEM_PAGETABLIST 0x0000003C
+#define ROLE_SYSTEM_CLOCK 0x0000003D
+#endif
+#define STATE_SYSTEM_UNAVAILABLE 0x00000001 // Disabled
+#define STATE_SYSTEM_SELECTED 0x00000002
+#define STATE_SYSTEM_FOCUSED 0x00000004
+#define STATE_SYSTEM_PRESSED 0x00000008
+#define STATE_SYSTEM_CHECKED 0x00000010
+#define STATE_SYSTEM_MIXED 0x00000020 // 3-state checkbox or toolbar button
+#define STATE_SYSTEM_READONLY 0x00000040
+#define STATE_SYSTEM_HOTTRACKED 0x00000080
+#define STATE_SYSTEM_DEFAULT 0x00000100
+#define STATE_SYSTEM_EXPANDED 0x00000200
+#define STATE_SYSTEM_COLLAPSED 0x00000400
+#define STATE_SYSTEM_BUSY 0x00000800
+#define STATE_SYSTEM_FLOATING 0x00001000 // Children "owned" not "contained" by parent
+#define STATE_SYSTEM_MARQUEED 0x00002000
+#define STATE_SYSTEM_ANIMATED 0x00004000
+#define STATE_SYSTEM_INVISIBLE 0x00008000
+#define STATE_SYSTEM_OFFSCREEN 0x00010000
+#define STATE_SYSTEM_SIZEABLE 0x00020000
+#define STATE_SYSTEM_MOVEABLE 0x00040000
+#define STATE_SYSTEM_SELFVOICING 0x00080000
+#define STATE_SYSTEM_FOCUSABLE 0x00100000
+#define STATE_SYSTEM_SELECTABLE 0x00200000
+#define STATE_SYSTEM_LINKED 0x00400000
+#define STATE_SYSTEM_TRAVERSED 0x00800000
+#define STATE_SYSTEM_MULTISELECTABLE 0x01000000 // Supports multiple selection
+#define STATE_SYSTEM_EXTSELECTABLE 0x02000000 // Supports extended selection
+#define STATE_SYSTEM_ALERT_LOW 0x04000000 // This information is of low priority
+#define STATE_SYSTEM_ALERT_MEDIUM 0x08000000 // This information is of medium priority
+#define STATE_SYSTEM_ALERT_HIGH 0x10000000 // This information is of high priority
+
+#define STATE_SYSTEM_VALID 0x1FFFFFFF
+
+/*
+ * Reserved IDs for system objects
+ */
+#define OBJID_WINDOW 0x00000000
+#define OBJID_SYSMENU 0xFFFFFFFF
+#define OBJID_TITLEBAR 0xFFFFFFFE
+#define OBJID_MENU 0xFFFFFFFD
+#define OBJID_CLIENT 0xFFFFFFFC
+#define OBJID_VSCROLL 0xFFFFFFFB
+#define OBJID_HSCROLL 0xFFFFFFFA
+#define OBJID_SIZEGRIP 0xFFFFFFF9
+#define OBJID_CARET 0xFFFFFFF8
+#define OBJID_CURSOR 0xFFFFFFF7
+#define OBJID_ALERT 0xFFFFFFF6
+#define OBJID_SOUND 0xFFFFFFF5
+
+/*
+ * EVENT DEFINITION
+ */
+#define EVENT_MIN 0x00000001
+#define EVENT_MAX 0x7FFFFFFF
+
+
+/*
+ * EVENT_SYSTEM_SOUND
+ * Sent when a sound is played. Currently nothing is generating this, we
+ * this event when a system sound (for menus, etc) is played. Apps
+ * generate this, if accessible, when a private sound is played. For
+ * example, if Mail plays a "New Mail" sound.
+ *
+ * System Sounds:
+ * (Generated by PlaySoundEvent in USER itself)
+ * hwnd is NULL
+ * idObject is OBJID_SOUND
+ * idChild is sound child ID if one
+ * App Sounds:
+ * (PlaySoundEvent won't generate notification; up to app)
+ * hwnd + idObject gets interface pointer to Sound object
+ * idChild identifies the sound in question
+ * are going to be cleaning up the SOUNDSENTRY feature in the control panel
+ * and will use this at that time. Applications implementing WinEvents
+ * are perfectly welcome to use it. Clients of IAccessible* will simply
+ * turn around and get back a non-visual object that describes the sound.
+ */
+#define EVENT_SYSTEM_SOUND 0x0001
+
+/*
+ * EVENT_SYSTEM_ALERT
+ * System Alerts:
+ * (Generated by MessageBox() calls for example)
+ * hwnd is hwndMessageBox
+ * idObject is OBJID_ALERT
+ * App Alerts:
+ * (Generated whenever)
+ * hwnd+idObject gets interface pointer to Alert
+ */
+#define EVENT_SYSTEM_ALERT 0x0002
+
+/*
+ * EVENT_SYSTEM_FOREGROUND
+ * Sent when the foreground (active) window changes, even if it is changing
+ * to another window in the same thread as the previous one.
+ * hwnd is hwndNewForeground
+ * idObject is OBJID_WINDOW
+ * idChild is INDEXID_OBJECT
+ */
+#define EVENT_SYSTEM_FOREGROUND 0x0003
+
+/*
+ * Menu
+ * hwnd is window (top level window or popup menu window)
+ * idObject is ID of control (OBJID_MENU, OBJID_SYSMENU, OBJID_SELF for popup)
+ * idChild is CHILDID_SELF
+ *
+ * EVENT_SYSTEM_MENUSTART
+ * EVENT_SYSTEM_MENUEND
+ * For MENUSTART, hwnd+idObject+idChild refers to the control with the menu bar,
+ * or the control bringing up the context menu.
+ *
+ * Sent when entering into and leaving from menu mode (system, app bar, and
+ * track popups).
+ */
+#define EVENT_SYSTEM_MENUSTART 0x0004
+#define EVENT_SYSTEM_MENUEND 0x0005
+
+/*
+ * EVENT_SYSTEM_MENUPOPUPSTART
+ * EVENT_SYSTEM_MENUPOPUPEND
+ * Sent when a menu popup comes up and just before it is taken down. Note
+ * that for a call to TrackPopupMenu(), a client will see EVENT_SYSTEM_MENUSTART
+ * followed almost immediately by EVENT_SYSTEM_MENUPOPUPSTART for the popup
+ * being shown.
+ *
+ * For MENUPOPUP, hwnd+idObject+idChild refers to the NEW popup coming up, not the
+ * parent item which is hierarchical. You can get the parent menu/popup by
+ * asking for the accParent object.
+ */
+#define EVENT_SYSTEM_MENUPOPUPSTART 0x0006
+#define EVENT_SYSTEM_MENUPOPUPEND 0x0007
+
+
+/*
+ * EVENT_SYSTEM_CAPTURESTART
+ * EVENT_SYSTEM_CAPTUREEND
+ * Sent when a window takes the capture and releases the capture.
+ */
+#define EVENT_SYSTEM_CAPTURESTART 0x0008
+#define EVENT_SYSTEM_CAPTUREEND 0x0009
+
+/*
+ * Move Size
+ * EVENT_SYSTEM_MOVESIZESTART
+ * EVENT_SYSTEM_MOVESIZEEND
+ * Sent when a window enters and leaves move-size dragging mode.
+ */
+#define EVENT_SYSTEM_MOVESIZESTART 0x000A
+#define EVENT_SYSTEM_MOVESIZEEND 0x000B
+
+/*
+ * Context Help
+ * EVENT_SYSTEM_CONTEXTHELPSTART
+ * EVENT_SYSTEM_CONTEXTHELPEND
+ * Sent when a window enters and leaves context sensitive help mode.
+ */
+#define EVENT_SYSTEM_CONTEXTHELPSTART 0x000C
+#define EVENT_SYSTEM_CONTEXTHELPEND 0x000D
+
+/*
+ * Drag & Drop
+ * EVENT_SYSTEM_DRAGDROPSTART
+ * EVENT_SYSTEM_DRAGDROPEND
+ * Send the START notification just before going into drag&drop loop. Send
+ * the END notification just after canceling out.
+ * Note that it is up to apps and OLE to generate this, since the system
+ * doesn't know. Like EVENT_SYSTEM_SOUND, it will be a while before this
+ * is prevalent.
+ */
+#define EVENT_SYSTEM_DRAGDROPSTART 0x000E
+#define EVENT_SYSTEM_DRAGDROPEND 0x000F
+
+/*
+ * Dialog
+ * Send the START notification right after the dialog is completely
+ * initialized and visible. Send the END right before the dialog
+ * is hidden and goes away.
+ * EVENT_SYSTEM_DIALOGSTART
+ * EVENT_SYSTEM_DIALOGEND
+ */
+#define EVENT_SYSTEM_DIALOGSTART 0x0010
+#define EVENT_SYSTEM_DIALOGEND 0x0011
+
+/*
+ * EVENT_SYSTEM_SCROLLING
+ * EVENT_SYSTEM_SCROLLINGSTART
+ * EVENT_SYSTEM_SCROLLINGEND
+ * Sent when beginning and ending the tracking of a scrollbar in a window,
+ * and also for scrollbar controls.
+ */
+#define EVENT_SYSTEM_SCROLLINGSTART 0x0012
+#define EVENT_SYSTEM_SCROLLINGEND 0x0013
+
+/*
+ * Alt-Tab Window
+ * Send the START notification right after the switch window is initialized
+ * and visible. Send the END right before it is hidden and goes away.
+ * EVENT_SYSTEM_SWITCHSTART
+ * EVENT_SYSTEM_SWITCHEND
+ */
+#define EVENT_SYSTEM_SWITCHSTART 0x0014
+#define EVENT_SYSTEM_SWITCHEND 0x0015
+
+/*
+ * EVENT_SYSTEM_MINIMIZESTART
+ * EVENT_SYSTEM_MINIMIZEEND
+ * Sent when a window minimizes and just before it restores.
+ */
+#define EVENT_SYSTEM_MINIMIZESTART 0x0016
+#define EVENT_SYSTEM_MINIMIZEEND 0x0017
+
+
+
+/*
+ * Object events
+ *
+ * The system AND apps generate these. The system generates these for
+ * real windows. Apps generate these for objects within their window which
+ * act like a separate control, e.g. an item in a list view.
+ *
+ * When the system generate them, dwParam2 is always WMOBJID_SELF. When
+ * apps generate them, apps put the has-meaning-to-the-app-only ID value
+ * in dwParam2.
+ * For all events, if you want detailed accessibility information, callers
+ * should
+ * * Call AccessibleObjectFromWindow() with the hwnd, idObject parameters
+ * of the event, and IID_IAccessible as the REFIID, to get back an
+ * IAccessible* to talk to
+ * * Initialize and fill in a VARIANT as VT_I4 with lVal the idChild
+ * parameter of the event.
+ * * If idChild isn't zero, call get_accChild() in the container to see
+ * if the child is an object in its own right. If so, you will get
+ * back an IDispatch* object for the child. You should release the
+ * parent, and call QueryInterface() on the child object to get its
+ * IAccessible*. Then you talk directly to the child. Otherwise,
+ * if get_accChild() returns you nothing, you should continue to
+ * use the child VARIANT. You will ask the container for the properties
+ * of the child identified by the VARIANT. In other words, the
+ * child in this case is accessible but not a full-blown object.
+ * Like a button on a titlebar which is 'small' and has no children.
+ */
+
+/*
+ * For all EVENT_OBJECT events,
+ * hwnd is the dude to Send the WM_GETOBJECT message to (unless NULL,
+ * see above for system things)
+ * idObject is the ID of the object that can resolve any queries a
+ * client might have. It's a way to deal with windowless controls,
+ * controls that are just drawn on the screen in some larger parent
+ * window (like SDM), or standard frame elements of a window.
+ * idChild is the piece inside of the object that is affected. This
+ * allows clients to access things that are too small to have full
+ * blown objects in their own right. Like the thumb of a scrollbar.
+ * The hwnd/idObject pair gets you to the container, the dude you
+ * probably want to talk to most of the time anyway. The idChild
+ * can then be passed into the acc properties to get the name/value
+ * of it as needed.
+ *
+ * Example #1:
+ * System propagating a listbox selection change
+ * EVENT_OBJECT_SELECTION
+ * hwnd == listbox hwnd
+ * idObject == OBJID_WINDOW
+ * idChild == new selected item, or CHILDID_SELF if
+ * nothing now selected within container.
+ * Word '97 propagating a listbox selection change
+ * hwnd == SDM window
+ * idObject == SDM ID to get at listbox 'control'
+ * idChild == new selected item, or CHILDID_SELF if
+ * nothing
+ *
+ * Example #2:
+ * System propagating a menu item selection on the menu bar
+ * EVENT_OBJECT_SELECTION
+ * hwnd == top level window
+ * idObject == OBJID_MENU
+ * idChild == ID of child menu bar item selected
+ *
+ * Example #3:
+ * System propagating a dropdown coming off of said menu bar item
+ * EVENT_OBJECT_CREATE
+ * hwnd == popup item
+ * idObject == OBJID_WINDOW
+ * idChild == CHILDID_SELF
+ *
+ * Example #4:
+ *
+ * For EVENT_OBJECT_REORDER, the object referred to by hwnd/idObject is the
+ * PARENT container in which the zorder is occurring. This is because if
+ * one child is zordering, all of them are changing their relative zorder.
+ */
+#define EVENT_OBJECT_CREATE 0x8000 // hwnd + ID + idChild is created item
+#define EVENT_OBJECT_DESTROY 0x8001 // hwnd + ID + idChild is destroyed item
+#define EVENT_OBJECT_SHOW 0x8002 // hwnd + ID + idChild is shown item
+#define EVENT_OBJECT_HIDE 0x8003 // hwnd + ID + idChild is hidden item
+#define EVENT_OBJECT_REORDER 0x8004 // hwnd + ID + idChild is parent of zordering children
+/*
+ * NOTE:
+ * Minimize the number of notifications!
+ *
+ * When you are hiding a parent object, obviously all child objects are no
+ * longer visible on screen. They still have the same "visible" status,
+ * but are not truly visible. Hence do not send HIDE notifications for the
+ * children also. One implies all. The same goes for SHOW.
+ */
+
+
+#define EVENT_OBJECT_FOCUS 0x8005 // hwnd + ID + idChild is focused item
+#define EVENT_OBJECT_SELECTION 0x8006 // hwnd + ID + idChild is selected item (if only one), or idChild is OBJID_WINDOW if complex
+#define EVENT_OBJECT_SELECTIONADD 0x8007 // hwnd + ID + idChild is item added
+#define EVENT_OBJECT_SELECTIONREMOVE 0x8008 // hwnd + ID + idChild is item removed
+#define EVENT_OBJECT_SELECTIONWITHIN 0x8009 // hwnd + ID + idChild is parent of changed selected items
+
+/*
+ * NOTES:
+ * There is only one "focused" child item in a parent. This is the place
+ * keystrokes are going at a given moment. Hence only send a notification
+ * about where the NEW focus is going. A NEW item getting the focus already
+ * implies that the OLD item is losing it.
+ *
+ * SELECTION however can be multiple. Hence the different SELECTION
+ * notifications. Here's when to use each:
+ *
+ * (1) Send a SELECTION notification in the simple single selection
+ * case (like the focus) when the item with the selection is
+ * merely moving to a different item within a container. hwnd + ID
+ * is the container control, idChildItem is the new child with the
+ * selection.
+ *
+ * (2) Send a SELECTIONADD notification when a new item has simply been added
+ * to the selection within a container. This is appropriate when the
+ * number of newly selected items is very small. hwnd + ID is the
+ * container control, idChildItem is the new child added to the selection.
+ *
+ * (3) Send a SELECTIONREMOVE notification when a new item has simply been
+ * removed from the selection within a container. This is appropriate
+ * when the number of newly selected items is very small, just like
+ * SELECTIONADD. hwnd + ID is the container control, idChildItem is the
+ * new child removed from the selection.
+ *
+ * (4) Send a SELECTIONWITHIN notification when the selected items within a
+ * control have changed substantially. Rather than propagate a large
+ * number of changes to reflect removal for some items, addition of
+ * others, just tell somebody who cares that a lot happened. It will
+ * be faster an easier for somebody watching to just turn around and
+ * query the container control what the new bunch of selected items
+ * are.
+ */
+
+#define EVENT_OBJECT_STATECHANGE 0x800A // hwnd + ID + idChild is item w/ state change
+/*
+ * Examples of when to send an EVENT_OBJECT_STATECHANGE include
+ * * It is being enabled/disabled (USER does for windows)
+ * * It is being pressed/released (USER does for buttons)
+ * * It is being checked/unchecked (USER does for radio/check buttons)
+ */
+#define EVENT_OBJECT_LOCATIONCHANGE 0x800B // hwnd + ID + idChild is moved/sized item
+
+/*
+ * Note:
+ * A LOCATIONCHANGE is not sent for every child object when the parent
+ * changes shape/moves. Send one notification for the topmost object
+ * that is changing. For example, if the user resizes a top level window,
+ * USER will generate a LOCATIONCHANGE for it, but not for the menu bar,
+ * title bar, scrollbars, etc. that are also changing shape/moving.
+ *
+ * In other words, it only generates LOCATIONCHANGE notifications for
+ * real windows that are moving/sizing. It will not generate a LOCATIONCHANGE
+ * for every non-floating child window when the parent moves (the children are
+ * logically moving also on screen, but not relative to the parent).
+ *
+ * Now, if the app itself resizes child windows as a result of being
+ * sized, USER will generate LOCATIONCHANGEs for those dudes also because
+ * it doesn't know better.
+ *
+ * Note also that USER will generate LOCATIONCHANGE notifications for two
+ * non-window sys objects:
+ * (1) System caret
+ * (2) Cursor
+ */
+
+#define EVENT_OBJECT_NAMECHANGE 0x800C // hwnd + ID + idChild is item w/ name change
+#define EVENT_OBJECT_DESCRIPTIONCHANGE 0x800D // hwnd + ID + idChild is item w/ desc change
+#define EVENT_OBJECT_VALUECHANGE 0x800E // hwnd + ID + idChild is item w/ value change
+#define EVENT_OBJECT_PARENTCHANGE 0x800F // hwnd + ID + idChild is item w/ new parent
+#define EVENT_OBJECT_HELPCHANGE 0x8010 // hwnd + ID + idChild is item w/ help change
+#define EVENT_OBJECT_DEFACTIONCHANGE 0x8011 // hwnd + ID + idChild is item w/ def action change
+#define EVENT_OBJECT_ACCELERATORCHANGE 0x8012 // hwnd + ID + idChild is item w/ keybd accel change
+
+#ifdef WIN32
+WINUSERAPI VOID WINAPI
+NotifyWinEvent(
+ DWORD event,
+ HWND hwnd,
+ LONG idObject,
+ LONG idChild);
+#endif
+
+#include <bfc/dispatch.h>
+
+struct IAccessible;
+
+class Accessible : public Dispatchable {
+ public:
+ IAccessible *getIAccessible();
+#ifdef _WIN32
+ HRESULT getOSHandle(int p);
+#endif
+ void release();
+ void addRef();
+ int getNumRefs();
+ void onGetFocus(int idx=-1);
+ void onStateChange(int idx=-1);
+ void onSetName(const wchar_t *newname, int idx=-1);
+ OSWINDOWHANDLE getOSWnd();
+ int flattenContent(OSWINDOWHANDLE *w);
+
+ enum {
+ ACCESSIBLE_GETIACCESSIBLE=10,
+ ACCESSIBLE_GETOSHANDLE=20,
+ ACCESSIBLE_ADDREF=30,
+ ACCESSIBLE_RELEASE=40,
+ ACCESSIBLE_GETNUMREFS=50,
+ ACCESSIBLE_ONGETFOCUS=60,
+ ACCESSIBLE_ONSETNAME=70,
+ ACCESSIBLE_GETOSWND=80,
+ ACCESSIBLE_ONSTATECHANGE=90,
+ ACCESSIBLE_FLATTENCONTENT=100,
+ };
+};
+
+inline IAccessible *Accessible::getIAccessible() {
+ return _call(ACCESSIBLE_GETIACCESSIBLE, (IAccessible *)NULL);
+}
+
+#ifdef _WIN32
+inline HRESULT Accessible::getOSHandle(int p) {
+ return _call(ACCESSIBLE_GETOSHANDLE, (HRESULT)NULL, p);
+}
+#endif
+
+inline void Accessible::addRef() {
+ _voidcall(ACCESSIBLE_ADDREF);
+}
+
+inline void Accessible::release() {
+ _voidcall(ACCESSIBLE_RELEASE);
+}
+
+inline int Accessible::getNumRefs() {
+ return _call(ACCESSIBLE_GETNUMREFS, 0);
+}
+
+inline void Accessible::onGetFocus(int idx/* =-1 */) {
+ _voidcall(ACCESSIBLE_ONGETFOCUS, idx);
+}
+
+inline void Accessible::onSetName(const wchar_t *name, int idx) {
+ _voidcall(ACCESSIBLE_ONSETNAME, name, idx);
+}
+
+inline OSWINDOWHANDLE Accessible::getOSWnd() {
+ return _call(ACCESSIBLE_GETOSWND, (OSWINDOWHANDLE)NULL);
+}
+
+inline void Accessible::onStateChange(int idx/* =-1 */) {
+ _voidcall(ACCESSIBLE_ONSTATECHANGE, idx);
+}
+
+inline int Accessible::flattenContent(OSWINDOWHANDLE *w) {
+ return _call(ACCESSIBLE_FLATTENCONTENT, 0, w);
+}
+
+class AccessibleI : public Accessible {
+ public:
+ AccessibleI() {}
+ virtual ~AccessibleI() {}
+
+ virtual IAccessible *getIAccessible()=0;
+#ifdef _WIN32
+ virtual HRESULT getOSHandle(int p)=0;
+#endif
+ virtual void release()=0;
+ virtual void addRef()=0;
+ virtual int getNumRefs()=0;
+ virtual void onGetFocus(int idx=-1)=0;
+ virtual void onSetName(const wchar_t *name, int idx)=0;
+ virtual OSWINDOWHANDLE getOSWnd()=0;
+ virtual void onStateChange(int idx=-1)=0;
+ virtual int flattenContent(OSWINDOWHANDLE *w)=0;
+
+ protected:
+ RECVS_DISPATCH;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/api_canvas.cpp b/Src/Wasabi/api/wnd/api_canvas.cpp
new file mode 100644
index 00000000..e170572f
--- /dev/null
+++ b/Src/Wasabi/api/wnd/api_canvas.cpp
@@ -0,0 +1,2 @@
+#include <precomp.h>
+#include "ifc_canvas.h"
diff --git a/Src/Wasabi/api/wnd/api_canvas.h b/Src/Wasabi/api/wnd/api_canvas.h
new file mode 100644
index 00000000..513d6c47
--- /dev/null
+++ b/Src/Wasabi/api/wnd/api_canvas.h
@@ -0,0 +1,163 @@
+#ifndef __WASABI_API_CANVAS_H
+#define __WASABI_API_CANVAS_H
+
+#include <bfc/dispatch.h>
+#include <bfc/platform/platform.h>
+#include <api/service/svcs/svc_font.h> // for STDFONT_* stuff. should make a std_font thingy later
+#include <bfc/std.h> // for WASABI_DEFAULT_FONTNAMEW
+
+namespace Wasabi
+{
+ // benski> move this to std_font later
+struct FontInfo
+{
+ FontInfo()
+ {
+ // defaults
+ face = WASABI_DEFAULT_FONTNAMEW;
+ pointSize = 12;
+ bold = 0;
+ opaque = false;
+ underline = false;
+ italic = false;
+ alignFlags = STDFONT_LEFT;
+ antialias = 1;
+ bgColor = RGBA(255, 255, 255, 255);
+ color = RGBA(0, 0, 0, 0);
+ }
+
+ const wchar_t *face;
+ unsigned int pointSize;
+ int bold; // bold level
+ bool opaque;
+ bool underline;
+ bool italic;
+ int alignFlags;
+ int antialias; // anti-alias level
+ ARGB32 color;
+ ARGB32 bgColor;
+};
+}
+
+class ifc_window;
+// abstract base class: safe to use in API
+class NOVTABLE ifc_canvas : public Dispatchable
+{
+protected:
+ ifc_canvas()
+ {} // protect constructor
+ ~ifc_canvas()
+ {}
+
+public:
+ DISPATCH_CODES
+ {
+ GETHDC = 100,
+ GETROOTWND = 200,
+ GETBITS = 300,
+ GETOFFSETS = 400,
+ ISFIXEDCOORDS = 500,
+ GETDIM = 600,
+ GETTEXTFONT = 700,
+ GETTEXTSIZE = 710,
+ GETTEXTBOLD = 720,
+ GETTEXTOPAQUE = 730,
+ GETTEXTALIGN = 740,
+ GETTEXTCOLOR = 750,
+ GETTEXTBKCOLOR = 760,
+ GETTEXTAA = 770,
+ GETTEXTUNDERLINE = 780,
+ GETTEXTITALIC = 790,
+ GETCLIPBOX = 800,
+ };
+public:
+ HDC getHDC();
+ ifc_window *getRootWnd();
+ void *getBits();
+ void getOffsets(int *x, int *y);
+ bool isFixedCoords(); //FG> allows onPaint to handle double buffers as well as normal DCs
+ bool getDim(int *w, int *h = NULL, int *p = NULL); // w & h in pixels, pitch in bytes. 0 on success.
+ int getClipBox(RECT *r); // returns 0 if no clipping region
+ const wchar_t *getTextFont();
+ int getTextSize();
+ int getTextBold();
+ int getTextAntialias();
+ int getTextOpaque();
+ int getTextUnderline();
+ int getTextItalic();
+ int getTextAlign();
+ ARGB32 getTextColor();
+ ARGB32 getTextBkColor();
+};
+
+
+inline HDC ifc_canvas::getHDC()
+{
+ return _call(ifc_canvas::GETHDC, (HDC)0);
+}
+inline ifc_window *ifc_canvas::getRootWnd()
+{
+ return _call(ifc_canvas::GETROOTWND, (ifc_window*)0);
+}
+inline void *ifc_canvas::getBits()
+{
+ return _call(ifc_canvas::GETBITS, (void *)0);
+}
+inline void ifc_canvas::getOffsets(int *x, int *y)
+{
+ _voidcall(ifc_canvas::GETOFFSETS, x, y);
+}
+inline bool ifc_canvas::isFixedCoords()
+{ //FG> allows onPaint to handle double buffers as well as normal DCs
+ return _call(ifc_canvas::ISFIXEDCOORDS, false);
+}
+inline bool ifc_canvas::getDim(int *w, int *h, int *p)
+{ // w & h in pixels, pitch in bytes. 0 on success.
+ return _call(ifc_canvas::GETDIM, false, w, h, p);
+}
+inline int ifc_canvas::getClipBox(RECT *r)
+{ // returns 0 if no clipping region
+ return _call(ifc_canvas::GETCLIPBOX, 0, r);
+}
+
+inline const wchar_t *ifc_canvas::getTextFont()
+{
+ return _call(ifc_canvas::GETTEXTFONT, L"");
+}
+inline int ifc_canvas::getTextSize()
+{
+ return _call(ifc_canvas::GETTEXTSIZE, -1);
+}
+inline int ifc_canvas::getTextBold()
+{
+ return _call(ifc_canvas::GETTEXTBOLD, 0);
+}
+inline int ifc_canvas::getTextAntialias()
+{
+ return _call(ifc_canvas::GETTEXTAA, 0);
+}
+inline int ifc_canvas::getTextOpaque()
+{
+ return _call(ifc_canvas::GETTEXTOPAQUE, 0);
+}
+inline int ifc_canvas::getTextUnderline()
+{
+ return _call(ifc_canvas::GETTEXTUNDERLINE, 0);
+}
+inline int ifc_canvas::getTextItalic()
+{
+ return _call(ifc_canvas::GETTEXTITALIC, 0);
+}
+inline int ifc_canvas::getTextAlign()
+{
+ return _call(ifc_canvas::GETTEXTALIGN, -1);
+}
+inline ARGB32 ifc_canvas::getTextColor()
+{
+ return _call(ifc_canvas::GETTEXTCOLOR, RGB(0, 0, 0));
+}
+inline ARGB32 ifc_canvas::getTextBkColor()
+{
+ return _call(ifc_canvas::GETTEXTBKCOLOR, RGB(255, 255, 255));
+}
+#endif
diff --git a/Src/Wasabi/api/wnd/api_region.cpp b/Src/Wasabi/api/wnd/api_region.cpp
new file mode 100644
index 00000000..40063420
--- /dev/null
+++ b/Src/Wasabi/api/wnd/api_region.cpp
@@ -0,0 +1,2 @@
+#include <precomp.h>
+#include "api_region.h" \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/api_region.h b/Src/Wasabi/api/wnd/api_region.h
new file mode 100644
index 00000000..df184246
--- /dev/null
+++ b/Src/Wasabi/api/wnd/api_region.h
@@ -0,0 +1,200 @@
+#ifndef __WASABI_API_REGION_H
+#define __WASABI_API_REGION_H
+
+#include <bfc/dispatch.h>
+
+class api_region : public Dispatchable
+{
+protected:
+ api_region() {}
+ virtual ~api_region() {}
+
+public:
+ DISPATCH_CODES
+ {
+ REGION_GETOSHANDLE = 50,
+ REGION_CLONE = 100,
+ REGION_DISPOSECLONE = 110,
+ REGION_PTINREGION = 120,
+ REGION_OFFSET = 130,
+ REGION_GETBOX = 140,
+ REGION_SUBTRACTRGN = 150,
+ REGION_SUBTRACTRECT = 160,
+ REGION_ADDRECT = 170,
+ REGION_ADD = 180,
+ REGION_AND = 190,
+ REGION_SETRECT = 200,
+ REGION_EMPTY = 210,
+ REGION_ISEMPTY = 220,
+ REGION_EQUALS = 230,
+ REGION_ENCLOSED = 240,
+ REGION_INTERSECTRGN = 250,
+ REGION_DOESINTERSECTRGN = 251,
+ REGION_INTERSECTRECT = 260,
+ REGION_ISRECT = 270,
+ REGION_SCALE = 280,
+ REGION_DEBUG = 290,
+ REGION_MAKEWNDREGION = 300,
+ REGION_GETNUMRECTS = 310,
+ REGION_ENUMRECT = 320,
+ };
+public:
+ OSREGIONHANDLE getOSHandle(); // avoid as much as you can, should be used only when you need to call the OS api
+
+ api_region *clone();
+ void disposeClone(api_region *r);
+ bool ptInRegion(const POINT *pt);
+ void offset(int x, int y);
+ void getBox(RECT *r);
+ void subtractRegion(const api_region *r);
+ void subtractRgn(const api_region *r) { subtractRegion(r); } //DEPRECATED
+ void subtractRect(const RECT *r);
+ void addRect(const RECT *r);
+ void addRegion(const api_region *r);
+ void andRegion(const api_region *r);
+ void setRect(const RECT *r);
+ void empty();
+ int isEmpty();
+ int equals(const api_region *r);
+ int enclosed(const api_region *r, api_region *outside = NULL);
+ int intersectRgn(const api_region *r, api_region *intersection);
+ int doesIntersectRgn(const api_region *r);
+ int intersectRect(const RECT *r, api_region *intersection);
+
+ int isRect();
+ void scale(double sx, double sy, bool round = 0);
+ void debug(int async = 0);
+ OSREGIONHANDLE makeWindowRegion(); // gives you a handle to a clone of the OSREGION object so you can insert it into a window's region with SetWindowRgn. ANY other use is prohibited
+
+ // this is how you can enumerate the subrects that compose to make up the
+ // entire region
+ int getNumRects();
+ int enumRect(int n, RECT *r);
+};
+
+inline OSREGIONHANDLE api_region::getOSHandle()
+{
+ return _call(REGION_GETOSHANDLE, (OSREGIONHANDLE)NULL);
+}
+
+inline api_region *api_region::clone()
+{
+ return _call(REGION_CLONE, (api_region *)NULL);
+}
+
+inline void api_region::disposeClone(api_region *r)
+{
+ _voidcall(REGION_DISPOSECLONE, r);
+}
+
+inline bool api_region::ptInRegion(const POINT *pt)
+{
+ return _call(REGION_PTINREGION, false, pt);
+}
+
+inline void api_region::offset(int x, int y)
+{
+ _voidcall(REGION_OFFSET, x, y);
+}
+
+inline void api_region::getBox(RECT *r)
+{
+ _voidcall(REGION_GETBOX, r);
+}
+
+inline void api_region::subtractRegion(const api_region *reg)
+{
+ _voidcall(REGION_SUBTRACTRGN, reg);
+}
+
+inline void api_region::subtractRect(const RECT *r)
+{
+ _voidcall(REGION_SUBTRACTRECT, r);
+}
+
+inline void api_region::addRect(const RECT *r)
+{
+ _voidcall(REGION_ADDRECT, r);
+}
+
+inline void api_region::addRegion(const api_region *r)
+{
+ _voidcall(REGION_ADD, r);
+}
+
+inline void api_region::andRegion(const api_region *r)
+{
+ _voidcall(REGION_AND, r);
+}
+
+inline void api_region::setRect(const RECT *r)
+{
+ _voidcall(REGION_SETRECT, r);
+}
+
+inline void api_region::empty()
+{
+ _voidcall(REGION_EMPTY);
+}
+
+inline int api_region::isEmpty()
+{
+ return _call(REGION_ISEMPTY, 0);
+}
+
+inline int api_region::equals(const api_region *r)
+{
+ return _call(REGION_EQUALS, 0, r);
+}
+
+inline int api_region::enclosed(const api_region *r, api_region *outside)
+{
+ return _call(REGION_ENCLOSED, 0, r, outside);
+}
+
+inline int api_region::intersectRgn(const api_region *r, api_region *intersection)
+{
+ return _call(REGION_INTERSECTRGN, 0, r, intersection);
+}
+
+inline int api_region::doesIntersectRgn(const api_region *r)
+{
+ return _call(REGION_DOESINTERSECTRGN, 0, r);
+}
+
+inline int api_region::intersectRect(const RECT *r, api_region *intersection)
+{
+ return _call(REGION_INTERSECTRECT, 0, r, intersection);
+}
+
+inline int api_region::isRect()
+{
+ return _call(REGION_ISRECT, 0);
+}
+
+inline void api_region::scale(double sx, double sy, bool round)
+{
+ _voidcall(REGION_SCALE, sx, sy, round);
+}
+
+inline void api_region::debug(int async)
+{
+ _voidcall(REGION_DEBUG, async);
+}
+
+inline OSREGIONHANDLE api_region::makeWindowRegion()
+{
+ return _call(REGION_MAKEWNDREGION, (OSREGIONHANDLE)NULL);
+}
+
+inline int api_region::getNumRects()
+{
+ return _call(REGION_GETNUMRECTS, 0);
+}
+
+inline int api_region::enumRect(int n, RECT *r)
+{
+ return _call(REGION_ENUMRECT, 0, n, r);
+}
+
+#endif
diff --git a/Src/Wasabi/api/wnd/api_window.cpp b/Src/Wasabi/api/wnd/api_window.cpp
new file mode 100644
index 00000000..537a3b2c
--- /dev/null
+++ b/Src/Wasabi/api/wnd/api_window.cpp
@@ -0,0 +1,3 @@
+#include <precomp.h>
+#include "api_window.h"
+
diff --git a/Src/Wasabi/api/wnd/api_window.h b/Src/Wasabi/api/wnd/api_window.h
new file mode 100644
index 00000000..3d6f1c00
--- /dev/null
+++ b/Src/Wasabi/api/wnd/api_window.h
@@ -0,0 +1,1277 @@
+#ifndef __WASABI_API_WINDOW_H
+#define __WASABI_API_WINDOW_H
+
+#include <bfc/dispatch.h>
+#include <api/wnd/drag.h>
+#include <api/wnd/cursor.h>
+#include <api/wnd/accessible.h>
+#include <tataki/canvas/Canvas.h>
+#include <api/dependency/api_dependent.h>
+#include <api/timer/timerclient.h>
+#include <api/script/objects/guiobject.h>
+enum WndPreferences {
+ SUGGESTED_X,
+ SUGGESTED_Y,
+ SUGGESTED_W,
+ SUGGESTED_H,
+ MINIMUM_W,
+ MINIMUM_H,
+ MAXIMUM_W,
+ MAXIMUM_H,
+};
+
+enum GetTab {
+ TAB_GETCURRENT,
+ TAB_GETNEXT,
+ TAB_GETPREVIOUS,
+ TAB_GETFIRST,
+ TAB_GETLAST,
+};
+
+
+#define MAXIMIZE_WIDTH 1
+#define MAXIMIZE_HEIGHT 2
+
+#define RESTORE_X 1
+#define RESTORE_Y 2
+#define RESTORE_HEIGHT 4
+#define RESTORE_WIDTH 8
+
+// popWindowRect flags
+#define PWR_X 1
+#define PWR_Y 2
+#define PWR_WIDTH 4
+#define PWR_HEIGHT 8
+#define PWR_DIMENTIONS (PWR_WIDTH|PWR_HEIGHT)
+#define PWR_POSITION (PWR_X|PWR_Y)
+
+class FindObjectCallback;
+
+class NOVTABLE ifc_window : public Dispatchable
+{
+protected:
+ ifc_window() {} // protect constructor
+public:
+ static const GUID *depend_getClassGuid() {
+ // {11981849-61F7-4158-8283-DA7DD006D732}
+ static const GUID ret =
+ { 0x11981849, 0x61f7, 0x4158, { 0x82, 0x83, 0xda, 0x7d, 0xd0, 0x6, 0xd7, 0x32 } };
+ return &ret;
+ }
+
+ // this passes thru to the windows WndProc, if there is one -- NONPORTABLE
+#if defined (_WIN32) || defined (_WIN64)
+ virtual LRESULT wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)=0;
+#elif defined(__APPLE__)
+ virtual OSStatus eventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)=0;
+#endif
+
+ // get the OSWINDOWHANDLE (if there is one)
+ OSWINDOWHANDLE gethWnd() { return getOsWindowHandle(); } // stay back compatibile
+ OSWINDOWHANDLE getOsWindowHandle();
+ OSMODULEHANDLE getOsModuleHandle();
+ void performBatchProcesses(); // this is called after wndProc is called (under win32) to recompute batch operations such as calculating window regions, cascaderepainting, etc. this prevents N children from independently calling repaintTree for the whole gui on overlaping zones of the framebuffer. under OSes other than win32, this should be called after you've executed all your window events for this poll
+ TimerClient *getTimerClient();
+
+ const wchar_t *getRootWndName();
+ const wchar_t *getId();
+
+ int init(ifc_window *parent, int nochild=FALSE);
+ int isInited(); // are we post init() ? USE THIS INSTEAD OF gethWnd()==1
+ int isPostOnInit(); // are we post onInit() ? USE THIS INSTEAD OF ISINITED TO KNOW IF YOU CAN CALL ONRESIZE (if a function can be called by onInit and other parts of the code at the same time)
+
+ int setVirtual(int i);
+
+ int isClickThrough();
+ int onMouseMove(int x, int y);
+ int onLeftButtonUp(int x, int y);
+ int onRightButtonUp(int x, int y);
+ int onLeftButtonDown(int x, int y);
+ int onRightButtonDown(int x, int y);
+ int onLeftButtonDblClk(int x, int y);
+ int onRightButtonDblClk(int x, int y);
+
+ // fetch the DragInterface of the api_window here, can be NULL
+ DragInterface *getDragInterface();
+
+ int getCursorType(int x, int y);
+ OSCURSORHANDLE getCustomCursor(int x, int y);
+
+ // returns deepest child for point or yourself if no child there
+ ifc_window *rootWndFromPoint(POINT *pt);
+
+ void getClientRect(RECT *);
+ void getNonClientRect(RECT *rect);
+ // the onscreen coordinates
+ int getWindowRect(RECT *r);
+
+ void setVisible(int show);
+ void setCloaked(int cloak);
+ void onSetVisible(int show);
+ int isVisible(int within=0);
+
+ void *getInterface(GUID interface_guid);
+
+ // painting stuff
+ void invalidate();
+ void invalidateRect(RECT *r);
+ void invalidateRgn(api_region *r);
+ void invalidateFrom(ifc_window *who);
+ void invalidateRectFrom(RECT *r, ifc_window *who);
+ void invalidateRgnFrom(api_region *r, ifc_window *who);
+ void onChildInvalidate(api_region *r, ifc_window *who);
+ void validate();
+ void validateRect(RECT *r);
+ void validateRgn(api_region *reg);
+ int paintTree(ifc_canvas *canvas, api_region *r);
+ int paint(Canvas *canvas=NULL, api_region *r=NULL);
+ Canvas *getFrameBuffer();
+ ifc_window *getParent();
+ ifc_window *getRootParent();
+ ifc_window *getDesktopParent();
+ void setParent(ifc_window *newparent);
+ int onSiblingInvalidateRgn(api_region *r, ifc_window *who, int who_idx, int my_idx);
+ int wantSiblingInvalidations();
+ int wantAutoContextMenu();
+ int wantActivation();
+ void activate();
+ int cascadeRepaintFrom(ifc_window *who, int pack=1);
+ int cascadeRepaintRgnFrom(api_region *reg, ifc_window *who, int pack=1);
+ int cascadeRepaintRectFrom(RECT *r, ifc_window *who, int pack=1);
+ int cascadeRepaint(int pack=1);
+ int cascadeRepaintRgn(api_region *reg, int pack=1);
+ int cascadeRepaintRect(RECT *r, int pack=1);
+ void repaint();
+ ifc_window *getBaseTextureWindow();
+ int childNotify(ifc_window *child, int msg, intptr_t p1, intptr_t p2);
+ int getPreferences(int what);
+ void setPreferences(int what, int v);
+ api_region *getRegion();
+ void invalidateWindowRegion();
+ api_region *getComposedRegion();
+ api_region *getSubtractorRegion();
+ int getRegionOp();
+ void setRegionOp(int op);
+ int isRectRgn();
+ void setRectRgn(int rrgn);
+ void setStartHidden(int sh);
+ void setClickThrough(int ct);
+ void focusNext();
+ void focusPrevious();
+
+ void setWindowTitle(const wchar_t *name);
+
+ double getRenderRatio();
+ void setRenderRatio(double r);
+ void setRatioLinked(int l); // 1 = getRenderRatio asks parent, 0 = returns this ratio, default is 1, 0 should only be used for non virtuals
+ int handleRatio();
+ void resize(int x, int y, int w, int h, int wantcb=1);
+ inline void resizeToRect(RECT *r)
+ {
+ resize(r->left, r->top, r->right - r->left, r->bottom - r->top);
+ }
+ void move(int x, int y);
+ void notifyDeferredMove(int x, int y);
+ void getPosition(POINT *pt);
+ ifc_window *getForwardWnd();
+
+ // children registration/enumeration
+ void registerRootWndChild(ifc_window *child);
+ void unregisterRootWndChild(ifc_window *child);
+ ifc_window *findRootWndChild(int x, int y, int only_virtuals=0);
+ ifc_window *enumRootWndChildren(int _enum);
+ int getNumRootWndChildren();
+
+ // virtual child stuff
+ int isVirtual();
+ void bringVirtualToFront(ifc_window *w);
+ void bringVirtualToBack(ifc_window *w);
+ void bringVirtualAbove(ifc_window *w, ifc_window *b);
+ void bringVirtualBelow(ifc_window *w, ifc_window *b);
+ int checkDoubleClick(int button, int x, int y);
+
+ void onCancelCapture();
+ void cancelCapture();
+ void setVirtualChildCapture(ifc_window *child);
+ ifc_window *getVirtualChildCapture();
+ ifc_window *getCurVirtualChildFocus();
+ ifc_window *getTab(int what=TAB_GETCURRENT);
+
+ bool ptInRegion(int x, int y);
+
+ void clientToScreen(int *x, int *y); // so rootWndFromPoint can map ratio
+ void screenToClient(int *x, int *y); // ..
+
+ int getNotifyId();
+
+ int onActivate();
+ int onDeactivate();
+ int isActive();
+ int handleTransparency();
+ int handleDesktopAlpha();
+ void setEnabled(int e);
+ int onEnable(int e);
+ int isEnabled(int within=0);
+ int getPaintingAlpha();
+ void getAlpha(int *activealpha=NULL, int *inactivealpha=NULL);
+ void setAlpha(int activealpha, int inactivealpha=-1); // -1 means same as activealpha
+ void setTip(const wchar_t *tip);
+
+ int runModal();
+ void endModal(int retcode);
+
+ void bringToFront();
+ void bringToBack();
+ void setFocus();
+ int gotFocus();
+ ifc_window *getNextVirtualFocus(ifc_window *w);
+ void setVirtualChildFocus(ifc_window *w);
+ void setVirtualTabOrder(ifc_window *w, int a);
+ int getVirtualTabOrder(ifc_window *w);
+ int wantFocus();
+ void setTabOrder(int a);
+ int getTabOrder();
+ void setAutoTabOrder();
+ void setVirtualAutoTabOrder(ifc_window *w);
+
+ int onAcceleratorEvent(const wchar_t *name);
+ int onChar(unsigned int c);
+ int onKeyDown(int keycode);
+ int onKeyUp(int keycode);
+ int onSysKeyDown(int keyCode, int keyData);
+ int onSysKeyUp(int keyCode, int keyData);
+ int onKillFocus();
+ int onGetFocus();
+ void onSetRootFocus(ifc_window *w);
+
+ ifc_dependent *getDependencyPtr();
+ void addMinMaxEnforcer(ifc_window *w);
+ void removeMinMaxEnforcer(ifc_window *w);
+ ifc_window *enumMinMaxEnforcer(int n);
+ int getNumMinMaxEnforcers();
+ void signalMinMaxEnforcerChanged();
+
+ int onAction(const wchar_t *action, const wchar_t *param=NULL, int x=-1, int y=-1, intptr_t p1=0, intptr_t p2=0, void *data=NULL, size_t datalen=0, ifc_window *source=NULL);
+
+ void setRenderBaseTexture(int r);
+ int getRenderBaseTexture();
+ void renderBaseTexture(ifc_canvas *c, const RECT *r, int alpha=255);
+
+ GuiObject *getGuiObject(); // not guaranteed non null
+ int getFlag(int flag);
+
+ // see basewnd.h for codes. this is to force an event
+ int triggerEvent(int event, intptr_t p1=0, intptr_t p2=0);
+
+ int allowDeactivation();
+ void setAllowDeactivation(int allow);
+
+ ifc_window *findWindow(const wchar_t *id);
+ ifc_window *findWindowByInterface(GUID interface_guid);
+ ifc_window *findWindowByCallback(FindObjectCallback *cb);
+ ifc_window *findWindowChain(FindObjectCallback *cb, ifc_window *wcaller);
+
+ ifc_window *enumTab(int i);
+ int getNumTabs();
+
+ int getFocusOnClick();
+ void setFocusOnClick(int i);
+
+ void setNoDoubleClicks(int no);
+ void setNoLeftClicks(int no);
+ void setNoRightClicks(int no);
+ void setNoMouseMoves(int no);
+ void setNoContextMenus(int no);
+
+ int wantDoubleClicks();
+ int wantLeftClicks();
+ int wantRightClicks();
+ int wantMouseMoves();
+ int wantContextMenus();
+
+ void setDefaultCursor(Cursor *c);
+
+ Accessible *getAccessibleObject(int createifnotexist=1);
+
+ int accessibility_getState();
+
+#ifndef WA3COMPATIBILITY
+ void setDropTarget(void *dt);
+ void *getDropTarget();
+#endif
+
+#ifdef EXPERIMENTAL_INDEPENDENT_AOT
+ void setAlwaysOnTop(int i);
+ int getAlwaysOnTop();
+#endif
+
+ void maximize(int axis=MAXIMIZE_WIDTH|MAXIMIZE_HEIGHT);
+ void restore(int what=RESTORE_X|RESTORE_Y|RESTORE_WIDTH|RESTORE_HEIGHT);
+ int getRestoredRect(RECT *r);
+ int isMinimized();
+
+ enum {
+ Event_SETVISIBLE=100, // param 2 is 1 or 0
+ Event_ONPAINT=200, // param 2 is PaintCallback::BEFOREPAINT or PaintCallback::AFTERPAINT
+ Event_ONINVALIDATE=300,
+ };
+
+ enum {
+ BATCHPROCESSES = 50,
+ GETOSWINDOWHANDLE = 100,
+ GETOSMODULEHANDLE = 105,
+ GETROOTWNDNAME = 110,
+ GETID = 120,
+ GETDRAGINTERFACE = 200,
+ FROMPOINT = 300,
+ GETWINDOWRECT = 400,
+ ISVISIBLE = 501,
+ ONMETRICCHANGE = 700,
+ PAINTTREE = 900,
+ PAINT = 910,
+ GETFRAMEBUFFER = 920,
+ GETPARENT = 1000,
+ GETROOTPARENT = 1001,
+ SETPARENT = 1002,
+ GETDESKTOPPARENT = 1003,
+ CHILDNOTIFY = 1200,
+ GETPREFERENCES = 1300,
+ SETPREFERENCES = 1310,
+ CLICKTHROUGH = 1500,
+ GETFORWARDWND = 1501,
+ SETCLICKTHROUGH = 1502,
+ CLIENTSCREEN = 1600,
+ SCREENCLIENT = 1601,
+ INIT = 1700,
+ ISINITED = 1701,
+ ISPOSTONINIT = 1702,
+ SETVIRTUAL = 1704,
+ GETCURSORTYPE = 1800,
+ GETCUSTOMCURSOR = 1801,
+ GETINTERFACE = 1850,
+ GETCLIENTRECT = 1900,
+ GETNONCLIENTRECT = 1901,
+ SETVISIBLE = 2000,
+ ONSETVISIBLE = 2001,
+ SETCLOAKED = 2002,
+ INVALIDATE = 2100,
+ INVALIDATERECT = 2101,
+ INVALIDATERGN = 2102,
+ INVALIDATEFROM = 2103,
+ INVALIDATERECTFROM = 2104,
+ INVALIDATERGNFROM = 2105,
+ VALIDATE = 2200,
+ VALIDATERECT = 2201,
+ VALIDATERGN = 2202,
+ ONSIBINVALIDATE = 2300,
+ WANTSIBINVALIDATE = 2301,
+ ONCHILDINVALIDATE = 2302,
+ CASCADEREPAINTFROM = 2400,
+ CASCADEREPAINTRECTFROM = 2401,
+ CASCADEREPAINTRGNFROM = 2402,
+ CASCADEREPAINT = 2403,
+ CASCADEREPAINTRECT = 2405,
+ CASCADEREPAINTRGN = 2406,
+ REPAINT = 2500,
+ GETTEXTUREWND = 2600,
+ ONACTIVATE = 2700,
+ ACTIVATE = 2710,
+ ONDEACTIVATE = 2800,
+ ISACTIVATED = 2801,
+ GETPOSITION = 2900,
+ GETREGION = 3000,
+ GETREGIONOP = 3001,
+ INVALWNDRGN = 3002,
+ GETCOMPOSEDRGN = 3003,
+ GETSUBTRACTORRGN = 3010,
+ SETREGIONOP = 3004,
+ SETRECTRGN = 3005,
+ ISRECTRGN = 3006,
+ //SETPARAM = 3200, // deprecated, use the xmlobject interface
+ HANDLETRANSPARENCY = 3300,
+ HANDLEDESKTOPALPHA = 3400,
+ SETSTARTHIDDEN = 3500,
+ GETRENDERRATIO = 3600,
+ SETRENDERRATIO = 3610,
+ SETRATIOLINKED = 3615,
+ HANDLERATIO = 3620,
+ //_RESIZE = 3700, // deprecated, cut
+ _RESIZE = 3701,
+ _MOVE = 3710,
+ NOTIFYDEFERREDMOVE = 3720,
+ CHECKDBLCLK = 3800,
+ REGISTERROOTWNDCHILD = 3960,
+ UNREGISTERROOTWNDCHILD = 3965,
+ FINDROOTWNDCHILD= 3970,
+ ENUMROOTWNDCHILDREN = 3975,
+ GETNUMROOTWNDCHILDREN = 3980,
+ ISVIRTUAL = 3950,
+ BRINGVTOFRONT = 4000,
+ BRINGVTOBACK = 4010,
+ BRINGVABOVE = 4020,
+ BRINGVBELOW = 4030,
+ SETVCAPTURE = 4100,
+ GETVCAPTURE = 4110,
+ SETVTIMER = 4200,
+ KILLVTIMER = 4210,
+ PTINREGION = 4400,
+ ONLBDBLCLK = 4500,
+ ONRBDBLCLK = 4510,
+ ONLBUP = 4520,
+ ONRBUP = 4530,
+ ONLBDOWN = 4540,
+ ONRBDOWN = 4550,
+ ONMOUSEMOVE = 4560,
+ CLIENTTOSCREEN = 4600,
+ SCREENTOCLIENT = 4610,
+ GETNOTIFYID = 4700,
+ SETENABLED = 4800,
+ ISENABLED = 4810,
+ ONENABLE = 4811,
+ SETALPHA = 4900,
+ GETALPHA = 4910,
+ GETPAINTALPHA = 4911,
+ SETTOOLTIP = 4920,
+ RUNMODAL = 5000,
+ ENDMODAL = 5010,
+ WANTAUTOCONTEXTMENU = 5100,
+ ONCANCELCAPTURE = 5200,
+ CANCELCAPTURE = 5210,
+ BRINGTOFRONT = 5300,
+ BRINGTOBACK = 5310,
+ SETFOCUS = 5401,
+ GOTFOCUS = 5410,
+ GETNEXTVFOCUS = 5420,
+ SETVFOCUS = 5430,
+ ONKILLFOCUS = 5440,
+ ONGETFOCUS = 5450,
+ WANTFOCUS = 5460,
+ ONKEYDOWN = 5500,
+ ONKEYUP = 5510,
+ ONCHAR = 5520,
+ ONACCELERATOREVENT = 5530,
+ GETTIMERCLIENT = 5600,
+ GETDEPENDENCYPTR = 6000,
+ ADDMINMAXENFORCER = 6400,
+ REMOVEMINMAXENFORCER = 6410,
+ GETNUMMINMAXENFORCERS = 6420,
+ ENUMMINMAXENFORCER = 6430,
+ SIGNALMINMAXCHANGED = 6440,
+ ROOTWNDONACTION = 6300,
+ SETRENDERBASETEXTURE = 6600,
+ GETRENDERBASETEXTURE = 6610,
+ RENDERBASETEXTURE=6611,
+ GETGUIOBJECT = 6620,
+ ONSYSKEYDOWN = 6630,
+ ONSYSKEYUP = 6640,
+ GETFLAG = 6650,
+ TRIGGEREVENT = 6660,
+
+ SETALLOWDEACTIVATE = 6700,
+ ALLOWDEACTIVATE=6710,
+ FINDWND_BYID=6800,
+ FINDWND_BYGUID=6810,
+ FINDWND_BYCB=6820,
+ FINDWNDCHAIN=6830,
+ SETTABORDER=6900,
+ GETTABORDER=6910,
+ SETAUTOTABORDER=6920,
+ GETTAB=6940,
+ SETVIRTUALTABORDER=7000,
+ GETVIRTUALTABORDER=7010,
+ SETVIRTUALAUTOTABORDER=7020,
+ GETCURVIRTUALCHILDFOCUS=7030,
+ FOCUSNEXT=7100,
+ FOCUSPREVIOUS=7110,
+ SETWINDOWTITLE=7120,
+ GETNUMTABS = 7200,
+ ENUMTAB = 7210,
+ ONSETROOTFOCUS = 7300,
+ GETFOCUSONCLICK = 7400,
+ SETFOCUSONCLICK = 7410,
+ SETNODOUBLECLICKS = 7500,
+ SETNOLEFTCLICKS = 7510,
+ SETNORIGHTCLICKS = 7520,
+ SETNOMOUSEMOVES = 7530,
+ SETNOCONTEXTMENUS = 7540,
+ WANTDOUBLECLICKS = 7600,
+ WANTLEFTCLICKS = 7610,
+ WANTRIGHTCLICKS = 7620,
+ WANTMOUSEMOVES = 7630,
+ WANTCONTEXTMENUS = 7640,
+ WANTACTIVATION = 7700,
+ SETDEFAULTCURSOR = 7800,
+
+ GETACCESSIBLEOBJECT = 8000,
+ ACCGETSTATE = 8104,
+
+#ifdef EXPERIMENTAL_INDEPENDENT_AOT
+ SETALWAYSONTOP = 8500,
+ GETALWAYSONTOP = 8501,
+#endif
+
+#ifndef WA3COMPATIBILITY
+ GETDROPTARGET = 8800,
+ SETDROPTARGET = 8810,
+#endif
+ ISMINIMIZED = 8900,
+ MAXIMIZE = 9200,
+ RESTORE = 9210,
+ GETRESTOREDRECT = 9220,
+ };
+};
+
+
+// helper functions definitions
+inline OSWINDOWHANDLE ifc_window::getOsWindowHandle() {
+ return _call(GETOSWINDOWHANDLE, (OSWINDOWHANDLE)NULL);
+}
+
+inline OSMODULEHANDLE ifc_window::getOsModuleHandle() {
+ return _call(GETOSMODULEHANDLE, (OSMODULEHANDLE)NULL);
+}
+
+inline void ifc_window::performBatchProcesses() {
+ _voidcall(BATCHPROCESSES);
+}
+
+inline const wchar_t *ifc_window::getRootWndName()
+{
+ return _call(GETROOTWNDNAME, (const wchar_t *)NULL);
+}
+
+inline const wchar_t *ifc_window::getId() {
+ return _call(GETID, (const wchar_t *)NULL);
+}
+
+inline DragInterface *ifc_window::getDragInterface() {
+ return _call(GETDRAGINTERFACE, (DragInterface*)0);
+}
+
+inline ifc_window *ifc_window::rootWndFromPoint(POINT *pt) {
+ return _call(FROMPOINT, (ifc_window*)0, pt);
+}
+
+inline int ifc_window::getWindowRect(RECT *r) {
+ return _voidcall(GETWINDOWRECT, r);
+}
+
+inline int ifc_window::isVisible(int within) {
+ return _call(ISVISIBLE, 0, within);
+}
+
+inline int ifc_window::paintTree(ifc_canvas *canvas, api_region *r) {
+ return _call(PAINTTREE, 0, canvas, r);
+}
+
+inline Canvas *ifc_window::getFrameBuffer() {
+ return _call(GETFRAMEBUFFER, (Canvas *)NULL);
+}
+
+inline int ifc_window::paint(Canvas *canvas, api_region *r) {
+ return _call(PAINT, 0, canvas, r);
+}
+
+inline ifc_window *ifc_window::getParent() {
+ return _call(GETPARENT, (ifc_window *)0);
+}
+
+inline ifc_window *ifc_window::getRootParent() {
+ return _call(GETROOTPARENT, (ifc_window *)0);
+}
+
+inline ifc_window *ifc_window::getDesktopParent() {
+ return _call(GETDESKTOPPARENT, (ifc_window *)0);
+}
+
+inline void ifc_window::setParent(ifc_window *parent) {
+ _voidcall(SETPARENT, parent);
+}
+
+inline int ifc_window::childNotify(ifc_window *child, int msg, intptr_t p1, intptr_t p2) {
+ return _call(CHILDNOTIFY, 0, child, msg, p1, p2);
+}
+
+inline int ifc_window::getPreferences(int what) {
+ return _call(GETPREFERENCES, 0, what);
+}
+
+inline void ifc_window::setPreferences(int what, int v) {
+ _voidcall(SETPREFERENCES, what, v);
+}
+
+inline void ifc_window::cancelCapture() {
+ _voidcall(CANCELCAPTURE, 0);
+}
+
+inline void ifc_window::onCancelCapture() {
+ _voidcall(ONCANCELCAPTURE, 0);
+}
+
+inline int ifc_window::isClickThrough() {
+ return _call(CLICKTHROUGH, 0);
+}
+
+inline void ifc_window::setClickThrough(int ct) {
+ _voidcall(SETCLICKTHROUGH, ct);
+}
+
+inline ifc_window *ifc_window::getForwardWnd() {
+ return _call(GETFORWARDWND, this);
+}
+
+inline void ifc_window::clientToScreen(int *x, int *y) {
+ _voidcall(CLIENTSCREEN, x, y);
+}
+
+inline void ifc_window::screenToClient(int *x, int *y) {
+ _voidcall(SCREENCLIENT, x, y);
+}
+
+inline int ifc_window::init(ifc_window *parent, int nochild) {
+ return _call(INIT, 0, parent, nochild);
+}
+
+inline int ifc_window::isInited() {
+ return _call(ISINITED, 0);
+}
+
+inline int ifc_window::isPostOnInit() {
+ return _call(ISPOSTONINIT, 0);
+}
+
+inline int ifc_window::setVirtual(int i) {
+ return _call(SETVIRTUAL, 0, i);
+}
+
+inline int ifc_window::getCursorType(int x, int y) {
+ return _call(GETCURSORTYPE, 0, x, y);
+}
+
+inline OSCURSORHANDLE ifc_window::getCustomCursor(int x, int y) {
+ return _call(GETCUSTOMCURSOR, (OSCURSORHANDLE)NULL, x, y);
+}
+
+inline void ifc_window::getClientRect(RECT *r) {
+ _voidcall(GETCLIENTRECT, r);
+}
+
+inline void ifc_window::getNonClientRect(RECT *rect) {
+ _voidcall(GETNONCLIENTRECT, rect);
+}
+
+inline void ifc_window::getPosition(POINT *pt) {
+ _voidcall(GETPOSITION, pt);
+}
+
+inline void ifc_window::setVisible(int show) {
+ _voidcall(SETVISIBLE, show);
+}
+
+inline void ifc_window::setCloaked(int cloak) {
+ _voidcall(SETCLOAKED, cloak);
+}
+
+inline void ifc_window::onSetVisible(int show) {
+ _voidcall(ONSETVISIBLE, show);
+}
+
+inline void ifc_window::invalidate() {
+ _voidcall(INVALIDATE);
+}
+
+inline void ifc_window::invalidateRect(RECT *r) {
+ _voidcall(INVALIDATERECT, r);
+}
+
+inline void ifc_window::invalidateRgn(api_region *r) {
+ _voidcall(INVALIDATERGN, r);
+}
+
+inline void ifc_window::onChildInvalidate(api_region *r, ifc_window *who) {
+ _voidcall(ONCHILDINVALIDATE, r, who);
+}
+
+inline void ifc_window::invalidateFrom(ifc_window *who) {
+ _voidcall(INVALIDATEFROM, who);
+}
+
+inline void ifc_window::invalidateRectFrom(RECT *r, ifc_window *who) {
+ _voidcall(INVALIDATERECTFROM, r, who);
+}
+
+inline void ifc_window::invalidateRgnFrom(api_region *r, ifc_window *who) {
+ _voidcall(INVALIDATERGNFROM, r, who);
+}
+
+inline void ifc_window::validate() {
+ _voidcall(VALIDATE);
+}
+
+inline void ifc_window::validateRect(RECT *r) {
+ _voidcall(VALIDATERECT, r);
+}
+
+inline void ifc_window::validateRgn(api_region *reg) {
+ _voidcall(VALIDATERGN, reg);
+}
+
+inline int ifc_window::onSiblingInvalidateRgn(api_region *r, ifc_window *who, int who_idx, int my_idx) {
+ return _call(ONSIBINVALIDATE, 0, r, who, who_idx, my_idx);
+}
+
+inline int ifc_window::wantSiblingInvalidations() {
+ return _call(WANTSIBINVALIDATE, 0);
+}
+
+inline int ifc_window::cascadeRepaintFrom(ifc_window *who, int pack) {
+ return _call(CASCADEREPAINTFROM, 0, who, pack);
+}
+
+inline int ifc_window::cascadeRepaintRgnFrom(api_region *reg, ifc_window *who, int pack) {
+ return _call(CASCADEREPAINTRGNFROM, 0, reg, who, pack);
+}
+
+inline int ifc_window::cascadeRepaintRectFrom(RECT *r, ifc_window *who, int pack) {
+ return _call(CASCADEREPAINTRECTFROM, 0, r, who, pack);
+}
+
+inline int ifc_window::cascadeRepaint(int pack) {
+ return _call(CASCADEREPAINT, 0, pack);
+}
+
+inline int ifc_window::cascadeRepaintRgn(api_region *reg, int pack) {
+ return _call(CASCADEREPAINTRGN, 0, reg, pack);
+}
+
+inline int ifc_window::cascadeRepaintRect(RECT *r, int pack) {
+ return _call(CASCADEREPAINTRECT, 0, r, pack);
+}
+
+inline void ifc_window::repaint() {
+ _voidcall(REPAINT);
+}
+
+inline ifc_window *ifc_window::getBaseTextureWindow() {
+ return _call(GETTEXTUREWND, (ifc_window *)0);
+}
+
+inline int ifc_window::onActivate() {
+ return _call(ONACTIVATE, 0);
+}
+
+inline void ifc_window::activate() {
+ _voidcall(ACTIVATE);
+}
+
+inline int ifc_window::onDeactivate() {
+ return _call(ONDEACTIVATE, 0);
+}
+
+inline int ifc_window::isActive() {
+ return _call(ISACTIVATED, 0);
+}
+
+inline api_region *ifc_window::getRegion() {
+ return _call(GETREGION, (api_region *)NULL);
+}
+
+inline int ifc_window::handleTransparency() {
+ return _call(HANDLETRANSPARENCY, 0);
+}
+
+inline int ifc_window::handleDesktopAlpha() {
+ return _call(HANDLEDESKTOPALPHA, 0);
+}
+
+inline void ifc_window::setStartHidden(int sh) {
+ _voidcall(SETSTARTHIDDEN, sh);
+}
+
+inline double ifc_window::getRenderRatio() {
+ return _call(GETRENDERRATIO, 1.0);
+}
+
+inline void ifc_window::setRenderRatio(double r) {
+ _voidcall(SETRENDERRATIO, r);
+}
+
+inline void ifc_window::setRatioLinked(int l) {
+ _voidcall(SETRATIOLINKED, l);
+}
+
+inline int ifc_window::handleRatio() {
+ return _call(HANDLERATIO, 0);
+}
+
+inline void ifc_window::resize(int x, int y, int w, int h, int wantcb) {
+ _voidcall(_RESIZE, x, y, w, h, wantcb);
+}
+
+inline void ifc_window::move(int x, int y) {
+ _voidcall(_MOVE, x, y);
+}
+
+inline void ifc_window::notifyDeferredMove(int x, int y) {
+ _voidcall(NOTIFYDEFERREDMOVE, x, y);
+}
+
+inline int ifc_window::checkDoubleClick(int button, int x, int y) {
+ return _call(CHECKDBLCLK, 0, button, x, y);
+}
+
+inline void ifc_window::registerRootWndChild(ifc_window *child) {
+ _voidcall(REGISTERROOTWNDCHILD, child);
+}
+
+inline void ifc_window::unregisterRootWndChild(ifc_window *child) {
+ _voidcall(UNREGISTERROOTWNDCHILD, child);
+}
+
+inline ifc_window *ifc_window::findRootWndChild(int x, int y, int only_virtuals) {
+ return _call(FINDROOTWNDCHILD, (ifc_window *)NULL, x, y, only_virtuals);
+}
+
+inline ifc_window *ifc_window::enumRootWndChildren(int _enum) {
+ return _call(ENUMROOTWNDCHILDREN, (ifc_window *)NULL, _enum);
+}
+
+inline int ifc_window::getNumRootWndChildren() {
+ return _call(GETNUMROOTWNDCHILDREN, 0);
+}
+
+inline int ifc_window::isVirtual() {
+ return _call(ISVIRTUAL, 0);
+}
+
+inline void ifc_window::bringVirtualToFront(ifc_window *w) {
+ _voidcall(BRINGVTOFRONT, w);
+}
+
+inline void ifc_window::bringVirtualToBack(ifc_window *w) {
+ _voidcall(BRINGVTOBACK, w);
+}
+
+inline void ifc_window::bringVirtualAbove(ifc_window *w, ifc_window *b) {
+ _voidcall(BRINGVABOVE, w, b);
+}
+
+inline void ifc_window::bringVirtualBelow(ifc_window *w, ifc_window *b) {
+ _voidcall(BRINGVBELOW, w, b);
+}
+
+inline void ifc_window::setVirtualChildCapture(ifc_window *child) {
+ _voidcall(SETVCAPTURE, child);
+}
+
+inline ifc_window *ifc_window::getVirtualChildCapture() {
+ return _call(GETVCAPTURE, (ifc_window *)NULL);
+}
+
+inline bool ifc_window::ptInRegion(int x, int y) {
+ return _call(PTINREGION, (bool)false, x, y);
+}
+
+inline int ifc_window::onLeftButtonDblClk(int x, int y) {
+ return _call(ONLBDBLCLK, 0, x, y);
+}
+
+inline int ifc_window::onRightButtonDblClk(int x, int y) {
+ return _call(ONRBDBLCLK, 0, x, y);
+}
+
+inline int ifc_window::onLeftButtonUp(int x, int y) {
+ return _call(ONLBUP, 0, x, y);
+}
+
+inline int ifc_window::onRightButtonUp(int x, int y) {
+ return _call(ONRBUP, 0, x, y);
+}
+
+inline int ifc_window::onLeftButtonDown(int x, int y) {
+ return _call(ONLBDOWN, 0, x, y);
+}
+
+inline int ifc_window::onRightButtonDown(int x, int y) {
+ return _call(ONRBDOWN, 0, x, y);
+}
+
+inline int ifc_window::onMouseMove(int x, int y) {
+ return _call(ONMOUSEMOVE, 0, x, y);
+}
+
+inline int ifc_window::getNotifyId() {
+ return _call(GETNOTIFYID, 0);
+}
+
+inline void *ifc_window::getInterface(GUID interface_guid) {
+ return _call(GETINTERFACE, (void *)NULL, interface_guid);
+}
+
+inline void ifc_window::setEnabled(int e) {
+ _voidcall(SETENABLED, e);
+}
+
+inline int ifc_window::isEnabled(int within) {
+ return _call(ISENABLED, 0, within);
+}
+
+inline int ifc_window::onEnable(int e) {
+ return _voidcall(ONENABLE, e);
+}
+
+inline void ifc_window::setAlpha(int activealpha, int inactivealpha) {
+ _voidcall(SETALPHA, activealpha, inactivealpha);
+}
+
+inline void ifc_window::getAlpha(int *active, int *inactive) {
+ _voidcall(GETALPHA, active, inactive);
+}
+
+inline int ifc_window::getPaintingAlpha() {
+ return _call(GETPAINTALPHA, 255);
+}
+
+inline void ifc_window::setTip(const wchar_t *tip) {
+ _voidcall(SETTOOLTIP, tip);
+}
+
+inline int ifc_window::runModal() {
+ return _call(RUNMODAL, 0);
+}
+
+inline void ifc_window::endModal(int retcode) {
+ _voidcall(ENDMODAL, retcode);
+}
+
+inline int ifc_window::wantAutoContextMenu() {
+ return _call(WANTAUTOCONTEXTMENU, 0);
+}
+
+inline int ifc_window::wantActivation() {
+ return _call(WANTACTIVATION, 1);
+}
+
+inline void ifc_window::bringToFront() {
+ _voidcall(BRINGTOFRONT);
+}
+
+inline void ifc_window::bringToBack() {
+ _voidcall(BRINGTOBACK);
+}
+
+inline void ifc_window::setFocus() {
+ _voidcall(SETFOCUS);
+}
+
+inline int ifc_window::gotFocus() {
+ return _call(GOTFOCUS, 0);
+}
+
+inline int ifc_window::onGetFocus() {
+ return _call(ONGETFOCUS, 0);
+}
+
+inline int ifc_window::onKillFocus() {
+ return _call(ONKILLFOCUS, 0);
+}
+
+inline ifc_window *ifc_window::getNextVirtualFocus(ifc_window *cur) {
+ return _call(GETNEXTVFOCUS, (ifc_window *)NULL, cur);
+}
+
+inline int ifc_window::wantFocus() {
+ return _call(WANTFOCUS, 0);
+}
+
+inline int ifc_window::onAcceleratorEvent(const wchar_t *name) {
+ return _call(ONACCELERATOREVENT, 0, name);
+}
+
+inline int ifc_window::onChar(unsigned int c) {
+ return _call(ONCHAR, 0, c);
+}
+
+inline int ifc_window::onKeyDown(int keycode) {
+ return _call(ONKEYDOWN, 0, keycode);
+}
+
+inline int ifc_window::onKeyUp(int keycode) {
+ return _call(ONKEYUP, 0, keycode);
+}
+
+inline int ifc_window::onSysKeyDown(int keycode, int keydata) {
+ return _call(ONSYSKEYDOWN, 0, keycode, keydata);
+}
+
+inline int ifc_window::onSysKeyUp(int keycode, int keydata) {
+ return _call(ONSYSKEYUP, 0, keycode, keydata);
+}
+
+inline void ifc_window::setVirtualChildFocus(ifc_window *w) {
+ _voidcall(SETVFOCUS, w);
+}
+
+inline int ifc_window::getRegionOp() {
+ return _call(GETREGIONOP, 0);
+}
+
+inline void ifc_window::invalidateWindowRegion() {
+ _voidcall(INVALWNDRGN);
+}
+
+inline api_region *ifc_window::getComposedRegion() {
+ return _call(GETCOMPOSEDRGN, (api_region *)NULL);
+}
+
+inline api_region *ifc_window::getSubtractorRegion() {
+ return _call(GETSUBTRACTORRGN, (api_region *)NULL);
+}
+
+inline void ifc_window::setRegionOp(int op) {
+ _voidcall(SETREGIONOP, op);
+}
+
+inline void ifc_window::setRectRgn(int rrgn) {
+ _voidcall(SETRECTRGN, rrgn);
+}
+
+inline int ifc_window::isRectRgn() {
+ return _call(ISRECTRGN, 0);
+}
+
+inline TimerClient *ifc_window::getTimerClient() {
+ return _call(GETTIMERCLIENT, (TimerClient *)NULL);
+}
+
+inline ifc_dependent *ifc_window::getDependencyPtr() {
+ return _call(GETDEPENDENCYPTR, (ifc_dependent *)NULL);
+}
+
+inline void ifc_window::addMinMaxEnforcer(ifc_window *w) {
+ _voidcall(ADDMINMAXENFORCER, w);
+}
+
+inline void ifc_window::removeMinMaxEnforcer(ifc_window *w) {
+ _voidcall(REMOVEMINMAXENFORCER, w);
+}
+
+inline ifc_window *ifc_window::enumMinMaxEnforcer(int n) {
+ return _call(ENUMMINMAXENFORCER, (ifc_window *)NULL, n);
+}
+
+inline int ifc_window::getNumMinMaxEnforcers() {
+ return _call(GETNUMMINMAXENFORCERS, 0);
+}
+
+inline void ifc_window::signalMinMaxEnforcerChanged() {
+ _voidcall(SIGNALMINMAXCHANGED, 0);
+}
+
+inline int ifc_window::onAction(const wchar_t *action, const wchar_t *param, int x, int y, intptr_t p1, intptr_t p2, void *data, size_t datalen, ifc_window *source) {
+ return _call(ROOTWNDONACTION, 0, action, param, x, y, p1, p2, data, datalen, source);
+}
+
+inline void ifc_window::setRenderBaseTexture(int i) {
+ _voidcall(SETRENDERBASETEXTURE, i);
+}
+
+inline int ifc_window::getRenderBaseTexture() {
+ return _call(GETRENDERBASETEXTURE, 0);
+}
+
+inline void ifc_window::renderBaseTexture(ifc_canvas *c, const RECT *r, int alpha)
+{
+ _voidcall(RENDERBASETEXTURE, c, r, alpha);
+}
+
+inline GuiObject *ifc_window::getGuiObject() {
+ return _call(GETGUIOBJECT, (GuiObject *) NULL);
+}
+
+inline int ifc_window::triggerEvent(int event, intptr_t p1, intptr_t p2) {
+ return _call(TRIGGEREVENT, 0, event, p1, p2);
+}
+
+inline int ifc_window::getFlag(int flag) {
+ return _call(GETFLAG, 0, flag);
+}
+
+inline int ifc_window::allowDeactivation() {
+ return _call(ALLOWDEACTIVATE, 1);
+}
+
+inline void ifc_window::setAllowDeactivation(int allow) {
+ _voidcall(SETALLOWDEACTIVATE, allow);
+}
+
+inline ifc_window *ifc_window::findWindow(const wchar_t *id) {
+ return _call(FINDWND_BYID, (ifc_window *)NULL, id);
+}
+
+inline ifc_window *ifc_window::findWindowByInterface(GUID interface_guid) {
+ return _call(FINDWND_BYGUID, (ifc_window *)NULL, interface_guid);
+}
+
+inline ifc_window *ifc_window::findWindowByCallback(FindObjectCallback *cb) {
+ return _call(FINDWND_BYCB, (ifc_window *)NULL, cb);
+}
+
+inline ifc_window *ifc_window::findWindowChain(FindObjectCallback *cb, ifc_window *wcaller) {
+ return _call(FINDWNDCHAIN, (ifc_window *)NULL, cb, wcaller);
+}
+
+inline void ifc_window::setTabOrder(int a) {
+ _voidcall(SETTABORDER, a);
+}
+
+inline int ifc_window::getTabOrder() {
+ return _call(GETTABORDER, -1);
+}
+
+inline void ifc_window::setAutoTabOrder() {
+ _voidcall(SETAUTOTABORDER, 0);
+}
+
+inline void ifc_window::setVirtualTabOrder(ifc_window *w, int a) {
+ _voidcall(SETVIRTUALTABORDER, w, a);
+}
+
+inline int ifc_window::getVirtualTabOrder(ifc_window *w) {
+ return _call(GETVIRTUALTABORDER, 0, w);
+}
+
+inline void ifc_window::setVirtualAutoTabOrder(ifc_window *w) {
+ _voidcall(SETVIRTUALAUTOTABORDER, w);
+}
+
+inline ifc_window *ifc_window::getCurVirtualChildFocus() {
+ return _call(GETCURVIRTUALCHILDFOCUS, (ifc_window *)NULL);
+}
+
+inline ifc_window *ifc_window::getTab(int what) {
+ return _call(GETTAB, (ifc_window *)NULL, what);
+}
+
+inline void ifc_window::focusNext() {
+ _voidcall(FOCUSNEXT);
+}
+
+inline void ifc_window::focusPrevious() {
+ _voidcall(FOCUSPREVIOUS);
+}
+
+inline void ifc_window::setWindowTitle(const wchar_t *title){
+ _voidcall(SETWINDOWTITLE, title);
+}
+inline int ifc_window::getNumTabs() {
+ return _call(GETNUMTABS, 0);
+}
+
+inline ifc_window *ifc_window::enumTab(int i) {
+ return _call(ENUMTAB, (ifc_window *)NULL, i);
+}
+
+inline void ifc_window::onSetRootFocus(ifc_window *w) {
+ _voidcall(ONSETROOTFOCUS, w);
+}
+
+inline int ifc_window::getFocusOnClick() {
+ return _call(GETFOCUSONCLICK, 0);
+}
+
+inline void ifc_window::setFocusOnClick(int i) {
+ _voidcall(SETFOCUSONCLICK, i);
+}
+
+inline void ifc_window::setNoDoubleClicks(int no) {
+ _voidcall(SETNODOUBLECLICKS, no);
+}
+
+inline void ifc_window::setNoLeftClicks(int no) {
+ _voidcall(SETNOLEFTCLICKS, no);
+}
+
+inline void ifc_window::setNoRightClicks(int no) {
+ _voidcall(SETNORIGHTCLICKS, no);
+}
+
+inline void ifc_window::setNoMouseMoves(int no) {
+ _voidcall(SETNOMOUSEMOVES, no);
+}
+
+inline void ifc_window::setNoContextMenus(int no) {
+ _voidcall(SETNOCONTEXTMENUS, no);
+}
+
+inline int ifc_window::wantDoubleClicks() {
+ return _call(WANTDOUBLECLICKS, 1);
+}
+
+inline int ifc_window::wantRightClicks() {
+ return _call(WANTLEFTCLICKS, 1);
+}
+
+inline int ifc_window::wantLeftClicks() {
+ return _call(WANTRIGHTCLICKS, 1);
+}
+
+inline int ifc_window::wantMouseMoves() {
+ return _call(WANTMOUSEMOVES, 1);
+}
+
+inline int ifc_window::wantContextMenus() {
+ return _call(WANTCONTEXTMENUS, 1);
+}
+
+inline void ifc_window::setDefaultCursor(Cursor *c) {
+ _voidcall(SETDEFAULTCURSOR, c);
+}
+
+inline Accessible *ifc_window::getAccessibleObject(int createifnotexist) {
+ return _call(GETACCESSIBLEOBJECT, (Accessible*)NULL, createifnotexist);
+}
+
+
+inline int ifc_window::accessibility_getState() {
+ return _call(ACCGETSTATE, 0);
+}
+
+#ifdef EXPERIMENTAL_INDEPENDENT_AOT
+inline void ifc_window::setAlwaysOnTop(int i) {
+ _voidcall(SETALWAYSONTOP, i);
+}
+
+inline int ifc_window::getAlwaysOnTop() {
+ return _call(GETALWAYSONTOP, 0);
+}
+#endif
+
+#ifndef WA3COMPATIBILITY
+inline void ifc_window::setDropTarget(void *dt) {
+ _voidcall(SETDROPTARGET, dt);
+}
+
+inline void *ifc_window::getDropTarget() {
+ return _call(GETDROPTARGET, (void *)NULL);
+}
+#endif
+
+inline int ifc_window::isMinimized() {
+ return _call(ISMINIMIZED, 0);
+}
+
+inline void ifc_window::maximize(int axis) {
+ _voidcall(MAXIMIZE, axis);
+}
+
+inline void ifc_window::restore(int what) {
+ _voidcall(RESTORE, what);
+}
+
+inline int ifc_window::getRestoredRect(RECT *r)
+{
+ return _call(GETRESTOREDRECT, 0, r);
+}
+
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/api_wnd.cpp b/Src/Wasabi/api/wnd/api_wnd.cpp
new file mode 100644
index 00000000..50d2f455
--- /dev/null
+++ b/Src/Wasabi/api/wnd/api_wnd.cpp
@@ -0,0 +1,57 @@
+#include "precomp.h"
+#include "api_wnd.h"
+
+#define CBCLASS wnd_apiI
+START_DISPATCH;
+VCB(API_WND_SETROOTWND, main_setRootWnd);
+CB(API_WND_GETROOTWND, main_getRootWnd);
+CB(API_WND_GETMODALWND, getModalWnd);
+VCB(API_WND_PUSHMODALWND, popModalWnd);
+VCB(API_WND_POPMODALWND, popModalWnd);
+CB(API_WND_ROOTWNDFROMPOINT, rootWndFromPoint);
+VCB(API_WND_REGISTERROOTWND, registerRootWnd);
+VCB(API_WND_UNREGISTERROOTWND, unregisterRootWnd);
+CB(API_WND_ROOTWNDISVALID, rootwndIsValid);
+CB(API_WND_INTERCEPTONCHAR, interceptOnChar);
+CB(API_WND_INTERCEPTONKEYDOWN, interceptOnKeyDown);
+CB(API_WND_INTERCEPTONKEYUP, interceptOnKeyUp);
+CB(API_WND_INTERCEPTONSYSKEYDOWN, interceptOnSysKeyDown);
+CB(API_WND_INTERCEPTONSYSKEYUP, interceptOnSysKeyUp);
+VCB(API_WND_HOOKKEYBOARD, hookKeyboard);
+VCB(API_WND_UNHOOKKEYBOARD, unhookKeyboard);
+VCB(API_WND_KBDRESET, kbdReset);
+CB(API_WND_FORWARDONCHAR, forwardOnChar);
+CB(API_WND_FORWARDONKEYDOWN, forwardOnKeyDown);
+CB(API_WND_FORWARDONKEYUP, forwardOnKeyUp);
+CB(API_WND_FORWARDONSYSKEYDOWN, forwardOnSysKeyDown);
+CB(API_WND_FORWARDONSYSKEYUP, forwardOnSysKeyUp);
+CB(API_WND_FORWARDONKILLFOCUS, forwardOnKillFocus);
+CB(API_WND_POPUPEXIT_CHECK, popupexit_check);
+VCB(API_WND_POPUPEXIT_SIGNAL, popupexit_signal);
+VCB(API_WND_POPUPEXIT_REGISTER, popupexit_register);
+VCB(API_WND_POPUPEXIT_DEREGISTER, popupexit_deregister);
+VCB(API_WND_RENDERBASETEXTURE, skin_renderBaseTexture);
+VCB(API_WND_REGISTERBASETEXTUREWINDOW, skin_registerBaseTextureWindow);
+VCB(API_WND_UNREGISTERBASETEXTUREWINDOW, skin_unregisterBaseTextureWindow);
+VCB(API_WND_APPDEACTIVATION_PUSH_DISALLOW, appdeactivation_push_disallow);
+VCB(API_WND_APPDEACTIVATION_POP_DISALLOW, appdeactivation_pop_disallow);
+CB(API_WND_APPDEACTIVATION_ISALLOWED, appdeactivation_isallowed);
+VCB(API_WND_APPDEACTIVATION_SETBYPASS, appdeactivation_setbypass);
+CB(API_WND_FORWARDONMOUSEWHEEL, forwardOnMouseWheel);
+#ifdef WASABI_COMPILE_PAINTSETS
+CB(API_WND_PAINTSET_PRESENT, paintset_present );
+#ifdef WASABI_COMPILE_IMGLDR
+VCB(API_WND_PAINTSET_RENDER, paintset_render);
+#ifdef WASABI_COMPILE_FONTS
+VCB(API_WND_PAINTSET_RENDERTITLE, paintset_renderTitle);
+#endif // fonts
+#endif // imgldr
+#endif // paintsets
+// fg> this may need to go away eventually but i need it _right now_
+VCB(API_WND_SETDEFAULTDROPTARGET, setDefaultDropTarget);
+CB(API_WND_GETDEFAULTDROPTARGET, getDefaultDropTarget);
+CB(API_WND_PUSHKBDLOCK, pushKeyboardLock);
+CB(API_WND_POPKBDLOCK, popKeyboardLock);
+CB(API_WND_ISKBDLOCKED, isKeyboardLocked);
+CB(API_WND_ROOTWNDFROMOSHANDLE, rootWndFromOSHandle);
+END_DISPATCH;
diff --git a/Src/Wasabi/api/wnd/api_wnd.h b/Src/Wasabi/api/wnd/api_wnd.h
new file mode 100644
index 00000000..ce72cd8c
--- /dev/null
+++ b/Src/Wasabi/api/wnd/api_wnd.h
@@ -0,0 +1,390 @@
+#ifndef __API_WND_H
+#define __API_WND_H
+
+#include <wasabicfg.h>
+#include <bfc/dispatch.h>
+#include <bfc/platform/platform.h>
+class ifc_window;
+class PopupExitCallback; // see ../bfc/popexitcb.h
+class ifc_canvas; // see ../common/canvas.h
+class CfgItem;
+
+#ifndef MODALWND_DEF
+#define MODALWND_DEF
+ifc_window *const MODALWND_NOWND = reinterpret_cast<ifc_window*>(-1);
+#endif
+
+class wnd_api : public Dispatchable
+{
+ public:
+
+ // the master window
+ /**
+ Get the main root window.
+
+ @ret Main root window.
+ */
+ ifc_window *main_getRootWnd();
+ void main_setRootWnd(ifc_window *w);
+ /**
+ Get the modal window on top of the
+ modal window stack.
+
+ @ret Window that's currently modal.
+ */
+ ifc_window *getModalWnd();
+ /**
+ Push a window onto the modal stack. If
+ the window is on top of the stack, it's
+ currently modal.
+
+ @param w Window to push onto the modal stack.
+ */
+ void pushModalWnd(ifc_window *w=MODALWND_NOWND);
+
+ /**
+ Pop a window from the modal stack. If
+ the window is on top of the stack, it
+ will no longer be modal after this call.
+
+ @param w Window to pop from the modal stack.
+ */
+ void popModalWnd(ifc_window *w=MODALWND_NOWND);
+ ifc_window *rootWndFromPoint(POINT *pt);
+ ifc_window *rootWndFromOSHandle(OSWINDOWHANDLE wnd);
+ void registerRootWnd(ifc_window *wnd);
+ void unregisterRootWnd(ifc_window *wnd);
+ int rootwndIsValid(ifc_window *wnd);
+ void hookKeyboard(ifc_window *hooker);
+ void unhookKeyboard(ifc_window *hooker);
+ void kbdReset();
+ int interceptOnChar(unsigned int c);
+ int interceptOnKeyDown(int k);
+ int interceptOnKeyUp(int k);
+ int interceptOnSysKeyDown(int k, int kd);
+ int interceptOnSysKeyUp(int k, int kd);
+ int forwardOnChar(ifc_window *from, unsigned int c, int kd);
+ int forwardOnKeyDown(ifc_window *from, int k, int kd);
+ int forwardOnKeyUp(ifc_window *from, int k, int kd);
+ int forwardOnSysKeyDown(ifc_window *from, int k, int kd);
+ int forwardOnSysKeyUp(ifc_window *from, int k, int kd);
+ int forwardOnKillFocus();
+ int pushKeyboardLock();
+ int popKeyboardLock();
+ int isKeyboardLocked();
+ void popupexit_deregister(PopupExitCallback *cb);
+ void popupexit_register(PopupExitCallback *cb, ifc_window *watched);
+ int popupexit_check(ifc_window *w);
+ void popupexit_signal();
+#define RenderBaseTexture renderBaseTexture //CUT
+ void skin_renderBaseTexture(ifc_window *base, ifc_canvas *c, const RECT &r, ifc_window *destWnd, int alpha=255);
+ void skin_registerBaseTextureWindow(ifc_window *window, const wchar_t *bmp=NULL);
+ void skin_unregisterBaseTextureWindow(ifc_window *window);
+ void appdeactivation_push_disallow(ifc_window *w);
+ void appdeactivation_pop_disallow(ifc_window *w);
+ int appdeactivation_isallowed(ifc_window *w);
+ void appdeactivation_setbypass(int i);
+ int paintset_present(int set);
+ void paintset_render(int set, ifc_canvas *c, const RECT *r, int alpha=255);
+ void paintset_renderTitle(const wchar_t *t, ifc_canvas *c, const RECT *r, int alpha=255);
+ int forwardOnMouseWheel(int l, int a);
+ void setDefaultDropTarget(void *dt);
+ void *getDefaultDropTarget();
+
+ enum {
+ API_WND_GETROOTWND = 10,
+ API_WND_SETROOTWND = 20,
+ API_WND_GETMODALWND = 30,
+ API_WND_PUSHMODALWND = 40,
+ API_WND_POPMODALWND = 50,
+ API_WND_ROOTWNDFROMPOINT = 60,
+ API_WND_ROOTWNDFROMOSHANDLE = 65,
+ API_WND_REGISTERROOTWND = 70,
+ API_WND_UNREGISTERROOTWND = 80,
+ API_WND_ROOTWNDISVALID = 90,
+ API_WND_INTERCEPTONCHAR = 100,
+ API_WND_INTERCEPTONKEYDOWN = 110,
+ API_WND_INTERCEPTONKEYUP = 120,
+ API_WND_INTERCEPTONSYSKEYDOWN = 130,
+ API_WND_INTERCEPTONSYSKEYUP = 140,
+ API_WND_HOOKKEYBOARD = 150,
+ API_WND_UNHOOKKEYBOARD = 160,
+ API_WND_KBDRESET = 165,
+ API_WND_FORWARDONCHAR = 170,
+ API_WND_FORWARDONKEYDOWN = 180,
+ API_WND_FORWARDONKEYUP = 190,
+ API_WND_FORWARDONSYSKEYDOWN = 200,
+ API_WND_FORWARDONSYSKEYUP = 210,
+ API_WND_FORWARDONKILLFOCUS = 220,
+ API_WND_POPUPEXIT_CHECK = 230,
+ API_WND_POPUPEXIT_SIGNAL = 240,
+ API_WND_POPUPEXIT_REGISTER = 250,
+ API_WND_POPUPEXIT_DEREGISTER = 260,
+ API_WND_RENDERBASETEXTURE = 270,
+ API_WND_REGISTERBASETEXTUREWINDOW = 280,
+ API_WND_UNREGISTERBASETEXTUREWINDOW = 290,
+ API_WND_APPDEACTIVATION_PUSH_DISALLOW = 300,
+ API_WND_APPDEACTIVATION_POP_DISALLOW = 310,
+ API_WND_APPDEACTIVATION_ISALLOWED = 320,
+ API_WND_APPDEACTIVATION_SETBYPASS = 330,
+ API_WND_PAINTSET_PRESENT = 335,
+ API_WND_PAINTSET_RENDER = 340,
+ API_WND_PAINTSET_RENDERTITLE = 350,
+ API_WND_FORWARDONMOUSEWHEEL = 360,
+ // fg> this may need to go away eventually but i need it _right now_
+ API_WND_SETDEFAULTDROPTARGET = 370,
+ API_WND_GETDEFAULTDROPTARGET = 380,
+ API_WND_PUSHKBDLOCK = 390,
+ API_WND_POPKBDLOCK = 400,
+ API_WND_ISKBDLOCKED = 410,
+ };
+};
+
+
+inline ifc_window *wnd_api::main_getRootWnd() {
+ return _call(API_WND_GETROOTWND, (ifc_window *)0 );
+}
+
+inline void wnd_api::main_setRootWnd(ifc_window *w) {
+ _voidcall(API_WND_SETROOTWND, w );
+}
+
+inline ifc_window *wnd_api::getModalWnd() {
+ return _call(API_WND_GETMODALWND, (ifc_window *)0 );
+}
+
+inline void wnd_api::pushModalWnd(ifc_window *w) {
+ _voidcall(API_WND_PUSHMODALWND, w);
+}
+
+inline void wnd_api::popModalWnd(ifc_window *w) {
+ _voidcall(API_WND_POPMODALWND, w);
+}
+
+inline ifc_window *wnd_api::rootWndFromPoint(POINT *pt) {
+ return _call(API_WND_ROOTWNDFROMPOINT, (ifc_window *)0, pt );
+}
+
+inline ifc_window *wnd_api::rootWndFromOSHandle(OSWINDOWHANDLE wnd) {
+ return _call(API_WND_ROOTWNDFROMOSHANDLE, (ifc_window *)0, wnd);
+}
+
+inline void wnd_api::registerRootWnd(ifc_window *wnd) {
+ _voidcall(API_WND_REGISTERROOTWND, wnd );
+}
+
+inline void wnd_api::unregisterRootWnd(ifc_window *wnd) {
+ _voidcall(API_WND_UNREGISTERROOTWND, wnd );
+}
+
+inline int wnd_api::rootwndIsValid(ifc_window *wnd) {
+ return _call(API_WND_ROOTWNDISVALID, (int)0, wnd );
+}
+
+inline int wnd_api::interceptOnChar(unsigned int c) {
+ return _call(API_WND_INTERCEPTONCHAR, (int)0, c );
+}
+
+inline int wnd_api::interceptOnKeyDown(int k) {
+ return _call(API_WND_INTERCEPTONKEYDOWN, (int)0, k );
+}
+
+inline int wnd_api::interceptOnKeyUp(int k) {
+ return _call(API_WND_INTERCEPTONKEYUP, (int)0, k );
+}
+
+inline int wnd_api::interceptOnSysKeyDown(int k, int kd) {
+ return _call(API_WND_INTERCEPTONSYSKEYDOWN, (int)0, k , kd );
+}
+
+inline int wnd_api::interceptOnSysKeyUp(int k, int kd) {
+ return _call(API_WND_INTERCEPTONSYSKEYUP, (int)0, k , kd );
+}
+
+inline void wnd_api::hookKeyboard(ifc_window *hooker) {
+ _voidcall(API_WND_HOOKKEYBOARD, hooker);
+}
+
+inline void wnd_api::unhookKeyboard(ifc_window *hooker) {
+ _voidcall(API_WND_UNHOOKKEYBOARD, hooker);
+}
+
+inline void wnd_api::kbdReset() {
+ _voidcall(API_WND_KBDRESET);
+}
+
+inline int wnd_api::forwardOnChar(ifc_window *from, unsigned int c, int kd) {
+ return _call(API_WND_FORWARDONCHAR, (int)0, from, c, kd );
+}
+
+inline int wnd_api::forwardOnKeyDown(ifc_window *from, int k, int kd) {
+ return _call(API_WND_FORWARDONKEYDOWN, (int)0, from, k, kd);
+}
+
+inline int wnd_api::forwardOnKeyUp(ifc_window *from, int k, int kd) {
+ return _call(API_WND_FORWARDONKEYUP, (int)0, from, k, kd );
+}
+
+inline int wnd_api::forwardOnSysKeyDown(ifc_window *from, int k, int kd) {
+ return _call(API_WND_FORWARDONSYSKEYDOWN, (int)0, from, k , kd );
+}
+
+inline int wnd_api::forwardOnSysKeyUp(ifc_window *from, int k, int kd) {
+ return _call(API_WND_FORWARDONSYSKEYUP, (int)0, from, k , kd );
+}
+
+inline int wnd_api::forwardOnKillFocus() {
+ return _call(API_WND_FORWARDONKILLFOCUS, (int)0 );
+}
+
+inline int wnd_api::popupexit_check(ifc_window *w) {
+ return _call(API_WND_POPUPEXIT_CHECK, 0, w);
+}
+
+inline void wnd_api::popupexit_signal() {
+ _voidcall(API_WND_POPUPEXIT_SIGNAL);
+}
+
+inline void wnd_api::popupexit_register(PopupExitCallback *cb, ifc_window *watched) {
+ _voidcall(API_WND_POPUPEXIT_REGISTER, cb, watched);
+}
+
+inline void wnd_api::popupexit_deregister(PopupExitCallback *cb) {
+ _voidcall(API_WND_POPUPEXIT_DEREGISTER, cb);
+}
+
+#define RenderBaseTexture renderBaseTexture //CUT
+
+inline void wnd_api::skin_renderBaseTexture(ifc_window *base, ifc_canvas *c, const RECT &r, ifc_window *destWnd, int alpha) {
+ _voidcall(API_WND_RENDERBASETEXTURE, base, c, &r, destWnd, alpha );
+}
+
+inline void wnd_api::skin_registerBaseTextureWindow(ifc_window *window, const wchar_t *bmp) {
+ _voidcall(API_WND_REGISTERBASETEXTUREWINDOW, window, bmp);
+}
+
+inline void wnd_api::skin_unregisterBaseTextureWindow(ifc_window *window) {
+ _voidcall(API_WND_UNREGISTERBASETEXTUREWINDOW, window );
+}
+
+inline void wnd_api::appdeactivation_push_disallow(ifc_window *w) {
+ _voidcall(API_WND_APPDEACTIVATION_PUSH_DISALLOW, w);
+}
+
+inline void wnd_api::appdeactivation_pop_disallow(ifc_window *w) {
+ _voidcall(API_WND_APPDEACTIVATION_POP_DISALLOW, w);
+}
+
+inline int wnd_api::appdeactivation_isallowed(ifc_window *w) {
+ return _call(API_WND_APPDEACTIVATION_ISALLOWED, 0, w);
+}
+
+inline void wnd_api::appdeactivation_setbypass(int i) {
+ _voidcall(API_WND_APPDEACTIVATION_SETBYPASS, i);
+}
+
+inline int wnd_api::paintset_present(int set)
+{
+ return _call(API_WND_PAINTSET_PRESENT, 0, set);
+}
+
+inline void wnd_api::paintset_render(int set, ifc_canvas *c, const RECT *r, int alpha)
+{
+ _voidcall(API_WND_PAINTSET_RENDER, set, c, r, alpha);
+}
+
+inline void wnd_api::paintset_renderTitle(const wchar_t *t, ifc_canvas *c, const RECT *r, int alpha)
+{
+ _voidcall(API_WND_PAINTSET_RENDERTITLE, t, c, r, alpha);
+}
+
+inline int wnd_api::forwardOnMouseWheel(int l, int a) {
+ return _call(API_WND_FORWARDONMOUSEWHEEL, 0, l, a);
+}
+
+// fg> this may need to go away eventually but i need it _right now_
+
+inline void wnd_api::setDefaultDropTarget(void *dt) {
+ _voidcall(API_WND_SETDEFAULTDROPTARGET, dt);
+}
+
+inline void *wnd_api::getDefaultDropTarget() {
+ return _call(API_WND_GETDEFAULTDROPTARGET, (void*)NULL);
+}
+
+inline int wnd_api::pushKeyboardLock() {
+ return _call(API_WND_PUSHKBDLOCK, 0);
+}
+
+inline int wnd_api::popKeyboardLock() {
+ return _call(API_WND_POPKBDLOCK, 0);
+}
+
+inline int wnd_api::isKeyboardLocked() {
+ return _call(API_WND_ISKBDLOCKED, 0);
+}
+
+class wnd_apiI : public wnd_api {
+ public:
+ virtual void main_setRootWnd(ifc_window *w)=0;
+ virtual ifc_window *main_getRootWnd()=0;
+ virtual ifc_window *getModalWnd()=0;
+ virtual void pushModalWnd(ifc_window *w=MODALWND_NOWND)=0;
+ virtual void popModalWnd(ifc_window *w=MODALWND_NOWND)=0;
+ virtual ifc_window *rootWndFromPoint(POINT *pt)=0;
+ virtual ifc_window *rootWndFromOSHandle(OSWINDOWHANDLE wnd)=0;
+ virtual void registerRootWnd(ifc_window *wnd)=0;
+ virtual void unregisterRootWnd(ifc_window *wnd)=0;
+ virtual int rootwndIsValid(ifc_window *wnd)=0;
+ virtual void hookKeyboard(ifc_window *hooker)=0;
+ virtual void unhookKeyboard(ifc_window *hooker)=0;
+ virtual void kbdReset()=0;
+ virtual int interceptOnChar(unsigned int c)=0;
+ virtual int interceptOnKeyDown(int k)=0;
+ virtual int interceptOnKeyUp(int k)=0;
+ virtual int interceptOnSysKeyDown(int k, int kd)=0;
+ virtual int interceptOnSysKeyUp(int k, int kd)=0;
+ virtual int forwardOnChar(ifc_window *from, unsigned int c, int kd)=0;
+ virtual int forwardOnKeyDown(ifc_window *from, int k, int kd)=0;
+ virtual int forwardOnKeyUp(ifc_window *from, int k, int kd)=0;
+ virtual int forwardOnSysKeyDown(ifc_window *from, int k, int kd)=0;
+ virtual int forwardOnSysKeyUp(ifc_window *from, int k, int kd)=0;
+ virtual int forwardOnKillFocus()=0;
+ virtual void popupexit_deregister(PopupExitCallback *cb)=0;
+ virtual void popupexit_register(PopupExitCallback *cb, ifc_window *watched)=0;
+ virtual int popupexit_check(ifc_window *w)=0;
+ virtual void popupexit_signal()=0;
+ virtual void skin_renderBaseTexture(ifc_window *base, ifc_canvas *c, const RECT *r, ifc_window *destWnd, int alpha=255)=0;
+ virtual void skin_registerBaseTextureWindow(ifc_window *window, const wchar_t *bmp=NULL)=0;
+ virtual void skin_unregisterBaseTextureWindow(ifc_window *window)=0;
+ virtual void appdeactivation_push_disallow(ifc_window *w)=0;
+ virtual void appdeactivation_pop_disallow(ifc_window *w)=0;
+ virtual int appdeactivation_isallowed(ifc_window *w)=0;
+ virtual void appdeactivation_setbypass(int i)=0;
+#ifdef WASABI_COMPILE_PAINTSETS
+ virtual int paintset_present(int set)=0;
+#ifdef WASABI_COMPILE_IMGLDR
+ virtual void paintset_render(int set, ifc_canvas *c, const RECT *r, int alpha=255)=0;
+#ifdef WASABI_COMPILE_FONTS
+ virtual void paintset_renderTitle(const wchar_t *t, ifc_canvas *c, const RECT *r, int alpha=255)=0;
+#endif // fonts
+#endif // imgldr
+#endif // paintsets
+ virtual int forwardOnMouseWheel(int l, int a)=0;
+ // fg> this may need to go away eventually but i need it _right now_
+ virtual void setDefaultDropTarget(void *dt)=0;
+ virtual void *getDefaultDropTarget()=0;
+ virtual int pushKeyboardLock()=0;
+ virtual int popKeyboardLock()=0;
+ virtual int isKeyboardLocked()=0;
+ protected:
+ RECVS_DISPATCH;
+};
+
+// {ABB8FBC7-6255-4d41-ACAB-D3D61DDD74EE}
+static const GUID wndApiServiceGuid =
+{ 0xabb8fbc7, 0x6255, 0x4d41, { 0xac, 0xab, 0xd3, 0xd6, 0x1d, 0xdd, 0x74, 0xee } };
+
+extern wnd_api *wndApi;
+
+#endif
diff --git a/Src/Wasabi/api/wnd/basewnd.cpp b/Src/Wasabi/api/wnd/basewnd.cpp
new file mode 100644
index 00000000..f24e4d6f
--- /dev/null
+++ b/Src/Wasabi/api/wnd/basewnd.cpp
@@ -0,0 +1,5743 @@
+#include <precomp.h>
+
+#include <bfc/wasabi_std.h>
+#include <bfc/wasabi_std_wnd.h>
+#include <api/wnd/wndevent.h>
+
+#include <bfc/bfc_assert.h>
+#include <api/wnd/wndclass/tooltip.h>
+#include <api/wnd/cursor.h>
+#include <api/wnd/accessible.h>
+#include <api/service/svcs/svc_accessibility.h>
+#include <api/wnd/paintsets.h>
+#include <api/wnd/PaintCanvas.h>
+
+#ifdef _WIN32
+#include <shellapi.h> // for HDROP
+#endif
+#include <tataki/canvas/bltcanvas.h>
+
+#define DESKTOPALPHA
+#define REFRESH_RATE 25
+#define DRAWTIMERID 125
+
+#include <api/wnd/basewnd.h>
+#include <api/wnd/usermsg.h>
+
+#include <api/wnd/paintcb.h>
+#include <tataki/canvas/canvas.h>
+#include <bfc/file/filename.h>
+#include <tataki/region/region.h>
+#include <api/wnd/wndclass/guiobjwnd.h>
+#include <api/script/scriptguid.h>
+#include <api/wnd/notifmsg.h>
+#include <api/metrics/metricscb.h>
+
+#include <api/wndmgr/gc.h>
+#include <api/wndmgr/layout.h>
+
+namespace Agave
+{
+ #include "../Agave/Config/api_config.h"
+}
+
+
+
+//#define TIP_TIMER_ID 1601
+#define TIP_DESTROYTIMER_ID 1602
+#define TIP_AWAY_ID 1603
+#define TIP_AWAY_DELAY 100
+
+#define TIP_TIMER_THRESHOLD 350
+#define TIP_LENGTH 3000
+
+#define VCHILD_TIMER_ID_MIN 2000
+#define VCHILD_TIMER_ID_MAX 2100
+
+#define BUFFEREDMSG_TIMER_ID 1604
+
+#define DEFERREDCB_INVALIDATE 0x201 // move to .h
+#define DEFERREDCB_FOCUSFIRST 0x202 // move to .h
+#define DC_KILLGHOST 0x204
+
+#ifdef _WIN32
+#define WM_DEFER_CALLBACK (WM_USER+0x333)
+#endif
+class DragSet : public PtrList<void>, public NamedW {};
+
+//CUT? static void register_wndClass(HINSTANCE);
+
+//CUT? #define ROOTSTRING "RootWnd"
+
+//CUT? #define BASEWNDCLASSNAME "BaseWindow_" ROOTSTRING
+
+#ifndef WM_MOUSEWHEEL
+#define WM_MOUSEWHEEL 0x20A
+#endif
+
+static ifc_window *stickyWnd;
+static RECT sticky;
+
+static UINT WINAMP_WM_DIRECT_MOUSE_WHEEL = WM_NULL;
+
+/*api_window *api_window::rootwndFromPoint(POINT &point, int level) {
+ api_window *wnd;
+ wnd = WASABI_API_WND->rootWndFromPoint(&point);
+ return api_window::rootwndFromRootWnd(wnd, level, &point);
+}
+
+api_window *api_window::rootwndFromRootWnd(api_window *wnd, int level, POINT *point) {
+
+ for (;;) {
+ if (wnd == NULL || level < 0) return NULL;
+ if (point) {
+ RECT r;
+ wnd->getWindowRect(&r);
+ if (!PtInRect(&r, *point)) return NULL; // PORT ME
+ }
+ if (level == 0) return wnd;
+ wnd = wnd->getRootWndParent();
+ level--;
+ }
+ // should never get here
+}*/
+
+static BOOL DisabledWindow_OnMouseClick(HWND hwnd)
+{
+ DWORD windowStyle = (DWORD)GetWindowLongPtrW(hwnd, GWL_STYLE);
+ if (WS_DISABLED != ((WS_CHILD | WS_DISABLED) & windowStyle))
+ return FALSE;
+
+ HWND hActive = GetActiveWindow();
+ HWND hPopup = GetWindow(hwnd, GW_ENABLEDPOPUP);
+
+ BOOL beepOk = (hPopup == hActive || hwnd == GetWindow(hActive, GW_OWNER));
+ if (!beepOk && NULL == hPopup)
+ {
+ for (HWND hWalker = hwnd; ;)
+ {
+ hWalker = GetWindow(hWalker, GW_OWNER);
+ if (NULL == hWalker || (0 != (WS_CHILD & GetWindowLongPtrW(hWalker, GWL_STYLE))))
+ break;
+ if (hActive == GetWindow(hWalker, GW_ENABLEDPOPUP))
+ {
+ beepOk = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (beepOk)
+ {
+ static const GUID accessibilityConfigGroupGUID =
+ { 0xe2e7f4a, 0x7c51, 0x478f, { 0x87, 0x74, 0xab, 0xbc, 0xf6, 0xd5, 0xa8, 0x57 } };
+
+ #define GetBoolConfig(__group, __itemName, __default)\
+ ((NULL != (__group)) && NULL != (item = group->GetItem(__itemName)) ? item->GetBool() : (__default))
+
+ waServiceFactory *serviceFactory = WASABI_API_SVC->service_getServiceByGuid(Agave::AgaveConfigGUID);
+ Agave::api_config *config = (NULL != serviceFactory) ? (Agave::api_config *)serviceFactory->getInterface() : NULL;
+ Agave::ifc_configgroup *group = (NULL != config) ? config->GetGroup(accessibilityConfigGroupGUID) : NULL;
+ Agave::ifc_configitem *item;
+
+ if (GetBoolConfig(group, L"modalflash", true))
+ {
+ FLASHWINFO flashInfo;
+ flashInfo.cbSize = sizeof(FLASHWINFO);
+ flashInfo.hwnd = hActive;
+ flashInfo.dwFlags = FLASHW_CAPTION;
+ flashInfo.uCount = 2;
+ flashInfo.dwTimeout = 100;
+ FlashWindowEx(&flashInfo);
+ }
+
+ if (GetBoolConfig(group, L"modalbeep", false))
+ MessageBeep(MB_OK);
+
+ if (NULL != config)
+ serviceFactory->releaseInterface(config);
+ }
+ else
+ {
+ for (HWND hWalker = hwnd; NULL == hPopup;)
+ {
+ hWalker = GetWindow(hWalker, GW_OWNER);
+ if (NULL == hWalker || (0 != (WS_CHILD & GetWindowLongPtrW(hWalker, GWL_STYLE))))
+ break;
+ hPopup = GetWindow(hWalker, GW_ENABLEDPOPUP);
+ }
+
+ SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
+ if (NULL != hPopup && hPopup != hwnd)
+ {
+ BringWindowToTop(hPopup);
+ SetActiveWindow(hPopup);
+ }
+ }
+
+ return TRUE;
+}
+int WndWatcher::viewer_onItemDeleted(ifc_dependent *item)
+{
+ if (item == dep)
+ {
+ dep = NULL;
+ watcher->wndwatcher_onDeleteWindow(watched);
+ watched = NULL;
+ }
+ return 1;
+}
+
+BaseWnd::BaseWnd()
+{
+ uiwaslocked = 0;
+ m_takenOver = 0;
+ rootfocus = NULL;
+ rootfocuswatcher.setWatcher(this);
+ alwaysontop = 0;
+ customdefaultcursor = NULL;
+ preventcancelcapture = 0;
+ ratiolinked = 1;
+ deleting = 0;
+ hinstance = NULL;
+ hwnd = NULL;
+ parentWnd = NULL;
+ dragging = 0;
+ prevtarg = NULL;
+ inputCaptured = 0;
+ btexture = NULL;
+ postoninit = 0;
+ inited = 0;
+ skipnextfocus = 0;
+ ncb = FALSE;
+ accessible = NULL;
+
+ tooltip = NULL;
+ tip_done = FALSE;
+ tipshowtimer = FALSE;
+ tipawaytimer = FALSE;
+ tipdestroytimer = FALSE;
+ start_hidden = 0;
+ notifyWindow = NULL;
+ lastClick[0] = 0;
+ lastClick[1] = 0;
+ lastClickP[0].x = 0;
+ lastClickP[0].y = 0;
+ lastClickP[1].x = 0;
+ lastClickP[1].y = 0;
+ destroying = FALSE;
+
+ curVirtualChildCaptured = NULL;
+ curVirtualChildFocus = NULL;
+
+ virtualCanvas = NULL; virtualCanvasH = virtualCanvasW = 0;
+ deferedInvalidRgn = NULL;
+
+ hasfocus = 0;
+ focus_on_click = 1;
+ lastnullregion = 0;
+ ratio = 1;
+ lastratio = 1;
+ rwidth = rheight = 0;
+ skin_id = -1;
+ wndalpha = 255;
+ activealpha = 255;
+ inactivealpha = 255;
+ w2k_alpha = 0; //FUCKO
+ scalecanvas = NULL;
+ clickthrough = 0;
+
+ mustquit = 0;
+ returnvalue = 0;
+ notifyid = 0;
+ cloaked = 0;
+ disable_tooltip_til_recapture = 0;
+
+ subtractorrgn = NULL;
+ composedrgn = NULL;
+ wndregioninvalid = 1;
+ regionop = REGIONOP_NONE;
+ rectrgn = 1;
+ need_flush_cascaderepaint = 0;
+ deferedCascadeRepaintRgn = NULL;
+ this_visible = 0;
+ this_enabled = 1;
+ renderbasetexture = 0;
+ oldCapture = NULL;
+ my_guiobject = NULL;
+ want_autoresize_after_init = 0;
+ resizecount = 0;
+ suggested_w = 320;
+ suggested_h = 200;
+ maximum_w = maximum_h = AUTOWH;
+ minimum_w = minimum_h = AUTOWH;
+ rx = 0;
+ ry = 0;
+ rwidth = 0;
+ rheight = 0;
+ allow_deactivate = 1;
+ minimized = 0;
+ inonresize = 0;
+#ifndef WA3COMPATIBILITY
+ m_target = NULL;
+#endif
+
+ nodoubleclick = noleftclick = norightclick = nomousemove = nocontextmnu = 0;
+ focusEventsEnabled = 1;
+ maximized = 0;
+ MEMSET(&restore_rect, 0, sizeof(RECT));
+ ghostbust = 0;
+
+ lastActiveWnd = NULL;
+}
+
+BaseWnd::~BaseWnd()
+{
+ //ASSERT(virtualChildren.getNumItems() == 0);
+ childtabs.deleteAll();
+ if (WASABI_API_WND && WASABI_API_WND->getModalWnd() == this) WASABI_API_WND->popModalWnd(this);
+ destroying = TRUE;
+ curVirtualChildFocus = NULL;
+#ifdef _WIN32
+ if (inputCaptured && GetCapture() == getOsWindowHandle()) ReleaseCapture();
+#else
+#warning port me
+#endif
+
+ for (int i = 0;i < ghosthwnd.getNumItems();i++)
+ Wasabi::Std::Wnd::destroyWnd(ghosthwnd.enumItem(i));
+
+ if (hwnd != NULL && !m_takenOver)
+ {
+#ifdef URLDROPS
+ if (acceptExternalDrops()) Wasabi::Std::Wnd::revokeDragNDrop(hwnd /*, &m_target*/);
+#else
+#ifndef WA3COMPATIBILITY
+ if (m_target != NULL)
+ {
+ Wasabi::Std::Wnd::revokeDragNDrop(hwnd);
+ }
+#endif
+#endif
+ int popact = !wantActivation();
+ if (popact) WASABI_API_WND->appdeactivation_push_disallow(this);
+
+ Wasabi::Std::Wnd::destroyWnd(hwnd);
+
+ if (popact) WASABI_API_WND->appdeactivation_pop_disallow(this);
+ }
+
+ deleteFrameBuffer(virtualCanvas);
+ virtualCanvas = NULL;
+ delete scalecanvas;
+ scalecanvas = NULL;
+
+ resetDragSet();
+
+ notifyParent(ChildNotify::DELETED);
+ if (tipdestroytimer)
+ killTimer(TIP_DESTROYTIMER_ID);
+ if (tipshowtimer)
+ {
+ // TODO: on the mac, use CreateMouseTrackingRegion
+ TRACKMOUSEEVENT tracker;
+ tracker.cbSize=sizeof(tracker);
+ tracker.dwFlags = TME_HOVER|TME_CANCEL;
+ tracker.hwndTrack = this->getOsWindowHandle();
+ tracker.dwHoverTime = TIP_TIMER_THRESHOLD;
+
+ TrackMouseEvent(&tracker);
+
+ }
+ if (tipawaytimer)
+ killTimer(TIP_AWAY_ID);
+
+ destroyTip();
+
+ delete tooltip;
+
+ if (uiwaslocked)
+ killTimer(BUFFEREDMSG_TIMER_ID);
+
+ if (deferedInvalidRgn)
+ delete deferedInvalidRgn;
+
+ delete composedrgn;
+ delete subtractorrgn;
+ delete deferedCascadeRepaintRgn;
+
+ if (parentWnd != NULL)
+ parentWnd->unregisterRootWndChild(this);
+
+ if (!m_takenOver && WASABI_API_WND) WASABI_API_WND->unregisterRootWnd(this);
+ hwnd = NULL;
+}
+
+int BaseWnd::init(ifc_window *parWnd, int nochild)
+{
+ if (parWnd == NULL)
+ return 0;
+
+ OSWINDOWHANDLE phwnd = parWnd->getOsWindowHandle();
+ ASSERT(phwnd != NULL);
+
+ parentWnd = parWnd; // set default parent wnd
+ int ret = init(parWnd->getOsModuleHandle(), phwnd, nochild);
+
+ if (!ret)
+ parentWnd = NULL; // abort
+
+ return ret;
+}
+
+int BaseWnd::init(OSMODULEHANDLE moduleHandle, OSWINDOWHANDLE parent, int nochild)
+{
+ RECT r;
+ int w, h;
+
+ ASSERTPR(getOsWindowHandle() == NULL, "don't you double init you gaybag");
+
+ hinstance = moduleHandle;
+
+#ifdef _WIN32
+ ASSERT(hinstance != NULL);
+#endif
+
+ //CUT register_wndClass(hinstance);
+
+ if (parent != NULL)
+ {
+ Wasabi::Std::Wnd::getClientRect(parent, &r);
+ }
+ else
+ {
+ Wasabi::Std::setRect(&r, 0, 0, getPreferences(SUGGESTED_W), getPreferences(SUGGESTED_H));
+ }
+
+ w = (r.right - r.left);
+ h = (r.bottom - r.top);
+
+ rwidth = w;
+ rheight = h;
+ rx = r.left;
+ ry = r.top;
+
+ int popact = !wantActivation();
+ if (popact) WASABI_API_WND->appdeactivation_push_disallow(this);
+
+ //CUThwnd = createWindow(r.left, r.top, w, h, nochild, parent, hinstance);
+ hwnd = Wasabi::Std::Wnd::createWnd(&r, nochild, acceptExternalDrops(), parent, hinstance, static_cast<ifc_window*>(this));
+#ifdef __APPLE__
+#warning remove me
+ Wasabi::Std::Wnd::showWnd(hwnd);
+#endif
+
+ if (popact) WASABI_API_WND->appdeactivation_pop_disallow(this);
+
+ //ASSERT(hwnd != NULL); // lets fail nicely, this could happen for some win32 reason, we don't want to fail the whole app for it, so lets just fail the wnd
+ if (hwnd == NULL) return 0;
+
+ if (wantActivation()) bringToFront();
+
+ //CUT nreal++;
+
+ //FUCKO
+#ifdef _WIN32 // PORT ME
+#ifdef URLDROPS
+ if (acceptExternalDrops()) RegisterDragDrop(hwnd, &m_target);
+#else
+#ifndef WA3COMPATIBILITY
+ if (!m_target && WASABI_API_WND != NULL)
+ m_target = WASABI_API_WND->getDefaultDropTarget();
+ if (m_target != NULL)
+ {
+ RegisterDragDrop(hwnd, (IDropTarget *)m_target);
+ }
+#endif
+#endif
+#endif
+
+ this_visible = 0;
+
+ onInit();
+
+ this_visible = !start_hidden;
+
+ onPostOnInit();
+
+ return 1;
+}
+
+#ifndef WA3COMPATIBILITY
+void BaseWnd::setDropTarget(void *dt)
+{
+#ifdef _WIN32
+ if (isVirtual()) return ;
+ if (isInited() && m_target != NULL)
+ {
+ Wasabi::Std::Wnd::revokeDragNDrop(getOsWindowHandle());
+ m_target = NULL;
+ }
+ m_target = dt;
+ if (m_target != NULL && isInited())
+ {
+ RegisterDragDrop(gethWnd(), (IDropTarget *)m_target);
+ }
+#else
+#warning port me
+#endif
+}
+
+void *BaseWnd::getDropTarget()
+{
+ return m_target;
+}
+#endif
+
+int BaseWnd::onInit()
+{
+
+ const wchar_t *s = getName();
+ if (s != NULL)
+ setOSWndName(s);
+
+ inited = 1;
+
+ if (getParent())
+ getParent()->registerRootWndChild(this);
+
+ if (WASABI_API_WND != NULL)
+ WASABI_API_WND->registerRootWnd(this);
+
+#ifdef _WIN32
+ if (!Wasabi::Std::Wnd::isDesktopAlphaAvailable())
+ w2k_alpha = 0; //FUCKO
+
+ if (w2k_alpha)
+ {
+ setLayeredWindow(1);
+ }
+
+ if (WM_NULL == WINAMP_WM_DIRECT_MOUSE_WHEEL)
+ WINAMP_WM_DIRECT_MOUSE_WHEEL = RegisterWindowMessageW(L"WINAMP_WM_DIRECT_MOUSE_WHEEL");
+
+#endif
+
+ return 0;
+}
+
+int BaseWnd::onPostOnInit()
+{
+ postoninit = 1; // from now on, isInited() returns 1;
+ if (want_autoresize_after_init) onResize();
+ else invalidateWindowRegion();
+ if (isVisible()) onSetVisible(1);
+ if (getTabOrder() == -1) setAutoTabOrder();
+ ifc_window *dp = getDesktopParent();
+ if ((dp == NULL || dp == this) && WASABI_API_TIMER != NULL)
+ postDeferredCallback(DEFERREDCB_FOCUSFIRST, 0, 500);
+ return 0;
+}
+
+void BaseWnd::setLayeredWindow(int i)
+{
+ if (!Wasabi::Std::Wnd::isValidWnd(getOsWindowHandle())) return ;
+ if (!isInited()) return ;
+ Wasabi::Std::Wnd::setLayeredWnd(getOsWindowHandle(), i);
+#if 0//CUT
+ if (i)
+ {
+ SetWindowLong(getOsWindowHandle(), GWL_EXSTYLE, GetWindowLong(getOsWindowHandle(), GWL_EXSTYLE) & ~WS_EX_LAYERED);
+ SetWindowLong(getOsWindowHandle(), GWL_EXSTYLE, GetWindowLong(getOsWindowHandle(), GWL_EXSTYLE) | WS_EX_LAYERED);
+ }
+ else
+ {
+ SetWindowLong(getOsWindowHandle(), GWL_EXSTYLE, GetWindowLong(getOsWindowHandle(), GWL_EXSTYLE) & ~WS_EX_LAYERED);
+ }
+#endif
+ setTransparency(-1);
+}
+
+int BaseWnd::getCursorType(int x, int y)
+{
+ if (!customdefaultcursor)
+ return BASEWND_CURSOR_POINTER;
+ return BASEWND_CURSOR_USERSET;
+}
+
+void BaseWnd::onSetName()
+{
+ if (isInited() && !isVirtual())
+ Wasabi::Std::Wnd::setWndName(getOsWindowHandle(), getNameSafe());
+ notifyParent(ChildNotify::NAMECHANGED);
+ if (accessible)
+ accessible->onSetName(getName());
+}
+
+OSWINDOWHANDLE BaseWnd::getOsWindowHandle()
+{
+ OSWINDOWHANDLE handle;
+
+ if ( isVirtual() )
+ handle = getParent()->getOsWindowHandle();
+ else
+ handle = hwnd;
+
+
+ return handle;
+}
+
+OSMODULEHANDLE BaseWnd::getOsModuleHandle()
+{
+ return hinstance;
+}
+
+void BaseWnd::onTip()
+{
+ tipshowtimer = FALSE;
+ tip_done = TRUE;
+
+ POINT p;
+ Wasabi::Std::getMousePos(&p);
+ if (WASABI_API_WND->rootWndFromPoint(&p) == (ifc_window *)this)
+ {
+ createTip();
+ setTimer(TIP_DESTROYTIMER_ID, TIP_LENGTH);
+ tipdestroytimer = TRUE;
+ }
+ setTimer(TIP_AWAY_ID, TIP_AWAY_DELAY);
+ tipawaytimer = TRUE;
+}
+
+void BaseWnd::timerCallback(int id)
+{
+ switch (id)
+ {
+ case BUFFEREDMSG_TIMER_ID:
+ checkLockedUI();
+ break;
+// case TIP_TIMER_ID:
+ //onTip();
+ //break;
+ case TIP_DESTROYTIMER_ID:
+ killTimer(TIP_DESTROYTIMER_ID);
+ killTimer(TIP_AWAY_ID);
+ tipawaytimer = FALSE;
+ tipdestroytimer = FALSE;
+ destroyTip();
+ break;
+ case TIP_AWAY_ID:
+ onTipMouseMove();
+ break;
+ }
+}
+
+int BaseWnd::isInited()
+{
+ return inited;
+}
+
+int BaseWnd::isDestroying()
+{
+ return destroying;
+}
+
+int BaseWnd::wantSiblingInvalidations()
+{
+ return FALSE;
+}
+
+void BaseWnd::setRSize(int x, int y, int w, int h)
+{
+ rwidth = w;
+ rheight = h;
+ rx = x;
+ ry = y;
+}
+
+void BaseWnd::resize(int x, int y, int w, int h, int wantcb)
+{
+ inonresize = 1;
+
+ if (x == AUTOWH) x = NOCHANGE;
+ if (y == AUTOWH) y = NOCHANGE;
+ if (w == AUTOWH) w = NOCHANGE;
+ if (h == AUTOWH) h = NOCHANGE;
+
+ if (getNumMinMaxEnforcers() > 0)
+ {
+ int min_w = getPreferences(MINIMUM_W);
+ int min_h = getPreferences(MINIMUM_H);
+ int max_w = getPreferences(MAXIMUM_W);
+ int max_h = getPreferences(MAXIMUM_H);
+ if (min_w != AUTOWH && w != NOCHANGE && w < min_w) w = min_w;
+ if (max_w != AUTOWH && w != NOCHANGE && w > max_w) w = max_w;
+ if (min_h != AUTOWH && h != NOCHANGE && h < min_h) h = min_h;
+ if (max_h != AUTOWH && h != NOCHANGE && h > max_h) h = max_h;
+ }
+
+ int noresize = (w == NOCHANGE && h == NOCHANGE);
+ int nomove = (x == NOCHANGE && y == NOCHANGE)/* || (x == rx && y == ry)*/;
+ if (x == NOCHANGE) x = rx;
+ if (y == NOCHANGE) y = ry;
+ if (w == NOCHANGE) w = rwidth;
+ if (h == NOCHANGE) h = rheight;
+
+#ifdef _DEBUG
+ ASSERT(x < 0xFFF0);
+ ASSERT(y < 0xFFF0);
+ ASSERT(w < 0xFFF0);
+ ASSERT(h < 0xFFF0);
+#endif
+
+ double thisratio = getRenderRatio();
+ int different_ratio = (lastratio != thisratio);
+ lastratio = thisratio;
+
+ int noevent = (resizecount > 1 && w == rwidth && h == rheight);
+ //ifc_window *dp = getDesktopParent();
+ if (different_ratio == 1 && noevent == 1)
+ {
+ if (Wasabi::Std::Wnd::getTopmostChild(getOsWindowHandle()) != INVALIDOSWINDOWHANDLE)
+ noevent = 0;
+ invalidateWindowRegion();
+ }
+
+ RECT oldsize, newsize = Wasabi::Std::makeRect(x, y, w, h);
+ if (hwnd != NULL)
+ BaseWnd::getNonClientRect(&oldsize);
+ else
+ oldsize = newsize;
+
+ setRSize(x, y, w, h);
+
+ if (handleRatio() && renderRatioActive())
+ {
+ multRatio(&w, &h);
+ if (getParent() != NULL)
+ {
+ multRatio(&x, &y);
+ }
+ }
+
+ if (!noevent)
+ {
+ if (wantcb && isPostOnInit())
+ {
+ resizecount = MIN(5, ++resizecount);
+ if (!isVirtual())
+ invalidateWindowRegion();
+ onResize();
+ if (ensureWindowRegionValid())
+ updateWindowRegion();
+ }
+ }
+
+ if (getOsWindowHandle() != NULL)
+ {
+
+ RECT oldsizescaled;
+ getWindowRect(&oldsizescaled);
+ RECT newsizescaled = {x, y, x + w, y + h};
+ if (MEMCMP(&newsizescaled, &oldsizescaled, sizeof(RECT)))
+ {
+ //CUT SetWindowPos(getOsWindowHandle(), NULL, x, y, w, h,
+ //CUT SWP_NOZORDER |
+ //CUT SWP_NOACTIVATE |
+ //CUT (!wantRedrawOnResize() ? SWP_NOCOPYBITS: 0) |
+ //CUT (ncb ? SWP_NOCOPYBITS : 0) |
+ //CUT ( nomove ? SWP_NOMOVE : 0) |
+ //CUT ( noresize ? SWP_NOSIZE : 0) |
+ //CUT 0);
+ Wasabi::Std::Wnd::setWndPos( getOsWindowHandle(), NULL, x, y, w, h, TRUE, TRUE, !wantRedrawOnResize() || ncb, nomove, noresize );
+ }
+ //else
+ //{
+ // DebugStringW(L"BaseWnd::resize optimized\n");
+ //}
+
+ onAfterResize();
+
+ if (ncb)
+ invalidate();
+ else
+ {
+ RECT r;
+ if (hwnd != NULL)
+ {
+ if (newsize.left == oldsize.left && newsize.top == oldsize.top)
+ {
+ if (newsize.right > oldsize.right)
+ {
+ // growing in width
+ r.left = oldsize.right;
+ r.right = newsize.right;
+ r.top = newsize.top;
+ r.bottom = newsize.bottom;
+ invalidateRect(&r);
+ if (newsize.bottom > oldsize.bottom)
+ {
+ // growing in width & height
+ r.left = oldsize.left;
+ r.right = newsize.right;
+ r.top = oldsize.bottom;
+ r.bottom = newsize.bottom;
+ invalidateRect(&r);
+ }
+ }
+ else if (newsize.bottom > oldsize.bottom)
+ {
+ if (newsize.bottom > oldsize.bottom)
+ {
+ // growing in height
+ r.left = oldsize.left;
+ r.right = newsize.right;
+ r.top = oldsize.bottom;
+ r.bottom = newsize.bottom;
+ invalidateRect(&r);
+ }
+ }
+ }
+ }
+ }
+ }
+ inonresize = 0;
+}
+
+void BaseWnd::forcedOnResizeChain(ifc_window *w)
+{
+ w->triggerEvent(TRIGGER_ONRESIZE);
+ int n = w->getNumRootWndChildren();
+ for (int i = 0;i < n;i++)
+ {
+ forcedOnResizeChain(w->enumRootWndChildren(i));
+ }
+}
+
+int BaseWnd::forcedOnResize()
+{
+ forcedOnResizeChain(this);
+ return 1;
+}
+
+int BaseWnd::onResize()
+{
+ if (!isVirtual() || (getRegionOp() != REGIONOP_NONE))
+ invalidateWindowRegion();
+ // you are not supposed to call onResize until after onInit has returned. If what you wanted was to generate
+ // an onResize event to do some custom client coordinates recalculations (ie: to apply on your children)
+ // then you don't need to do anything since onResize is going to be called after onInit() is done. If you still want to
+ // trigger it because your code might be called by onInit and after onInit, use isPostOnInit() as a test.
+ // if what you wanted was to signal a object that you just resized it, then you don't need to do anything beside
+ // resize(...), it will generate the event on its own if the window is inited, and will defer to until after onInit
+ // if it is not.
+ // shortly put: do not call onResize before or inside onInit()
+ // if you have any valid reason for doing that, i'd like to know about it so i can make it possible. -FG
+#ifdef _DEBUG
+ if (!isPostOnInit())
+ {
+ //__asm int 3;
+ ASSERTPR(isPostOnInit(), "do not call onResize before or inside onInit()");
+ }
+#endif
+ return FALSE;
+}
+
+void BaseWnd::resizeToClient(BaseWnd *wnd)
+{
+ if (wnd != NULL)
+ wnd->resize(&clientRect());
+}
+
+int BaseWnd::onPostedMove()
+{
+ /*
+ if (w2k_alpha && Wasabi::Std::Wnd::isDesktopAlphaAvailable() && !cloaked)
+ {
+ RECT r;
+ getWindowRect(&r);
+ Wasabi::Std::Wnd::moveLayeredWnd(hwnd, r.left, r.top);
+ }*/
+ return FALSE;
+}
+
+void BaseWnd::resize(RECT *r, int wantcb)
+{
+ resize(r->left, r->top, r->right - r->left, r->bottom - r->top, wantcb);
+}
+
+void BaseWnd::move(int x, int y)
+{
+ //DebugStringW( L"BaseWnd::move( x = %d, y = %d )\n", x, y );
+
+ setRSize(x, y, rwidth, rheight);
+ Wasabi::Std::Wnd::setWndPos( getOsWindowHandle(), NULL, x, y, 0, 0, TRUE, TRUE, ncb, FALSE, TRUE );
+ //CUT if (!ncb)
+ //CUT SetWindowPos(getOsWindowHandle(), NULL, x, y, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_DEFERERASE);
+ //CUT else
+ //CUT SetWindowPos(getOsWindowHandle(), NULL, x, y, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOCOPYBITS|SWP_NOACTIVATE|SWP_DEFERERASE);
+}
+
+#ifdef EXPERIMENTAL_INDEPENDENT_AOT
+BOOL CALLBACK EnumOwnedTopMostWindows(HWND hwnd, LPARAM lParam)
+{
+ enumownedstruct *st = (enumownedstruct *)lParam;
+ if (hwnd != st->hthis && GetWindow(hwnd, GW_OWNER) == st->owner)
+ {
+ ifc_window *w = (ifc_window*)GetWindowLong(hwnd, GWL_USERDATA);
+ if (w != NULL && w->getAlwaysOnTop())
+ st->hlist->addItem(w);
+ }
+ return TRUE;
+}
+
+void BaseWnd::saveTopMosts()
+{
+ HWND owner = GetWindow(getOsWindowHandle(), GW_OWNER);
+ enumownedstruct st;
+ ontoplist.removeAll();
+ if (owner != NULL)
+ {
+ st.owner = owner;
+ st.hlist = &ontoplist;
+ st.hthis = getOsWindowHandle();
+ EnumWindows(EnumOwnedTopMostWindows, (long)&st);
+ }
+}
+
+void BaseWnd::restoreTopMosts()
+{
+ HWND owner = GetWindow(getOsWindowHandle(), GW_OWNER);
+ if (owner != NULL)
+ {
+ for (int i = 0;i < ontoplist.getNumItems();i++)
+ {
+ ontoplist.enumItem(i)->setAlwaysOnTop(1);
+ }
+ }
+}
+#endif
+
+void BaseWnd::bringToFront()
+{
+ // when we set a window to the top of the zorder (not topmost), win32 finds the owner and removes any topmost flag its children may
+ // have because it assumes we want this window over these, which we definitly don't. so we need to first go thru all the owner's children,
+ // make a list of the ones with a topmost flag, set this window on top, and set the topmost flags back. yay
+ ASSERT(!isVirtual());
+#ifdef EXPERIMENTAL_INDEPENDENT_AOT
+ saveTopMosts();
+#endif
+ //CUT SetWindowPos(getOsWindowHandle(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE|SWP_DEFERERASE|SWP_NOOWNERZORDER);
+ Wasabi::Std::Wnd::bringToFront(getOsWindowHandle());
+#ifdef EXPERIMENTAL_INDEPENDENT_AOT
+ restoreTopMosts();
+#endif
+}
+
+void BaseWnd::bringToBack()
+{
+ ASSERT(!isVirtual());
+#ifdef EXPERIMENTAL_INDEPENDENT_AOT
+ saveTopMosts();
+#endif
+ //CUT SetWindowPos(getOsWindowHandle(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE|SWP_DEFERERASE|SWP_NOOWNERZORDER);
+ Wasabi::Std::Wnd::sendToBack(getOsWindowHandle());
+#ifdef EXPERIMENTAL_INDEPENDENT_AOT
+ restoreTopMosts();
+#endif
+}
+
+void BaseWnd::setVisible(int show)
+{
+ int visible = isVisible(1);
+ if (!!visible == !!show) return ;
+ invalidate();
+ this_visible = !!show;
+ /*if (!getParent() || getParent() == WASABI_API_WND->main_getRootWnd() && IsWindow(getOsWindowHandle())) {
+ if (!show) {
+ setLayeredWindow(0);
+ if (setLayeredWindowAttributes)
+ setLayeredWindowAttributes(hwnd, RGB(0,0,0), 255, LWA_ALPHA);
+ } else {
+ setLayeredWindow(w2k_alpha);
+ }
+ }*/
+ if (!getParent() || getParent() == WASABI_API_WND->main_getRootWnd() || getParent()->isVisible())
+ {
+ onSetVisible(show);
+ }
+}
+
+void BaseWnd::setCloaked(int cloak)
+{
+ if (cloaked == cloak) return ;
+ cloaked = cloak;
+ if (isVirtual()) return ;
+ if (cloaked)
+ {
+ //CUTif (IsWindowVisible(getOsWindowHandle()))
+ //CUT ShowWindow(getOsWindowHandle(), SW_HIDE);
+ if (Wasabi::Std::Wnd::isWndVisible(getOsWindowHandle()))
+ Wasabi::Std::Wnd::hideWnd(getOsWindowHandle());
+ }
+ else
+ {
+ if (isVisible(1))
+ //CUTShowWindow(getOsWindowHandle(), SW_NORMAL);
+ Wasabi::Std::Wnd::showWnd(getOsWindowHandle());
+ }
+}
+
+
+void BaseWnd::onSetVisible(int show)
+{
+ /* for debug purposes - don't delete please
+ #include "../../../studio/container.h"
+ #include "../../../studio/layout.h"
+ if (!show && getGuiObject() && STRCASEEQLSAFE(getGuiObject()->guiobject_getId(), "normal")) {
+ Layout *l = (Layout *)getInterface(layoutGuid);
+ if (l) {
+ if (l->getParentContainer() && STRCASEEQLSAFE(l->getParentContainer()->getId(), "main")) {
+ DebugString("Hiding main player\n");
+ }
+ }
+ }*/
+ if (!isVirtual())
+ if (hwnd != NULL)
+ if (!cloaked)
+ {
+ //CUT // SetWindowPos(getOsWindowHandle(),NULL,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_SHOWWINDOW);
+ //CUT ShowWindow(getOsWindowHandle(), show ? SW_SHOWNA : SW_HIDE);
+ if (show)
+ Wasabi::Std::Wnd::showWnd(getOsWindowHandle(), TRUE);
+ else
+ Wasabi::Std::Wnd::hideWnd(getOsWindowHandle());
+ }
+ /* if (!show)
+ postDeferredCallback(0x7849);
+ else {*/
+ foreach(rootwndchildren)
+ ifc_window *w = rootwndchildren.getfor();
+ if (w && w->isVisible(1)) // check internal flag only
+ w->onSetVisible(show);
+ endfor;
+ dependent_sendEvent(BaseWnd::depend_getClassGuid(), Event_SETVISIBLE, show);
+ //}
+ /* if (getDesktopParent() == this) {
+ cascadeRepaint(0);
+ }*/
+
+ /*#ifdef WIN32 // os-specific non virtual child wnd support
+ if (!isVirtual()) {
+ HWND w = GetWindow(getOsWindowHandle(), GW_CHILD);
+ while (w != NULL) {
+ api_window *rootwnd = (api_window*)GetWindowLong(w, GWL_USERDATA);
+ if (rootwnd && rootwnd != this)
+ if (rootwnd->isInited())
+ rootwnd->onSetVisible(show);
+ w = GetWindow(w, GW_HWNDNEXT);
+ }
+ }
+ #endif*/
+ if (!isVirtual())
+ {
+ if (!show)
+ {
+ deferedInvalidate();
+ delete virtualCanvas;
+ virtualCanvas = NULL;
+ }
+ }
+ invalidateWindowRegion();
+}
+
+void BaseWnd::setEnabled(int en)
+{
+ int enabled = isEnabled(1);
+ if (!!enabled == !!en) return ;
+ invalidate();
+ this_enabled = !!en;
+ if (!getParent() || getParent() == WASABI_API_WND->main_getRootWnd() || getParent()->isEnabled())
+ {
+ onEnable(en);
+ }
+}
+
+int BaseWnd::isEnabled(int within)
+{
+ if (!isVirtual() && !getOsWindowHandle()) return 0;
+ if (!this_enabled) return 0;
+
+ if (within) return this_enabled; // whatever, local
+
+ if (isVirtual()) // virtual, global
+ if (getParent())
+ return getParent()->isEnabled();
+ else
+ return 0;
+
+ // non virtual, global
+ //CUT if (GetWindowLong(getOsWindowHandle(), GWL_STYLE) & WS_POPUP) return this_enabled;
+ if (Wasabi::Std::Wnd::isPopup(getOsWindowHandle())) return this_enabled;
+ //CUT if (!Wasabi::Std::Wnd::isValidWnd(GetParent(gethWnd()))) return this_enabled;
+ if (!Wasabi::Std::Wnd::isValidWnd(Wasabi::Std::Wnd::getParent(getOsWindowHandle()))) return this_enabled;
+ if (getParent()) return getParent()->isEnabled(); // not a popup, check its parent or fail
+ return this_enabled;
+}
+
+int BaseWnd::onEnable(int en)
+{
+ if (!isVirtual())
+ {
+ if (hwnd != NULL)
+ //CUT EnableWindow(getOsWindowHandle(), en);
+ Wasabi::Std::Wnd::setEnabled(getOsWindowHandle(), en);
+ foreach(rootwndchildren)
+ ifc_window *w = rootwndchildren.getfor();
+ if (w->isEnabled(1)) // check internal flag only
+ w->onEnable(en);
+ endfor;
+ }
+ return 1;
+}
+
+void BaseWnd::setFocus()
+{
+ if (curVirtualChildFocus != NULL)
+ {
+ curVirtualChildFocus->onKillFocus();
+ curVirtualChildFocus = NULL;
+ }
+ onSetRootFocus(this);
+ //CUT SetFocus(getOsWindowHandle());
+ Wasabi::Std::Wnd::setFocus(getOsWindowHandle());
+}
+
+void BaseWnd::setFocusOnClick(int f)
+{
+ focus_on_click = f;
+}
+
+api_region *BaseWnd::getDeferedInvalidRgn()
+{
+ return deferedInvalidRgn;
+}
+
+void BaseWnd::deferedInvalidate()
+{
+ if (!hasVirtualChildren() || !isVisible(1)) return ;
+ RECT r = Wasabi::Std::makeRect(0, 0, 0, 0);
+ getNonClientRect(&r);
+ deferedInvalidateRect(&r);
+}
+
+void BaseWnd::deferedInvalidateRect(RECT *r)
+{
+ if (!hasVirtualChildren()) return ;
+ RegionI h(r);
+ deferedInvalidateRgn(&h);
+}
+
+void BaseWnd::deferedInvalidateRgn(api_region *h)
+{
+ if (!hasVirtualChildren()) return ;
+ if (!deferedInvalidRgn)
+ {
+ deferedInvalidRgn = new RegionI();
+ }
+
+ deferedInvalidRgn->addRegion(h);
+}
+
+void BaseWnd::deferedValidate()
+{
+ if (!hasVirtualChildren() || !isVisible(1)) return ;
+ RECT r = Wasabi::Std::makeRect(0,0,0,0);
+ getNonClientRect(&r);
+ deferedValidateRect(&r);
+}
+
+void BaseWnd::deferedValidateRect(RECT *r)
+{
+ if (!hasVirtualChildren()) return ;
+ RegionI h(r);
+ deferedValidateRgn(&h);
+}
+
+void BaseWnd::deferedValidateRgn(api_region *h)
+{
+ if (!hasVirtualChildren()) return ;
+ if (!deferedInvalidRgn) return ;
+
+ deferedInvalidRgn->subtractRgn(h);
+}
+
+int BaseWnd::hasVirtualChildren()
+{
+ return 1; //virtualChildren.getNumItems() > 0;
+}
+
+void BaseWnd::invalidate()
+{
+ invalidateFrom(this);
+}
+
+void BaseWnd::invalidateFrom(ifc_window *who)
+{
+ if (hasVirtualChildren()) deferedInvalidate();
+ //CUT if (hwnd != NULL && isVisible(1)) InvalidateRect(getOsWindowHandle(), NULL, FALSE);
+ if (hwnd != NULL && isVisible(1))
+ Wasabi::Std::Wnd::invalidateRect(getOsWindowHandle());
+}
+
+void BaseWnd::invalidateRectFrom(RECT *r, ifc_window *who)
+{
+ if (hasVirtualChildren()) deferedInvalidateRect(r);
+ RegionI rg(r);
+ invalidateRgnFrom(&rg, who);
+}
+
+void BaseWnd::invalidateRgn(api_region *r)
+{
+ invalidateRgnFrom(r, this);
+}
+
+void BaseWnd::invalidateRect(RECT *r)
+{
+ invalidateRectFrom(r, this);
+}
+
+void BaseWnd::invalidateRgnFrom(api_region *r, ifc_window *who)
+{
+ if (parentWnd) parentWnd->onChildInvalidate(r, who);
+ PaintCallbackInfoI pc(NULL, r);
+ dependent_sendEvent(BaseWnd::depend_getClassGuid(), Event_ONINVALIDATE, 0, &pc);
+ if (hwnd != NULL && isVisible(1))
+ {
+ if (hasVirtualChildren())
+ {
+ api_region *_r = r->clone();
+ int j = virtualChildren.searchItem(who);
+ for (int i = 0;i < virtualChildren.getNumItems();i++)
+ {
+ ifc_window *w = virtualChildren[i];
+ if (w != who && w->wantSiblingInvalidations())
+ w->onSiblingInvalidateRgn(_r, who, j, i);
+ }
+
+ deferedInvalidateRgn(_r);
+ physicalInvalidateRgn(_r);
+ r->disposeClone(_r);
+ }
+ else
+ {
+ deferedInvalidateRgn(r);
+ physicalInvalidateRgn(r);
+ }
+ }
+}
+
+void BaseWnd::physicalInvalidateRgn(api_region *r)
+{
+ if (hwnd != NULL && isVisible(1))
+ {
+ if (renderRatioActive())
+ {
+ api_region *clone = r->clone();
+ clone->scale(getRenderRatio(), getRenderRatio(), TRUE);
+ //CUT InvalidateRgn(getOsWindowHandle(), clone->getOSHandle(), FALSE);
+ Wasabi::Std::Wnd::invalidateRegion(getOsWindowHandle(), clone->getOSHandle());
+ r->disposeClone(clone);
+ }
+ else
+ //CUT InvalidateRgn(getOsWindowHandle(), r->getOSHandle(), FALSE);
+ Wasabi::Std::Wnd::invalidateRegion(getOsWindowHandle(), r->getOSHandle());
+ }
+}
+
+void BaseWnd::validate()
+{
+ //CUT if (hwnd != NULL) ValidateRect(getOsWindowHandle(), NULL);
+ if (hwnd != NULL)
+ Wasabi::Std::Wnd::validateRect(getOsWindowHandle());
+}
+
+void BaseWnd::validateRect(RECT *r)
+{
+ if (hwnd != NULL)
+ {
+ if (renderRatioActive())
+ {
+ RECT r2 = *r;
+ Wasabi::Std::scaleRect(&r2, getRenderRatio());
+ //CUT ValidateRect(getOsWindowHandle(), &r2);
+ Wasabi::Std::Wnd::validateRect(getOsWindowHandle(), &r2);
+ }
+ else
+ //CUT ValidateRect(getOsWindowHandle(), r);
+ Wasabi::Std::Wnd::validateRect(getOsWindowHandle(), r);
+ }
+}
+
+void BaseWnd::validateRgn(api_region *reg)
+{
+ if (hwnd != NULL)
+ {
+ if (renderRatioActive())
+ {
+ api_region *clone = reg->clone();
+ clone->scale(getRenderRatio(), getRenderRatio(), TRUE);
+ //CUT ValidateRgn(getOsWindowHandle(), clone->getOSHandle());
+ Wasabi::Std::Wnd::validateRegion(getOsWindowHandle(), clone->getOSHandle());
+ reg->disposeClone(clone);
+ }
+ else
+ //CUT ValidateRgn(getOsWindowHandle(), reg->getOSHandle());
+ Wasabi::Std::Wnd::validateRegion(getOsWindowHandle(), reg->getOSHandle());
+ }
+}
+
+void BaseWnd::repaint()
+{
+ /* if (hasVirtualChildren()) {
+ api_region *h = new api_region();
+ int s = GetUpdateRgn(getOsWindowHandle(), h->getHRGN(), FALSE);
+ if (s != NULLREGION && s != ERROR) {
+ virtualDrawRgn(h);
+ }
+ delete h;
+ }*/
+ //CUTif (hwnd != NULL) UpdateWindow(getOsWindowHandle());
+ if (hwnd != NULL)
+ Wasabi::Std::Wnd::update(getOsWindowHandle());
+}
+
+void BaseWnd::getClientRect(RECT *rect)
+{
+ /* rect->left = rx;
+ rect->right = rx + rwidth;
+ rect->top = ry;
+ rect->bottom = ry + rheight;*/
+ //ASSERT(hwnd != NULL);
+ if (!Wasabi::Std::Wnd::isValidWnd(hwnd))
+ {
+ MEMSET(rect, 0, sizeof(RECT));
+ return ;
+ }
+
+ GetClientRect(getOsWindowHandle(), rect);
+ ////Wasabi::Std::Wnd::getClientRect(getOsWindowHandle(), rect);
+ rect->right = rect->left + rwidth;
+ rect->bottom = rect->top + rheight;
+}
+
+RECT BaseWnd::clientRect()
+{
+ RECT ret;
+ getClientRect(&ret);
+ return ret;
+}
+
+void BaseWnd::getNonClientRect(RECT *rect)
+{
+ // ASSERT(hwnd != NULL);
+ if (!hwnd)
+ getClientRect(rect);
+ else
+ {
+ Wasabi::Std::Wnd::getClientRect(getOsWindowHandle(), rect);
+ if (getRenderRatio() != 1.0)
+ {
+ rect->right = rect->left + rwidth;
+ rect->bottom = rect->left + rheight;
+ }
+ }
+ /* rect->left = rx;
+ rect->right = rx + rwidth;
+ rect->top = ry;
+ rect->bottom = ry + rheight;*/
+}
+
+RECT BaseWnd::nonClientRect()
+{
+ RECT ret;
+ getNonClientRect(&ret);
+ return ret;
+}
+
+void BaseWnd::getWindowRect(RECT *rect)
+{
+ //CUT#ifdef WIN32
+ //CUT ASSERT(hwnd != NULL);
+ //CUT GetWindowRect(getOsWindowHandle(), rect);
+ //CUT#else
+ //CUT#error port me
+ //CUT#endif
+ Wasabi::Std::Wnd::getWindowRect(getOsWindowHandle(), rect);
+}
+
+// get position relative to parent (same coordinate system for basewnd & virtualwnd)
+void BaseWnd::getPosition(POINT *pt)
+{
+ pt->x = rx;
+ pt->y = ry;
+}
+
+void *BaseWnd::dependent_getInterface(const GUID *classguid)
+{
+ HANDLEGETINTERFACE(ifc_window);
+ //CUT HANDLEGETINTERFACE(api_window);
+ return NULL;
+}
+
+RECT BaseWnd::windowRect()
+{
+ RECT ret;
+ getWindowRect(&ret);
+ return ret;
+}
+
+
+void BaseWnd::clientToScreen(int *x, int *y)
+{
+ int _x = x ? *x : 0;
+ int _y = y ? *y : 0;
+ if (renderRatioActive())
+ {
+ _x = (int)((double)_x * getRenderRatio());
+ _y = (int)((double)_y * getRenderRatio());
+ }
+ Wasabi::Std::Wnd::clientToScreen(getOsWindowHandle(), &_x, &_y);
+ if (x) *x = _x;
+ if (y) *y = _y;
+}
+
+void BaseWnd::clientToScreen(RECT *r)
+{
+ clientToScreen((int*)&r->left, (int*)&r->top);
+ clientToScreen((int*)&r->right, (int*)&r->bottom);
+}
+
+void BaseWnd::clientToScreen(POINT *p)
+{
+ clientToScreen((int *)&p->x, (int *)&p->y);
+}
+
+void BaseWnd::screenToClient(int *x, int *y)
+{
+ //CUT POINT p;
+ int _x = x ? *x : 0;
+ int _y = y ? *y : 0;
+ //CUT ScreenToClient(getOsWindowHandle(), &p);
+ Wasabi::Std::Wnd::screenToClient(getOsWindowHandle(), &_x, &_y);
+ if (renderRatioActive())
+ {
+ _x = (int)((double)_x / getRenderRatio());
+ _y = (int)((double)_y / getRenderRatio());
+ }
+ if (x) *x = _x;
+ if (y) *y = _y;
+}
+
+void BaseWnd::screenToClient(RECT *r)
+{
+ screenToClient((int*)&r->left, (int*)&r->top);
+ screenToClient((int*)&r->right, (int*)&r->bottom);
+}
+
+void BaseWnd::screenToClient(POINT *p)
+{
+ screenToClient((int *)&p->x, (int *)&p->y);
+}
+
+void BaseWnd::setParent(ifc_window *newparent)
+{
+ ASSERTPR(newparent != NULL, "quit being a weeny");
+ ASSERTPR(parentWnd == NULL || newparent == parentWnd, "can't reset parent");
+ parentWnd = newparent;
+ if (isInited())
+ {
+ OSWINDOWHANDLE w1 = getOsWindowHandle();
+ OSWINDOWHANDLE w2 = newparent->getOsWindowHandle();
+ if (w1 != w2)
+ //CUT SetParent(w1, w2);
+ Wasabi::Std::Wnd::setParent(w1, w2);
+ }
+}
+
+//FUCKO
+int BaseWnd::reparent(ifc_window *newparent)
+{
+#ifdef _WIN32
+ if (!isVirtual())
+ {
+ if (isInited())
+ {
+ ifc_window *old = getParent();
+ if (!old && newparent)
+ {
+ ::SetParent(getOsWindowHandle(), newparent->getOsWindowHandle());
+ SetWindowLong(getOsWindowHandle() , GWL_STYLE, GetWindowLong(getOsWindowHandle(), GWL_STYLE) & ~WS_POPUP);
+ SetWindowLong(getOsWindowHandle() , GWL_STYLE, GetWindowLong(getOsWindowHandle(), GWL_STYLE) | WS_CHILD);
+ }
+ else if (old && !newparent)
+ {
+ SetWindowLong(getOsWindowHandle() , GWL_STYLE, GetWindowLong(getOsWindowHandle(), GWL_STYLE) & ~WS_CHILD);
+ SetWindowLong(getOsWindowHandle() , GWL_STYLE, GetWindowLong(getOsWindowHandle(), GWL_STYLE) | WS_POPUP);
+ ::SetParent(getOsWindowHandle(), NULL);
+ }
+ else
+ {
+ ::SetParent(getOsWindowHandle(), newparent ? newparent->getOsWindowHandle() : NULL);
+ }
+ }
+ }
+
+ parentWnd = newparent;
+ onSetParent(newparent);
+
+#ifdef WASABI_ON_REPARENT
+ WASABI_ON_REPARENT(getOsWindowHandle());
+#endif
+#else
+#warning port me
+#endif
+ return 1;
+}
+
+ifc_window *BaseWnd::getParent()
+{
+ return parentWnd;
+}
+
+ifc_window *BaseWnd::getRootParent()
+{
+ return this;
+}
+
+//PORTME
+ifc_window *BaseWnd::getDesktopParent()
+{
+#ifdef _WIN32
+ // NONPORTABLE
+ HWND w = getOsWindowHandle();
+ HWND last = w;
+ if (!w) return NULL;
+ HWND p = w;
+ wchar_t cn[256] = {0};
+ while (p && !(GetWindowLong(p, GWL_STYLE) & WS_POPUP))
+ {
+ GetClassNameW(p, cn, 255); cn[255] = 0;
+ if (!wcscmp(cn, BASEWNDCLASSNAME))
+ last = p;
+ p = GetParent(p);
+ }
+ if (p)
+ {
+ GetClassNameW(p, cn, 255); cn[255] = 0;
+ if (!wcscmp(cn, BASEWNDCLASSNAME))
+ return (ifc_window*)GetWindowLongPtrW(p, GWLP_USERDATA);
+ else if (last != NULL)
+ return (ifc_window*)GetWindowLongPtrW(last, GWLP_USERDATA);
+ }
+#else
+#warning port me
+#endif
+ return NULL;
+}
+
+int BaseWnd::notifyParent(int msg, int param1, int param2)
+{
+ ifc_window *notifywnd = getNotifyWindow();
+ if (getParent() == NULL && notifywnd == NULL) return 0;
+ if (notifywnd == NULL) notifywnd = getParent();
+ ASSERT(notifywnd != NULL);
+ return notifywnd->childNotify(this, msg, param1, param2);
+}
+
+int BaseWnd::passNotifyUp(ifc_window *child, int msg, int param1, int param2)
+{
+ // Same code as above to decide for whom we should notify.
+ ifc_window *notifywnd = getNotifyWindow();
+ if (getParent() == NULL && notifywnd == NULL) return 0;
+ if (notifywnd == NULL) notifywnd = getParent();
+ ASSERT(notifywnd != NULL);
+ // And here we just change the api_window pointer.
+ return notifywnd->childNotify(child, msg, param1, param2);
+}
+
+void BaseWnd::setNotifyId(int id)
+{
+ notifyid = id;
+}
+
+int BaseWnd::getNotifyId()
+{
+ return notifyid;
+}
+
+DragInterface *BaseWnd::getDragInterface()
+{
+ return this;
+}
+
+ifc_window *BaseWnd::rootWndFromPoint(POINT *pt)
+{
+ // pt is in client coordinates
+ int x = (int)((double)pt->x / getRenderRatio());
+ int y = (int)((double)pt->y / getRenderRatio());
+
+ ifc_window *ret = findRootWndChild(x, y);
+ if (ret == NULL) ret = this;
+ return ret;
+}
+
+int BaseWnd::rootwnd_paintTree(ifc_canvas *canvas, api_region *r)
+{
+ BaseCloneCanvas c(canvas);
+ return paintTree(&c, r);
+}
+
+const wchar_t *BaseWnd::getRootWndName()
+{
+ return getName();
+}
+
+const wchar_t *BaseWnd::getId()
+{
+ return NULL;
+}
+
+void BaseWnd::setSkinId(int id)
+{
+ skin_id = id;
+}
+
+void BaseWnd::setPreferences(int what, int v)
+{
+ switch (what)
+ {
+ case MAXIMUM_W: maximum_w = v; break;
+ case MAXIMUM_H: maximum_h = v; break;
+ case MINIMUM_W: minimum_w = v; break;
+ case MINIMUM_H: minimum_h = v; break;
+ case SUGGESTED_W: suggested_w = v; break;
+ case SUGGESTED_H: suggested_h = v; break;
+ }
+}
+
+int BaseWnd::getPreferences(int what)
+{
+ if (getNumMinMaxEnforcers() > 0)
+ {
+
+ int min_x = minimum_w, min_y = minimum_h, max_x = maximum_w, max_y = maximum_h, sug_x = suggested_w, sug_y = suggested_h;
+
+ for (int i = 0;i < getNumMinMaxEnforcers();i++)
+ {
+
+ int tmin_x = MINIMUM_W, tmin_y = MINIMUM_H, tmax_x = MAXIMUM_W, tmax_y = MAXIMUM_H, tsug_x = SUGGESTED_W, tsug_y = SUGGESTED_H;
+
+ ifc_window *w = enumMinMaxEnforcer(i);
+
+ if (w)
+ {
+
+ tmin_x = w->getPreferences(MINIMUM_W);
+ tmin_y = w->getPreferences(MINIMUM_H);
+ tmax_x = w->getPreferences(MAXIMUM_W);
+ tmax_y = w->getPreferences(MAXIMUM_H);
+ tsug_x = w->getPreferences(SUGGESTED_W);
+ tsug_y = w->getPreferences(SUGGESTED_H);
+
+ if (tmin_x == -1) tmin_x = AUTOWH;
+ if (tmin_y == -1) tmin_y = AUTOWH;
+ if (tmax_x == -1) tmax_x = AUTOWH;
+ if (tmax_y == -1) tmax_y = AUTOWH;
+ if (tsug_x == -1) tsug_x = AUTOWH;
+ if (tsug_y == -1) tsug_y = AUTOWH;
+
+#ifndef DISABLE_SYSFONTSCALE
+ TextInfoCanvas textInfoCanvas(this);
+ double fontScale = textInfoCanvas.getSystemFontScale();
+ GuiObject *o = static_cast<GuiObject *>(getInterface(guiObjectGuid));
+ if (o != NULL)
+ {
+ if (o->guiobject_getAutoSysMetricsW())
+ {
+ if (tmin_x != AUTOWH) tmin_x = (int)((float)tmin_x * fontScale);
+ if (tmax_x != AUTOWH) tmax_x = (int)((float)tmax_x * fontScale);
+ if (tsug_x != AUTOWH) tsug_x = (int)((float)tsug_x * fontScale);
+ }
+ if (o->guiobject_getAutoSysMetricsH())
+ {
+ if (tmin_y != AUTOWH) tmin_y = (int)((float)tmin_y * fontScale);
+ if (tmax_y != AUTOWH) tmax_y = (int)((float)tmax_y * fontScale);
+ if (tsug_y != AUTOWH) tsug_y = (int)((float)tsug_y * fontScale);
+ }
+ }
+#endif
+
+ RECT cor;
+ w->getNonClientRect(&cor);
+ RECT wr;
+ getNonClientRect(&wr);
+
+ int xdif = (wr.right - wr.left) - (cor.right - cor.left);
+ int ydif = (wr.bottom - wr.top) - (cor.bottom - cor.top);
+ if (tmin_x != AUTOWH) tmin_x += xdif;
+ if (tmin_y != AUTOWH) tmin_y += ydif;
+ if (tmax_x != AUTOWH) tmax_x += xdif;
+ if (tmax_y != AUTOWH) tmax_y += ydif;
+ if (tsug_x != AUTOWH) tsug_x += xdif;
+ if (tsug_y != AUTOWH) tsug_y += ydif;
+ }
+
+ if (min_x != AUTOWH) min_x = (tmin_x != AUTOWH) ? MAX(min_x, tmin_x) : min_x; else min_x = tmin_x;
+ if (max_x != AUTOWH) max_x = (tmax_x != AUTOWH) ? MAX(max_x, tmax_x) : max_x; else max_x = tmax_x;
+ if (min_y != AUTOWH) min_y = (tmin_y != AUTOWH) ? MAX(min_y, tmin_y) : min_y; else min_y = tmin_y;
+ if (max_y != AUTOWH) max_y = (tmax_y != AUTOWH) ? MAX(max_y, tmax_y) : max_y; else max_y = tmax_y;
+ if (sug_x != AUTOWH) sug_x = (tsug_x != AUTOWH) ? MAX(sug_x, tsug_x) : sug_x; else sug_x = tsug_x;
+ if (sug_y != AUTOWH) sug_y = (tsug_y != AUTOWH) ? MAX(sug_y, tsug_y) : sug_y; else sug_y = tsug_y;
+ }
+
+ if (min_x != AUTOWH && min_x == max_x) sug_x = min_x;
+ if (min_y != AUTOWH && min_y == max_y) sug_y = min_y;
+
+ switch (what)
+ {
+ case MINIMUM_W: return min_x;
+ case MINIMUM_H: return min_y;
+ case MAXIMUM_W: return max_x;
+ case MAXIMUM_H: return max_y;
+ case SUGGESTED_W: return sug_x;
+ case SUGGESTED_H: return sug_y;
+ }
+ }
+
+ switch (what)
+ {
+ case SUGGESTED_W: return suggested_w;
+ case SUGGESTED_H: return suggested_h;
+ case MAXIMUM_W: return maximum_w;
+ case MAXIMUM_H: return maximum_h;
+ case MINIMUM_W: return minimum_w;
+ case MINIMUM_H: return minimum_h;
+ }
+
+ return AUTOWH;
+}
+
+void BaseWnd::setStartHidden(int wtf)
+{
+ start_hidden = wtf;
+}
+
+//PORTME
+#ifdef _WIN32
+
+
+
+#define EQUAL_CLSNAME(__name1, __name2)\
+(CSTR_EQUAL == CompareStringW(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT),\
+NORM_IGNORECASE, (__name1), -1, (__name2), -1))
+
+static BOOL BaseWnd_IsFrameWindow(HWND hwnd)
+{
+ WCHAR szClass[64] = {0};
+ if (NULL == hwnd || !GetClassNameW(hwnd, szClass, ARRAYSIZE(szClass)))
+ return FALSE;
+
+ return EQUAL_CLSNAME(szClass, L"Winamp v1.x") ||
+ EQUAL_CLSNAME(szClass, L"BaseWindow_RootWnd");
+}
+
+
+LRESULT BaseWnd::wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (!isDestroying()) switch (uMsg)
+ {
+ case WM_DEFER_CALLBACK:
+ timerclient_onDeferredCallback(wParam, lParam);
+ break;
+ case WM_SYSCOMMAND:
+ {
+ if ((wParam & 0xfff0) == SC_SCREENSAVE || (wParam & 0xfff0) == SC_MONITORPOWER)
+ {
+ ifc_window *main = WASABI_API_WND->main_getRootWnd();
+ if (main && main != this)
+ return SendMessageW(main->gethWnd(), uMsg, wParam, lParam);
+ }
+ break;
+ }
+ //CUT case WM_CREATE:
+ //CUT hwnd = hWnd;
+ //CUT break;
+
+ //CUT case WM_CLOSE:
+ //CUT return 0;
+
+ case WM_PAINT:
+ {
+ if (inonresize && !wantRedrawOnResize()) return 1;
+ ASSERT(hwnd != NULL);
+ if (!isVisible(1) || IsIconic(hWnd)) break;
+ RECT r;
+ if (GetUpdateRect(hWnd, &r, FALSE))
+ {
+ if (virtualOnPaint())
+ {
+ return 0;
+ }
+ }
+ }
+ break;
+
+ case WM_PRINTCLIENT:
+ {
+ bool old_cloaked = (!!cloaked);
+ cloaked = true;
+ DCCanvas dc((HDC)wParam, this);
+ paint(&dc, 0);
+ cloaked = old_cloaked;
+
+ if (lParam & PRF_CHILDREN)
+ {
+ RECT wnd_size;
+ GetWindowRect(hwnd, &wnd_size);
+
+ HWND child = GetWindow(hwnd, GW_CHILD);
+ while (child != NULL)
+ {
+ if (GetWindowLongPtrW(child, GWL_STYLE) & WS_VISIBLE)
+ {
+ RECT child_size;
+ GetWindowRect(child, &child_size);
+ if (child_size.right && child_size.bottom)
+ {
+ BltCanvas bitmap(child_size.right, child_size.bottom, child);;
+ SendMessageW(child, WM_PRINT, (WPARAM)bitmap.getHDC(), PRF_CHILDREN | PRF_CLIENT | PRF_NONCLIENT/*| PRF_OWNED*/);
+ //bitmap->makeAlpha(255);
+
+ //set alpha to 255
+ int w, h;
+ bitmap.getDim(&w, &h, NULL);
+ ARGB32 *m_pBits = (ARGB32 *)bitmap.getBits();
+ int nwords = w*h;
+ for (; nwords > 0; nwords--, m_pBits++)
+ {
+ unsigned char *pixel = (unsigned char *)m_pBits;
+ pixel[3] = 255; // alpha
+ }
+
+ POINT offset;
+ offset.x = child_size.left - wnd_size.left;
+ offset.y = child_size.top - wnd_size.top;
+
+ //BLENDFUNCTION blendFn;
+ //blendFn.BlendOp = AC_SRC_OVER;
+ //blendFn.BlendFlags = 0;
+ //blendFn.SourceConstantAlpha = 255;
+ //blendFn.AlphaFormat = 0;
+ //AlphaBlend((HDC)wParam, offset.x, offset.y, child_size.right-child_size.left, child_size.bottom-child_size.top,
+ // bitmap->getHDC(), 0, 0, child_size.right-child_size.left, child_size.bottom-child_size.top, blendFn);
+ StretchBlt((HDC)wParam, offset.x, offset.y, child_size.right-child_size.left, child_size.bottom-child_size.top,
+ bitmap.getHDC(), 0, 0, child_size.right-child_size.left, child_size.bottom-child_size.top, SRCCOPY);
+ }
+ }
+ child = GetWindow(child, GW_HWNDNEXT);
+ }
+
+ }
+ }
+ return 0;
+ //CUT case WM_NCPAINT: return 0;
+ //CUT case WM_SYNCPAINT: return 0;
+
+ case WM_SETCURSOR:
+ if (checkModal()) return TRUE;
+ if (hWnd == (HWND)wParam)
+ {
+ DWORD windowStyle = (DWORD)GetWindowLongPtrW(hWnd, GWL_STYLE);
+ switch(HIWORD(lParam))
+ {
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case 0x020B/*WM_XBUTTONDOWN*/:
+ DisabledWindow_OnMouseClick(hWnd);
+ break;
+ }
+ int ct = BASEWND_CURSOR_POINTER;
+ int _x, _y;
+ Wasabi::Std::getMousePos(&_x, &_y);
+ screenToClient(&_x, &_y);
+ OSCURSORHANDLE c = NULL;
+
+ if (0 == (WS_DISABLED & windowStyle))
+ {
+ if (!handleVirtualChildMsg(WM_SETCURSOR, _x, _y, &ct, &c))
+ {
+ ct = getCursorType(_x, _y);
+ }
+ }
+ wchar_t *wincursor = NULL;
+ switch (ct)
+ {
+ case BASEWND_CURSOR_USERSET:
+
+ if (c == NULL)
+ c = getCustomCursor(_x, _y);
+ if (c != NULL)
+ {
+ SetCursor(c);
+ return TRUE;
+ }
+ else wincursor = IDC_ARROW; // Ensure to have at least a cursor
+ break;
+ case BASEWND_CURSOR_POINTER:
+ wincursor = IDC_ARROW;
+ break;
+ case BASEWND_CURSOR_NORTHSOUTH:
+ wincursor = IDC_SIZENS;
+ break;
+ case BASEWND_CURSOR_EASTWEST:
+ wincursor = IDC_SIZEWE;
+ break;
+ case BASEWND_CURSOR_NORTHWEST_SOUTHEAST:
+ wincursor = IDC_SIZENWSE;
+ break;
+ case BASEWND_CURSOR_NORTHEAST_SOUTHWEST:
+ wincursor = IDC_SIZENESW;
+ break;
+ case BASEWND_CURSOR_4WAY:
+ wincursor = IDC_SIZEALL;
+ break;
+ case BASEWND_CURSOR_EDIT:
+ wincursor = IDC_IBEAM;
+ break;
+ default:
+ wincursor = IDC_ARROW;
+ break;
+ }
+ if (wincursor != NULL)
+ {
+ SetCursor(LoadCursor(NULL, wincursor));
+ return TRUE;
+ }
+ }
+ return FALSE;
+
+ case WM_TIMER:
+ timerCallback((int)wParam);
+ return 0;
+
+ case WM_GETOBJECT:
+ if (lParam == OBJID_CLIENT)
+ {
+ Accessible *acc = getAccessibleObject();
+ if (acc != NULL)
+ {
+ LRESULT lAcc = acc->getOSHandle((int)wParam);
+ return lAcc;
+ }
+ }
+ break; // Fall through to DefWindowProc
+
+
+ case WM_SETFOCUS:
+ if (!focusEventsEnabled) break;
+ if (isInited())
+ {
+ if (rootfocus != NULL && rootfocus != this)
+ {
+ if (rootfocus != curVirtualChildFocus)
+ rootfocus->setFocus();
+ break;
+ }
+ else
+ {
+ if (wantFocus())
+ {
+ onGetFocus();
+ break;
+ }
+ else
+ {
+ ifc_window *w = getTab(TAB_GETFIRST);
+ if (w != NULL)
+ {
+ w->setFocus();
+ }
+ }
+ }
+ }
+ break;
+
+ case WM_KILLFOCUS:
+ {
+ ifc_window *rp = getRootParent();
+ if (!WASABI_API_WND->rootwndIsValid(rp) || !Wasabi::Std::Wnd::isValidWnd(rp->getOsWindowHandle())) break;
+ if (!focusEventsEnabled) break;
+#ifdef WASABI_COMPILE_WND
+ if (WASABI_API_WND) WASABI_API_WND->forwardOnKillFocus(); // resets the keyboard active keys buffer
+#endif
+ if (!WASABI_API_WND->rootwndIsValid(curVirtualChildFocus)) curVirtualChildFocus = NULL;
+ if (curVirtualChildFocus)
+ {
+ curVirtualChildFocus->onKillFocus();
+ curVirtualChildFocus = NULL;
+ }
+ else
+ if (hasfocus) onKillFocus();
+ break;
+ }
+
+ // dragging and dropping
+
+ case WM_LBUTTONDOWN:
+ {
+ if (lParam == 0xdeadc0de)
+ return 1;
+
+ if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam))
+ return 0;
+
+ WASABI_API_WND->popupexit_check(this);
+
+ if (checkModal())
+ return 0;
+
+ abortTip();
+
+ int xPos = (signed short)LOWORD(lParam);
+ int yPos = (signed short)HIWORD(lParam);
+
+ xPos = (int)((float)xPos / getRenderRatio());
+ yPos = (int)((float)yPos / getRenderRatio());
+
+ if (!getCapture() && hasVirtualChildren() && handleVirtualChildMsg(WM_LBUTTONDOWN, xPos, yPos))
+ return 0;
+
+ if (isEnabled() && !dragging)
+ {
+ autoFocus(this);
+
+ int r = 0;
+
+ if (wantLeftClicks())
+ r = onLeftButtonDown(xPos, yPos);
+
+ if (checkDoubleClick(uMsg, xPos, yPos) && wantDoubleClicks() && onLeftButtonDblClk(xPos, yPos))
+ return 0;
+
+ return r;
+ }
+ }
+ break;
+
+ case WM_RBUTTONDOWN:
+ {
+ if (lParam == 0xdeadc0de) return 1;
+ if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0;
+ WASABI_API_WND->popupexit_check(this);
+ if (checkModal()) return 0;
+ abortTip();
+ int xPos = (signed short)LOWORD(lParam);
+ int yPos = (signed short)HIWORD(lParam);
+ xPos = (int)((float)xPos / getRenderRatio());
+ yPos = (int)((float)yPos / getRenderRatio());
+ if (!getCapture() && hasVirtualChildren())
+ if (handleVirtualChildMsg(WM_RBUTTONDOWN, xPos, yPos))
+ return 0;
+ if (isEnabled() && !dragging)
+ {
+ autoFocus(this);
+ int r = 0;
+ if (wantRightClicks())
+ r = onRightButtonDown(xPos, yPos);
+ if (checkDoubleClick(uMsg, xPos, yPos) && wantDoubleClicks()) if (onRightButtonDblClk(xPos, yPos)) return 0;
+ return r;
+ }
+ }
+ break;
+ case WM_MOUSEHOVER:
+ if (checkModal()) return 0;
+ if (!getCapture() && hasVirtualChildren())
+ if (handleVirtualChildMsg(WM_MOUSEHOVER, 0, 0))
+ return 0;
+ break;
+ case WM_MOUSEMOVE:
+ {
+ /* static int mm=0;
+ DebugString("mousemove %d\n", mm++);*/
+ if (checkModal()) return 0;
+ int xPos = (signed short)LOWORD(lParam);
+ int yPos = (signed short)HIWORD(lParam);
+ xPos = (int)((float)xPos / getRenderRatio());
+ yPos = (int)((float)yPos / getRenderRatio());
+ if (dragging)
+ {
+ POINT pt = {xPos, yPos};
+ clientToScreen(&pt);
+ ifc_window *targ;
+ int candrop = 0;
+ // find the window the mouse is over
+
+ targ = NULL;
+ if (stickyWnd)
+ {
+ RECT wr;
+ GetWindowRect(stickyWnd->getOsWindowHandle(), &wr);
+ if (pt.x >= wr.left - sticky.left &&
+ pt.x <= wr.right + sticky.right &&
+ pt.y >= wr.top - sticky.top &&
+ pt.y <= wr.bottom + sticky.bottom) targ = stickyWnd;
+ else stickyWnd = NULL;
+ }
+
+ if (targ == NULL && WASABI_API_WND) targ = WASABI_API_WND->rootWndFromPoint(&pt); // FG> not to self, check
+
+ DI prevtargdi(prevtarg);
+ DI targdi(targ);
+
+ if (prevtarg != targ)
+ {
+ // window switch
+ if (prevtarg != NULL) prevtargdi.dragLeave(this);
+ if (targ != NULL) targdi.dragEnter(this);
+ }
+ if (targ != NULL)
+ candrop = targdi.dragOver(pt.x, pt.y, this);
+ if (targ == NULL || !candrop)
+ SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_NO)));
+ else
+ SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_APPSTARTING)));
+ prevtarg = targ;
+ }
+ else if (isEnabled())
+ {
+ tipbeenchecked = FALSE;
+ if (!getCapture() && hasVirtualChildren())
+ {
+ if (handleVirtualChildMsg(WM_MOUSEMOVE, xPos, yPos))
+ return 0;
+ }
+ if (getCapture())
+ {
+ if (wantMouseMoves())
+ if (onMouseMove(xPos, yPos))
+ return 0;
+ }
+ if (!tipbeenchecked) onTipMouseMove();
+ return 0;
+ }
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ {
+ if (lParam == 0xdeadc0de) return 1;
+ if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0;
+ if (checkModal()) return 0;
+ int xPos = (signed short)LOWORD(lParam);
+ int yPos = (signed short)HIWORD(lParam);
+ xPos = (int)((float)xPos / getRenderRatio());
+ yPos = (int)((float)yPos / getRenderRatio());
+ abortTip();
+ if (!dragging && !getCapture() && hasVirtualChildren())
+ {
+ if (handleVirtualChildMsg(WM_LBUTTONUP, xPos, yPos))
+ return 0;
+ }
+ if (dragging)
+ {
+ clientToScreen(&xPos, &yPos);
+ int res = 0;
+ if (prevtarg != NULL)
+ {
+ res = DI(prevtarg).dragDrop(this, xPos, yPos);
+ }
+
+ // inform source what happened
+ dragComplete(res);
+
+ resetDragSet();
+ prevtarg = NULL;
+ stickyWnd = NULL;
+ suggestedTitle = NULL;
+ SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));
+ Wasabi::Std::Wnd::releaseCapture();
+ dragging = 0;
+ }
+ else if (isEnabled())
+ {
+ if (wantLeftClicks())
+ if (onLeftButtonUp(xPos, yPos)) return 0;
+ }
+ }
+ break;
+
+ case WM_RBUTTONUP:
+ {
+ if (lParam == 0xdeadc0de) return 1;
+ if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0;
+ if (checkModal()) return 0;
+ abortTip();
+ int xPos = (signed short)LOWORD(lParam);
+ int yPos = (signed short)HIWORD(lParam);
+ xPos = (int)((float)xPos / getRenderRatio());
+ yPos = (int)((float)yPos / getRenderRatio());
+ if (!getCapture() && hasVirtualChildren())
+ {
+ if (handleVirtualChildMsg(WM_RBUTTONUP, xPos, yPos))
+ return 0;
+ }
+ if (isEnabled() && !dragging)
+ {
+ if (wantRightClicks())
+ if (onRightButtonUp(xPos, yPos)) return 0;
+ }
+ }
+ break;
+
+ case WM_CONTEXTMENU:
+ {
+ if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0;
+ if (checkModal()) return 0;
+ ASSERT(hWnd != NULL);
+ int xPos = (signed short)LOWORD(lParam);
+ int yPos = (signed short)HIWORD(lParam);
+ if (hWnd == getOsWindowHandle())
+ {
+ if (wantContextMenus())
+ if (onContextMenu(xPos, yPos)) return 0;
+ }
+ else if (GetParent(hWnd) == getOsWindowHandle())
+ {
+ if (wantContextMenus())
+ if (onChildContextMenu(xPos, yPos)) return 0;
+ }
+ }
+ break;
+
+ case WM_ERASEBKGND:
+ return (onEraseBkgnd((HDC)wParam));
+
+ case WM_MOUSEWHEEL:
+ {
+ abortTip();
+
+ int l, a;
+ l = (short)HIWORD(wParam) / 120;
+ a = (short)HIWORD(wParam);
+ if (!l)
+ if (a > 0) l = 1;
+ else if (a < 0)l = 0;
+ a = l >= 0 ? l : -l;
+ if (GetAsyncKeyState(VK_MBUTTON)&0x8000)
+ {
+ if (l >= 0) l = 0; // Fast Forward 5s
+ else l = 1; // Rewind 5s
+ }
+ else
+ {
+ if (l >= 0) l = 2; // Volume up
+ else l = 3; // Volume down
+ }
+
+ int r = 0;
+
+ if (l & 1)
+ r = onMouseWheelDown(!(BOOL)(l & 2), a);
+ else
+ r = onMouseWheelUp(!(BOOL)(l & 2), a);
+ if (r == 0)
+ {
+ r = WASABI_API_WND->forwardOnMouseWheel(l, a);
+ }
+ // if it wasn't handled by this wnd, nor by the api, send it to the main wnd, unless we're it
+ if (r == 0)
+ {
+ if (WASABI_API_WND->main_getRootWnd() != this)
+ r = (int)SendMessageW(WASABI_API_WND->main_getRootWnd()->gethWnd(), uMsg, wParam, lParam);
+ }
+
+ return r;
+ }
+
+ case WM_WA_RELOAD:
+ {
+ if (wParam == 0)
+ freeResources();
+ else
+ reloadResources();
+ return 0;
+ }
+
+ case WM_WA_GETFBSIZE:
+ {
+ SIZE *s = (SIZE *)wParam;
+ s->cx = rwidth;
+ s->cy = rheight;
+ return 0;
+ }
+
+ case WM_USER + 8976: // wheel in tip, delete tip
+ abortTip();
+ return 0;
+
+ case WM_CHAR:
+ if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0;
+ if (WASABI_API_WND->interceptOnChar((TCHAR) wParam)) return 0;
+ if (curVirtualChildFocus == NULL)
+ {
+ if (onChar(((TCHAR) wParam))) return 0;
+ }
+ else
+ {
+ if (curVirtualChildFocus->onChar(((TCHAR) wParam))) return 0;
+ }
+ if (WASABI_API_WND && WASABI_API_WND->forwardOnChar(this, (TCHAR) wParam, (int)lParam)) return 0;
+ break;
+
+ case WM_KEYDOWN:
+ if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0;
+ if (WASABI_API_WND->interceptOnKeyDown((int) wParam)) return 0;
+ if (curVirtualChildFocus == NULL)
+ {
+ if (onKeyDown((int) wParam)) return 0;
+ }
+ else
+ {
+ if (curVirtualChildFocus->onKeyDown((int)wParam)) return 0;
+ }
+ if (WASABI_API_WND && WASABI_API_WND->forwardOnKeyDown(this, (int) wParam, (int)lParam)) return 0;
+ break;
+
+ case WM_KEYUP:
+ if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0;
+ if (WASABI_API_WND->interceptOnKeyUp((int) wParam)) return 0;
+ if (curVirtualChildFocus == NULL)
+ {
+ if (onKeyUp((int) wParam)) return 0;
+ }
+ else
+ {
+ if (curVirtualChildFocus->onKeyUp((int)wParam)) return 0;
+ }
+ if (WASABI_API_WND && WASABI_API_WND->forwardOnKeyUp(this, (int) wParam, (int)lParam)) return 0;
+ break;
+
+ case WM_SYSKEYDOWN:
+ if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0;
+ if (WASABI_API_WND->interceptOnSysKeyDown((int) wParam, (int)lParam)) return 0;
+ if (curVirtualChildFocus == NULL)
+ {
+ if (onSysKeyDown((int) wParam, (int)lParam)) return 0;
+ }
+ else
+ {
+ if (curVirtualChildFocus->onSysKeyDown((int)wParam, (int)lParam)) return 0;
+ }
+ if (WASABI_API_WND && WASABI_API_WND->forwardOnSysKeyDown(this, (int) wParam, (int)lParam)) return 0;
+ break;
+
+ case WM_SYSKEYUP:
+ if (bufferizeLockedUIMsg(uMsg, (int)wParam, (int)lParam)) return 0;
+ if (WASABI_API_WND->interceptOnSysKeyUp((int) wParam, (int)lParam)) return 0;
+ if (curVirtualChildFocus == NULL)
+ {
+ if (onSysKeyUp((int) wParam, (int)lParam)) return 0;
+ }
+ else
+ {
+ if (curVirtualChildFocus->onSysKeyUp((int)wParam, (int)lParam)) return 0;
+ }
+ if (WASABI_API_WND && WASABI_API_WND->forwardOnSysKeyUp(this, (int) wParam, (int)lParam)) return 0;
+ break;
+
+ case WM_MOUSEACTIVATE:
+ {
+ if (checkModal() || !wantActivation())
+ return MA_NOACTIVATE;
+ //SetFocus(getOsWindowHandle());
+ return MA_ACTIVATE;
+ }
+
+ case WM_ACTIVATEAPP:
+
+ if (wParam == FALSE)
+ {
+
+ if (WASABI_API_WND != NULL)
+ {
+ WASABI_API_WND->popupexit_signal();
+ WASABI_API_SYSCB->syscb_issueCallback(SysCallback::GC, GarbageCollectCallback::GARBAGECOLLECT);
+ WASABI_API_WND->kbdReset();
+ if (ghosthwnd.getNumItems() > 0 && ghostbust)
+ {
+ ghostbust = 0; postDeferredCallback(DC_KILLGHOST);
+ }
+ return 0;
+ }
+ }
+
+ break;
+
+ case WM_ACTIVATE:
+ switch(LOWORD(wParam))
+ {
+ case WA_ACTIVE:
+ case WA_CLICKACTIVE:
+ if (WASABI_API_WND != NULL)
+ WASABI_API_WND->popupexit_check(this);
+
+ onActivate();
+
+ if (WA_CLICKACTIVE == LOWORD(wParam))
+ {
+ POINT pt;
+ DWORD pts = GetMessagePos();
+ POINTSTOPOINT(pt, pts);
+ MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1);
+ HWND hTarget = ChildWindowFromPointEx(hwnd, pt, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED | CWP_SKIPTRANSPARENT);
+ if (hTarget && hTarget != hwnd) lastActiveWnd = hTarget;
+ }
+
+ if (lastActiveWnd != hwnd && NULL != lastActiveWnd && IsWindow(lastActiveWnd))
+ {
+ SendMessageW(lastActiveWnd, uMsg, wParam, lParam);
+ return 0;
+ }
+ break;
+ default:
+
+ onDeactivate();
+
+ lastActiveWnd = GetFocus();
+
+ if (NULL != lastActiveWnd && !IsChild(hwnd, lastActiveWnd))
+ lastActiveWnd = NULL;
+
+ {
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(x) (sizeof(x)/sizeof(*x))
+#endif
+ if (NULL != lastActiveWnd && !BaseWnd_IsFrameWindow(lastActiveWnd))
+ {
+ while (lastActiveWnd)
+ {
+ if (BaseWnd_IsFrameWindow(GetWindow(lastActiveWnd, GW_OWNER)))
+ break;
+ lastActiveWnd = GetAncestor(lastActiveWnd, GA_PARENT);
+ }
+ }
+ }
+
+ if (lastActiveWnd != hwnd && NULL != lastActiveWnd)
+ {
+ SendMessageW(lastActiveWnd, uMsg, wParam, lParam);
+ return 0;
+ }
+
+ break;
+ }
+ break;
+
+ case WM_NCACTIVATE:
+ if (allowDeactivation())
+ return TRUE;
+ return FALSE;
+
+ case WM_WINDOWPOSCHANGING:
+ {
+ if (!isVirtual() && Wasabi::Std::Wnd::isPopup(hwnd))
+ {
+ WINDOWPOS *wp = (WINDOWPOS *)lParam;
+ if (wp->x != rx || wp->y != ry) wp->flags |= SWP_NOMOVE;
+ }
+ }
+ break;
+
+ case WM_WINDOWPOSCHANGED:
+ {
+
+ WINDOWPOS *lpwp = (WINDOWPOS *)lParam; // points to size and position data
+ if (lpwp->flags & SWP_HIDEWINDOW)
+ {
+ minimized = 1;
+ onMinimize();
+ }
+ else if (lpwp->flags & SWP_SHOWWINDOW)
+ {
+ minimized = 0;
+ onRestore();
+ }
+
+ if (!inonresize)
+ {
+ int w = rwidth;
+ int h = rheight;
+ multRatio(&w, &h);
+ if (lpwp->cx != w || lpwp->cy != h)
+ {
+ DebugStringW(L"external onResize\n");
+ w = lpwp->cx;
+ h = lpwp->cy;
+ divRatio(&w, &h);
+ setRSize(rx, ry, w, h);
+ if (isPostOnInit())
+ onResize();
+ }
+ }
+
+ onPostedMove();
+ return 0;
+ }
+
+ case WM_DROPFILES:
+ {
+ if (checkModal()) break;
+ WASABI_API_WND->pushModalWnd();
+ onExternalDropBegin();
+ HDROP h = (HDROP)wParam;
+ POINT dp = {0};
+ DragQueryPoint(h, &dp);
+ clientToScreen(&dp);
+ // build a file list
+ wchar_t buf[WA_MAX_PATH] = {0};
+ PtrList<FilenamePS> keep;
+
+ SetCursor(LoadCursor(NULL, IDC_WAIT));
+
+ //CUT #if UTF8
+ //CUT // doesn't really need UTF8, the "buf" is never written to.
+ //CUT // made to be NULL to enforce this concept.
+ int nfiles = DragQueryFile(h, 0xffffffff, NULL, 0);
+ //CUT #else
+ //CUT int nfiles = DragQueryFile(h, 0xffffffff, buf, sizeof(buf));
+ //CUT #endif
+
+ // convert them all to PlayItem *'s
+ for (int i = 0; i < nfiles; i++)
+ {
+ DragQueryFileW(h, i, buf, WA_MAX_PATH);
+ addDroppedFile(buf, &keep); // recursive
+
+ }
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+ dragging = 1;
+ if (dragEnter(this))
+ {
+ if (dragOver(dp.x, dp.y, this)) dragDrop(this, dp.x, dp.y);
+ }
+ else
+ {
+ dragLeave(this);
+#ifdef FORWARD_DRAGNDROP
+ HWND w = WASABI_API_WND->main_getRootWnd()->gethWnd();
+ SendMessageW(w, WM_DROPFILES, wParam, lParam);
+#endif
+
+ }
+ dragging = 0;
+
+ // remove data
+ keep.deleteAll();
+ resetDragSet();
+
+ onExternalDropEnd();
+ WASABI_API_WND->popModalWnd();
+ }
+ return 0; // dropfiles
+
+ case WM_CAPTURECHANGED:
+ /* static int cc=0;
+ DebugString("capture changed! %d\n", cc++);*/
+ if (preventcancelcapture) return 0;
+ inputCaptured = 0;
+ if (curVirtualChildCaptured != NULL)
+ {
+ ifc_window *w = curVirtualChildCaptured;
+ curVirtualChildCaptured = NULL;
+ w->onCancelCapture();
+ }
+ else
+ {
+ onCancelCapture();
+ }
+ return 0;
+
+ } //switch
+
+ if (WINAMP_WM_DIRECT_MOUSE_WHEEL == uMsg &&
+ WM_NULL != WINAMP_WM_DIRECT_MOUSE_WHEEL)
+ {
+ wndProc(hWnd, WM_MOUSEWHEEL, wParam, lParam);
+ return TRUE;
+ }
+
+ if (uMsg >= WM_USER)
+ {
+ int ret;
+ if (onUserMessage(uMsg, (int)wParam, (int)lParam, &ret))
+ return ret;
+ return 0;
+ }
+
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+}
+#endif
+int BaseWnd::onUserMessage(int msg, int w, int l, int *r)
+{
+ return 0;
+}
+
+int BaseWnd::checkDoubleClick(int b, int x, int y)
+{
+#ifdef _WIN32
+ uint32_t now = Wasabi::Std::getTickCount();
+
+ switch (b)
+ {
+ case WM_LBUTTONDOWN:
+ if (lastClick[0] > now - Wasabi::Std::getDoubleClickDelay())
+ {
+ lastClick[0] = 0;
+ if (ABS(lastClickP[0].x - x) > Wasabi::Std::getDoubleClickX() || ABS(lastClickP[0].y - y) > Wasabi::Std::getDoubleClickY()) return 0;
+ return 1;
+ }
+ lastClick[0] = now;
+ lastClickP[0].x = x;
+ lastClickP[0].y = y;
+ break;
+
+ case WM_RBUTTONDOWN:
+ if (lastClick[1] > now - Wasabi::Std::getDoubleClickDelay())
+ {
+ lastClick[1] = 0;
+ if (ABS(lastClickP[1].x - x) > Wasabi::Std::getDoubleClickX() || ABS(lastClickP[1].y - y) > Wasabi::Std::getDoubleClickY()) return 0;
+ return 1;
+ }
+ lastClick[1] = now;
+ lastClickP[1].x = x;
+ lastClickP[1].y = y;
+ break;
+ }
+#else
+#warning port me
+#endif
+ return 0;
+}
+
+int BaseWnd::onMouseWheelUp(int click, int lines)
+{
+ return 0;
+}
+
+int BaseWnd::onMouseWheelDown(int click, int lines)
+{
+ return 0;
+}
+
+int BaseWnd::onContextMenu(int x, int y)
+{
+ return 0;
+}
+
+int BaseWnd::onChildContextMenu(int x, int y)
+{
+ return 0;
+}
+
+int BaseWnd::onDeferredCallback(intptr_t param1, intptr_t param2)
+{
+ switch (param1)
+ {
+ case DEFERREDCB_FLUSHPAINT:
+ do_flushPaint();
+ break;
+ case DEFERREDCB_INVALIDATE:
+ if (isPostOnInit())
+ invalidate();
+ break;
+ case DC_KILLGHOST:
+ if (ghosthwnd.getNumItems() > 0)
+ {
+ preventcancelcapture = 1;
+ for (int i = 0;i < ghosthwnd.getNumItems();i++)
+ Wasabi::Std::Wnd::destroyWnd(ghosthwnd.enumItem(i));
+ ghosthwnd.freeAll();
+ preventcancelcapture = 0;
+ }
+ break;
+ case DEFERREDCB_FOCUSFIRST:
+ assignRootFocus(NULL);
+ if (Wasabi::Std::Wnd::getFocus() == getOsWindowHandle())
+ {
+ focusNext();
+ }
+ break;
+ case 0x7849 /*DEFERREDCB_ONHIDE*/:
+ {
+ foreach(rootwndchildren)
+ ifc_window *w = rootwndchildren.getfor();
+ if (w->isVisible(1)) // check internal flag only
+ w->onSetVisible(0);
+ endfor;
+ dependent_sendEvent(BaseWnd::depend_getClassGuid(), Event_SETVISIBLE, 0);
+ break;
+ }
+ }
+ return 0;
+}
+
+int BaseWnd::onPaint(Canvas *canvas)
+{
+#if 0
+ // example:
+ PaintCanvas c;
+ if (!c.beginPaint(this)) return 0;
+ (do some painting)
+ c will self -destruct on return
+#endif
+ if (renderbasetexture)
+ {
+ PaintCanvas paintcanvas;
+ if (canvas == NULL)
+ {
+ if (!paintcanvas.beginPaint(this)) return 0;
+ canvas = &paintcanvas;
+ }
+ RECT r;
+ getNonClientRect(&r);
+ RenderBaseTexture(canvas, r);
+ }
+ return 0;
+}
+
+int BaseWnd::onPaint(Canvas *canvas, api_region *h)
+{
+ if (!canvas) return onPaint(canvas);
+
+#ifdef _WIN32
+ int sdc = SaveDC(canvas->getHDC());
+#elif defined(__APPLE__)
+ CGContextSaveGState(canvas->getHDC());
+#endif
+
+ canvas->selectClipRgn(h);
+
+ int rs = onPaint(canvas);
+
+#ifdef _WIN32
+ RestoreDC(canvas->getHDC(), sdc);
+#elif defined(__APPLE__)
+ CGContextRestoreGState(canvas->getHDC());
+#endif
+
+ return rs;
+}
+
+int BaseWnd::getTransparency()
+{
+ return wndalpha;
+}
+
+void BaseWnd::setTransparency(int amount)
+{
+ //if (wndalpha == amount) return;
+ if (amount == 254) amount = 255;
+ if (amount == 1) amount = 0;
+
+ if (amount != -1) wndalpha = amount; else amount = wndalpha;
+
+ if (!Wasabi::Std::Wnd::isDesktopAlphaAvailable())
+ {
+ wndalpha = 255;
+ return ;
+ }
+
+ if (w2k_alpha)
+ {
+ invalidate();
+ return ;
+ }
+
+#ifdef WIN32
+
+ if (!isInited() || isVirtual()) return ;
+ if (!Wasabi::Std::Wnd::isValidWnd(getOsWindowHandle())) return ;
+
+ if (amount < -1) amount = 0;
+ else if (amount > 255) amount = 255;
+
+ //CUT DWORD dwLong = GetWindowLong(hwnd, GWL_EXSTYLE);
+ if (amount == 255 && !forceTransparencyFlag())
+ {
+ Wasabi::Std::Wnd::setLayeredWnd(hwnd, FALSE);
+ //CUT if (dwLong & WS_EX_LAYERED)
+ //CUT SetWindowLong(hwnd, GWL_EXSTYLE, dwLong & ~WS_EX_LAYERED);
+ has_alpha_flag = 0;
+ }
+ else
+ {
+ if (!Wasabi::Std::Wnd::isLayeredWnd(hwnd))
+ Wasabi::Std::Wnd::setLayeredWnd(hwnd, TRUE);
+ //CUT if (!(dwLong & WS_EX_LAYERED))
+ //CUT SetWindowLong(hwnd, GWL_EXSTYLE, dwLong | WS_EX_LAYERED);
+ Wasabi::Std::Wnd::setLayeredAlpha(hwnd, amount);
+ //CUT setLayeredWindowAttributes(hwnd, RGB(0,0,0), amount, LWA_ALPHA);
+ has_alpha_flag = 1;
+ }
+#endif
+}
+
+int BaseWnd::forceTransparencyFlag()
+{
+ return 0;
+}
+
+int BaseWnd::beginCapture()
+{
+ if (!getCapture())
+ {
+ disable_tooltip_til_recapture = 0;
+ curVirtualChildCaptured = NULL;
+ /* oldCapture = */Wasabi::Std::Wnd::setCapture(getOsWindowHandle());
+ /* if (oldCapture) {
+ DebugString("Stolen capture detected, this may be ok, but try to avoid it if possible. Saving old capture\n");
+ }*/
+ inputCaptured = 1;
+ }
+ return 1;
+}
+
+int BaseWnd::endCapture()
+{
+ preventcancelcapture = 1;
+ if (Wasabi::Std::Wnd::getCapture() == getOsWindowHandle()) Wasabi::Std::Wnd::releaseCapture();
+ /* if (oldCapture) {
+ DebugString("Restoring old capture\n");
+ SetCapture(oldCapture);
+ oldCapture = NULL;
+ }*/
+ inputCaptured = 0;
+ preventcancelcapture = 0;
+ return 1;
+}
+
+int BaseWnd::getCapture()
+{
+ if (inputCaptured && Wasabi::Std::Wnd::getCapture() == getOsWindowHandle() && curVirtualChildCaptured == NULL) return 1;
+ return 0;
+}
+
+void BaseWnd::cancelCapture()
+{
+ if (curVirtualChildCaptured != NULL)
+ {
+ curVirtualChildCaptured->cancelCapture();
+ return ;
+ }
+ if (getCapture()) endCapture();
+ onCancelCapture();
+}
+
+int BaseWnd::onMouseMove(int x, int y)
+{
+ onTipMouseMove();
+ return 0;
+}
+
+void BaseWnd::onTipMouseMove()
+{
+ POINT p;
+
+ if (dragging) return ;
+ if (disable_tooltip_til_recapture) return ;
+
+ tipbeenchecked = TRUE;
+
+ Wasabi::Std::getMousePos(&p);
+
+ if (WASABI_API_WND->rootWndFromPoint(&p) != (ifc_window *)this)
+ {
+ // leaving area
+ tip_done = FALSE;
+ if (tipawaytimer)
+ killTimer(TIP_AWAY_ID);
+ tipawaytimer = FALSE;
+ if (tipshowtimer)
+ {
+ // TODO: on the mac, use CreateMouseTrackingRegion
+ TRACKMOUSEEVENT tracker;
+ tracker.cbSize=sizeof(tracker);
+ tracker.dwFlags = TME_HOVER|TME_CANCEL;
+ tracker.hwndTrack = this->getOsWindowHandle();
+ tracker.dwHoverTime = TIP_TIMER_THRESHOLD;
+
+ TrackMouseEvent(&tracker);
+ }
+ tipshowtimer = FALSE;
+ destroyTip();
+ }
+ else
+ {
+ // moving in area
+ const wchar_t *t = getTip();
+ if (!disable_tooltip_til_recapture && !tipshowtimer && !tip_done && t != NULL && *t != 0)
+ {
+ //entering area & need tip
+
+ // TODO: on the mac, use CreateMouseTrackingRegion
+ TRACKMOUSEEVENT tracker;
+ tracker.cbSize=sizeof(tracker);
+ tracker.dwFlags = TME_HOVER;
+ tracker.hwndTrack = this->getOsWindowHandle();
+ tracker.dwHoverTime = TIP_TIMER_THRESHOLD;
+
+ TrackMouseEvent(&tracker);
+
+ tipshowtimer = TRUE;
+ }
+ /*else if (tipshowtimer)
+ {
+ TRACKMOUSEEVENT tracker;
+ tracker.cbSize=sizeof(tracker);
+ tracker.dwFlags = TME_HOVER;
+ tracker.hwndTrack = this->getOsWindowHandle();
+ tracker.dwHoverTime = TIP_TIMER_THRESHOLD;
+
+ TrackMouseEvent(&tracker);
+ }*/
+ }
+}
+
+int BaseWnd::onLeftButtonDblClk(int x, int y)
+{
+ return 0;
+}
+
+int BaseWnd::onRightButtonDblClk(int x, int y)
+{
+ return 0;
+}
+
+int BaseWnd::onGetFocus()
+{
+ // return TRUE if you override this
+ hasfocus = 1;
+ notifyParent(ChildNotify::GOTFOCUS);
+ getRootParent()->onSetRootFocus(this);
+ invalidate();
+ Accessible *a = getAccessibleObject();
+ if (a != NULL)
+ a->onGetFocus();
+ return 1;
+}
+
+int BaseWnd::onKillFocus()
+{
+ // return TRUE if you override this
+ hasfocus = 0;
+ notifyParent(ChildNotify::KILLFOCUS);
+ invalidate();
+ return 1;
+}
+
+#if defined(_WIN64)
+int BaseWnd::childNotify(ifc_window* child, int msg, int p1, int p2)
+{
+ return 0;
+}
+#else
+int BaseWnd::childNotify(ifc_window *child, int msg, intptr_t p1, intptr_t p2)
+{
+ return 0;
+}
+#endif
+
+int BaseWnd::addDragItem(const wchar_t *droptype, void *item)
+{
+ ASSERT(droptype != NULL);
+ if (item == NULL) return -1;
+ DragSet *set;
+ int pos = dragCheckData(droptype);
+ if (pos == -1)
+ {
+ set = new DragSet();
+ set->setName(droptype);
+ dragsets.addItem(set);
+ pos = dragsets.getNumItems() - 1;
+ }
+ else set = dragsets[pos];
+ set->addItem(item);
+ return pos;
+}
+
+#ifdef _WIN32
+int BaseWnd::handleDrag()
+{
+ abortTip();
+ if (dragsets.getNumItems() == 0) return 0;
+
+ Wasabi::Std::Wnd::setCapture(hwnd);
+ SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_APPSTARTING)));
+
+ dragging = 1;
+ stickyWnd = NULL;
+
+ return 1;
+}
+#endif
+
+int BaseWnd::resetDragSet()
+{
+ dragsets.deleteAll();
+ return 1;
+}
+
+int BaseWnd::dragEnter(ifc_window *sourceWnd)
+{
+ ifc_window *rw = getParent(); //api_window::rootwndFromRootWnd(getParent()); //FG> note to self, check!
+ if (rw) return DI(rw).dragEnter(sourceWnd);
+ return 0;
+}
+
+int BaseWnd::dragSetSticky(ifc_window *wnd, int left, int right, int up, int down)
+{
+ ASSERT(dragging);
+ stickyWnd = wnd;
+
+ if (left < 0) left = 0;
+ if (right < 0) right = 0;
+ if (up < 0) up = 0;
+ if (down < 0) down = 0;
+
+ Wasabi::Std::setRect(&sticky, left, up, right, down);
+
+ return 1;
+}
+
+void BaseWnd::setSuggestedDropTitle(const wchar_t *title)
+{
+ ASSERT(title != NULL);
+ suggestedTitle = title;
+}
+
+const wchar_t *BaseWnd::dragGetSuggestedDropTitle()
+{
+ return suggestedTitle; // can be NULL
+}
+
+int BaseWnd::dragCheckData(const wchar_t *type, int *nitems)
+{
+ for (int i = 0; i < dragsets.getNumItems(); i++)
+ {
+ if (!WCSICMP(type, dragsets[i]->getName()))
+ {
+ if (nitems != NULL) *nitems = dragsets[i]->getNumItems();
+ return i;
+ }
+ }
+ return -1;
+}
+
+void *BaseWnd::dragGetData(int slot, int itemnum)
+{
+ if (slot < 0 || slot >= dragsets.getNumItems()) return 0;
+ if (itemnum < 0 || itemnum >= dragsets[slot]->getNumItems()) return 0;
+ return dragsets[slot]->enumItem(itemnum);
+}
+
+void BaseWnd::addDroppedFile(const wchar_t *filename, PtrList<FilenamePS> *plist)
+{
+#ifdef RECURSE_SUBDIRS_ON_DROP
+ const char *slash = filename + STRLEN(filename) - 1;
+ for (; slash > filename; slash--) if (*slash == '/' || *slash == '\\') break;
+ if (STREQL(slash + 1, ".") || STREQL(slash + 1, "..")) return ;
+
+ char buf[WA_MAX_PATH] = {0};
+ STRCPY(buf, filename);
+ // try to resolve shortcuts
+ char *ext = buf + STRLEN(buf) - 1;
+ for (; ext > buf; ext--) if (*ext == '.' || *ext == '\\' || *ext == '/') break;
+#ifdef WIN32
+ if (!STRICMP(ext, ".lnk"))
+ {
+ char buf2[MAX_PATH] = {0};
+ if (StdFile::resolveShortcut(buf, buf2)) STRCPY(buf, buf2);
+ }
+#endif
+
+ int isdir = 0;
+
+ // handle root dir specially?
+ WIN32_FIND_DATA data = {0};
+ HANDLE r = FindFirstFile(buf, &data);
+ if (!r) return ;
+ FindClose(r);
+ if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) isdir = 1;
+
+ if (isdir)
+ {
+ onExternalDropDirScan(buf);
+
+ // enumerate that dir
+ char search[WA_MAX_PATH] = {0};
+ wsprintf(search, "%s\\*.*", buf);
+ HANDLE files = FindFirstFile(search, &data);
+ if (files == INVALID_HANDLE_VALUE) return ; // nothin' in it
+ for (;;)
+ {
+ wchar_t obuf[WA_MAX_PATH] = {0};
+ swprintf(obuf, L"%s\\%s", buf, data.cFileName);
+ addDroppedFile(obuf, plist);
+ if (!FindNextFile(files, &data))
+ {
+ FindClose(files);
+ return ;
+ }
+ }
+
+ // should never get here
+ }
+ else
+ {
+ addDragItem(DD_FILENAME, plist->addItem(new FilenamePS(StringPrintfW(L"file:%s", buf))));
+ }
+#else
+ addDragItem(DD_FILENAME, plist->addItem(new FilenamePS(StringPrintfW(L"file:%s", filename))));
+#endif
+}
+
+bool BaseWnd::getNoCopyBits(void)
+{
+ return ncb;
+}
+
+void BaseWnd::setNoCopyBits(bool newncb)
+{
+ ncb = newncb;
+}
+
+int BaseWnd::onEraseBkgnd(HDC dc)
+{
+ return 1;
+}
+
+void BaseWnd::setIcon(OSICONHANDLE icon, int _small)
+{
+ Wasabi::Std::Wnd::setIcon(getOsWindowHandle(), icon, !_small);
+ //CUT SendMessageW(getOsWindowHandle(), WM_SETICON, _small ? ICON_SMALL : ICON_BIG, (int)icon);
+}
+
+const wchar_t *BaseWnd::getTip()
+{
+ return tip;
+}
+
+void BaseWnd::setTip(const wchar_t *_tooltip)
+{
+ tip = _tooltip;
+ abortTip();
+}
+
+int BaseWnd::getStartHidden()
+{
+ return start_hidden;
+}
+
+void BaseWnd::abortTip()
+{
+ if (tipshowtimer)
+ {
+ // TODO: on the mac, use CreateMouseTrackingRegion
+ TRACKMOUSEEVENT tracker;
+ tracker.cbSize=sizeof(tracker);
+ tracker.dwFlags = TME_HOVER|TME_CANCEL;
+ tracker.hwndTrack = this->getOsWindowHandle();
+ tracker.dwHoverTime = TIP_TIMER_THRESHOLD;
+
+ TrackMouseEvent(&tracker);
+ }
+ tipshowtimer = FALSE;
+ if (tipawaytimer)
+ killTimer(TIP_AWAY_ID);
+ tipawaytimer = FALSE;
+ if (tipdestroytimer)
+ killTimer(TIP_DESTROYTIMER_ID);
+ tipdestroytimer = FALSE;
+ destroyTip();
+ tip_done = FALSE;
+ RECT r;
+ if (getOsWindowHandle() && Wasabi::Std::Wnd::getUpdateRect(getOsWindowHandle(), &r) != 0) // FG> avoids xoring over disapearing tip
+ repaint();
+}
+
+int BaseWnd::isVisible(int within)
+{
+ if (!isVirtual() && !getOsWindowHandle()) return 0;
+ if (!this_visible) return 0;
+
+ if (within) return this_visible; // whatever, local
+
+ if (isVirtual()) // virtual, global
+ if (getParent())
+ return getParent()->isVisible();
+ else
+ return 0;
+
+ // non virtual, global
+ if (Wasabi::Std::Wnd::isPopup(getOsWindowHandle())) return this_visible;
+ if (!Wasabi::Std::Wnd::isValidWnd(Wasabi::Std::Wnd::getParent(getOsWindowHandle()))) return 0;
+ if (getParent()) return getParent()->isVisible(); // not a popup, check its parent or fail
+ return this_visible;
+}
+
+void BaseWnd::registerRootWndChild(ifc_window *child)
+{
+ rootwndchildren.addItem(child);
+ if (child->isVirtual())
+ virtualChildren.addItem(child);
+}
+
+void BaseWnd::unregisterRootWndChild(ifc_window *child)
+{
+ delTabOrderEntry(child);
+ rootwndchildren.removeItem(child);
+ if (curVirtualChildCaptured == child)
+ {
+ setVirtualChildCapture(NULL);
+ }
+ if (curVirtualChildFocus == child)
+ curVirtualChildFocus = NULL;
+ virtualChildren.removeItem(child);
+ //WASABI_API_WND->timer_remove(this, -1);
+ if (isPostOnInit() && isVisible())
+ postDeferredCallback(DEFERREDCB_INVALIDATE, 0);
+}
+
+int BaseWnd::isVirtual()
+{
+ return 0;
+}
+
+//CUT?inline int isInRect(RECT *r,int x,int y) {
+//CUT? if (x>=r->left&&x<=r->right&&y>=r->top&&y<=r->bottom) return 1;
+//CUT? return 0;
+//CUT?}
+
+int BaseWnd::ensureVirtualCanvasOk()
+{
+ RECT ncr;
+
+ if (isVirtual() && getParent()) return 1;
+
+ int size_w = rwidth;
+ int size_h = rheight;
+
+ if (!size_w || !size_h) return 0;
+
+ if (!virtualCanvas || virtualCanvasH != size_h || virtualCanvasW != size_w)
+ {
+ if (virtualCanvas)
+ {
+ deleteFrameBuffer(virtualCanvas);
+ virtualCanvas = NULL;
+ }
+ delete scalecanvas;
+ scalecanvas = NULL;
+ virtualCanvas = createFrameBuffer(size_w, size_h);
+ prepareFrameBuffer(virtualCanvas, size_w, size_h);
+ virtualCanvas->setBaseWnd(this);
+ virtualCanvasH = size_h; virtualCanvasW = size_w;
+ BaseWnd::getNonClientRect(&ncr);
+ deferedInvalidateRect(&ncr);
+ }
+ return 1;
+}
+
+Canvas *BaseWnd::createFrameBuffer(int w, int h)
+{
+ return new BltCanvas(w, h, getOsWindowHandle());
+}
+
+void BaseWnd::prepareFrameBuffer(Canvas *canvas, int w, int h)
+{
+ RECT r = {0, 0, w, h};
+ RegionI reg(&r);
+ virtualBeforePaint(&reg);
+#ifdef _WIN32
+ canvas->selectClipRgn(NULL);
+ canvas->fillRect(&r, 0);
+#elif defined(__APPLE__)
+ CGContextClearRect(canvas->getHDC(), CGRectInfinite); // TODO: make "clear" function in canvas
+#endif
+ virtualAfterPaint(&reg);
+}
+
+void BaseWnd::deleteFrameBuffer(Canvas *canvas)
+{
+ delete canvas;
+}
+
+// paints the client content, followed by the virtual child tree. recursive
+int BaseWnd::paintTree(Canvas *canvas, api_region *r)
+{
+ onPaint(canvas, r);
+
+#ifdef WASABI_DRAW_FOCUS_RECT
+ if (gotFocus())
+ {
+ RECT ncr;
+ getNonClientRect(&ncr);
+ // try to use skinned focus rect
+ if (WASABI_API_WND->paintset_present(Paintset::FOCUSRECT))
+ WASABI_API_WND->paintset_render(Paintset::FOCUSRECT, canvas, &ncr, 128);
+ else // otherwise this looks kinda nice :P
+ canvas->drawRect(&ncr, 0, 0xFFFFFF, 128);
+ }
+#endif
+
+ if (isVirtual() && !hasVirtualChildren()) return 0;
+
+ api_region *hostrgn = NULL;
+ api_region *update = r;
+
+ if (!(hwnd != NULL && getParent() == NULL))
+ {
+ hostrgn = getRegion();
+ update = r->clone();
+ if (hostrgn && !isRectRgn())
+ {
+ RECT ncr = clientRect();
+ api_region *hostclone = hostrgn->clone();
+ hostclone->addRegion(getComposedRegion());
+ hostclone->offset(ncr.left, ncr.top);
+ update->andRegion(hostclone);
+ hostrgn->disposeClone(hostclone);
+ }
+ }
+
+ RegionI client_update;
+ for (int i = 0;i < virtualChildren.getNumItems();i++)
+ {
+ if (!virtualChildren[i]->isVisible(1)) continue;
+ RECT rChild;
+ ifc_window *w = virtualChildren[i];
+ w->getNonClientRect(&rChild);
+ if ((rChild.right != rChild.left) && (rChild.bottom != rChild.top))
+ if (update->intersectRect(&rChild, &client_update))
+ {
+ w->paintTree(canvas, &client_update);
+ }
+ }
+
+ if (update != r) r->disposeClone(update);
+
+ return 1;
+}
+
+void BaseWnd::setVirtualCanvas(Canvas *c)
+{
+ virtualCanvas = c;
+}
+
+int BaseWnd::pointInWnd(POINT *p)
+{
+ RECT r;
+ if (!isVisible(1)) return 0;
+ getWindowRect(&r);
+ if (!Wasabi::Std::pointInRect(r, *p))
+ return 0;
+ for (int i = 0; i < getNumRootWndChildren(); i++)
+ {
+ ifc_window *c = enumRootWndChildren(i);
+ if (!c->isVisible(1)) continue;
+ RECT rChild;
+ c->getWindowRect(&rChild);
+ if (Wasabi::Std::pointInRect(rChild, *p))
+ return 0;
+ }
+ //NONPORTABLE
+ /* HWND child = GetWindow(getOsWindowHandle(), GW_CHILD);
+ while (child != NULL) {
+ if (IsWindowVisible(child)) {
+ RECT r2;
+ GetWindowRect(child, &r2);
+ if (Std::pointInRect(r2, *p))
+ return 0;
+ }
+ child = GetWindow(child, GW_HWNDNEXT);
+ }*/
+ return 1;
+}
+
+int BaseWnd::paint(Canvas *c, api_region *r)
+{
+ if (isVirtual())
+ {
+ RegionI d;
+ RECT cr;
+ getClientRect(&cr);
+ if (r == NULL)
+ {
+ d.addRect(&cr);
+ }
+ else
+ {
+ d.addRegion(r);
+ d.offset(cr.left, cr.top);
+ }
+ ifc_window *rp = getRootParent();
+ deferedInvalidate();
+ rp->paint(NULL, &d);
+ BltCanvas *cc = static_cast<BltCanvas*>(rp->getFrameBuffer());
+ if (r != NULL) c->selectClipRgn(r);
+ cc->blit(cr.left, cr.top, c, 0, 0, cr.right - cr.left, cr.bottom - cr.top);
+ return 1;
+ }
+
+ if (!ensureVirtualCanvasOk()) return 0;
+ RegionI *deleteme = NULL;
+ if (r == NULL)
+ {
+ RECT cr;
+ getNonClientRect(&cr);
+ deleteme = new RegionI(&cr);
+ r = deleteme;
+ }
+
+ virtualBeforePaint(r);
+
+ RECT rcPaint;
+ r->getBox(&rcPaint);
+
+ double ra = getRenderRatio();
+
+ if (deferedInvalidRgn)
+ {
+ api_region *nr = NULL;
+ if (renderRatioActive())
+ {
+ nr = r->clone();
+ double d = 1.0 / ra;
+ nr->scale(d, d, TRUE);
+ }
+
+ if (deferedInvalidRgn->isEmpty() == 0)
+ {
+ // some deferednvalidated regions needs to be repainted
+ // TODO: need a "clear region" function in canvas
+ api_region *i = deferedInvalidRgn->clone();
+#ifdef _WIN32
+ FillRgn(virtualCanvas->getHDC(), i->getOSHandle(), (HBRUSH)GetStockObject(BLACK_BRUSH));
+#elif defined(__APPLE__)
+ CGContextSaveGState(virtualCanvas->getHDC());
+ virtualCanvas->selectClipRgn(i);
+ CGContextClearRect(virtualCanvas->getHDC(), CGRectInfinite);
+// virtualCanvas->selectClipRgn(0);
+ CGContextRestoreGState(virtualCanvas->getHDC());
+#endif
+ paintTree(virtualCanvas, i);
+
+ deferedValidateRgn(i);
+ deferedInvalidRgn->disposeClone(i);
+
+ }
+ if (nr) r->disposeClone(nr);
+ }
+
+ virtualAfterPaint(r);
+
+ if (c != NULL)
+ {
+ commitFrameBuffer(c, &rcPaint, ra); //TH WDP2-212
+ }
+
+ delete deleteme;
+ return 1;
+}
+
+int BaseWnd::virtualOnPaint()
+{
+#ifdef _WIN32
+ RECT cr;
+ getNonClientRect(&cr);
+ if (cr.left >= cr.right || cr.top >= cr.bottom) return 0;
+
+ if (!ensureVirtualCanvasOk()) return 0;
+
+ RegionI reg;
+
+ //CUT GetUpdateRgn(getOsWindowHandle(), r->getOSHandle(), FALSE);
+ Wasabi::Std::Wnd::getUpdateRegion(getOsWindowHandle(), reg.getOSHandle());
+
+ PaintCanvas paintcanvas;
+ if (!paintcanvas.beginPaint(this))
+ {
+ virtualAfterPaint(&reg); return 0;
+ }
+
+ // DO NOT DELETE - This looks like it does nothing, but it actually makes the GDI call us again with WM_PAINT if some window
+ // moves over this one between BeginPaint and EndPaint. We still use GetUpdateRgn so we don't have to check for
+ // the version of Windows. See doc. If this function is not available (should be here in 95/98/NT/2K, but we never know)
+ // then we use the rcPaint rect... less precise, but still works.
+ //CUT if (getRandomRgn) {
+ if (Wasabi::Std::Wnd::haveGetRandomRegion())
+ {
+ RegionI zap;
+ //CUT getRandomRgn(paintcanvas.getHDC(), zap.getOSHandle(), SYSRGN);
+ Wasabi::Std::Wnd::getRandomRegion(paintcanvas.getHDC(), zap.getOSHandle());
+ }
+ else
+ {
+ RECT z;
+ paintcanvas.getRcPaint(&z);
+ reg.setRect(&z);
+ }
+
+ // -------------
+
+ /*// for debug
+ HDC dc = GetDC(getOsWindowHandle());
+ InvertRgn(dc, r->getHRGN());
+ InvertRgn(dc, r->getHRGN());
+ ReleaseDC(getOsWindowHandle(), dc);*/
+
+ paint(&paintcanvas, &reg);
+#else
+#warning port me or remove me
+#endif
+
+ return 1;
+}
+
+ifc_window *BaseWnd::enumVirtualChild(int _enum)
+{
+ return virtualChildren[_enum];
+}
+
+int BaseWnd::getNumVirtuals()
+{
+ return virtualChildren.getNumItems();
+}
+
+ifc_window *BaseWnd::enumRootWndChildren(int n)
+{
+ return rootwndchildren.enumItem(n);
+}
+
+int BaseWnd::getNumRootWndChildren()
+{
+ return rootwndchildren.getNumItems();
+}
+
+ifc_window *BaseWnd::findRootWndChild(int x, int y, int only_virtuals)
+{
+ for (int i = getNumRootWndChildren() - 1; i > -1; i--)
+ {
+ RECT r;
+ ifc_window *child = enumRootWndChildren(i);
+ //DebugStringW(L"findRootWndChild = entering = %s\n", child->getId());
+ if (only_virtuals && !child->isVirtual()) continue;
+ child->getNonClientRect(&r);
+ int _x = x;
+ int _y = y;
+ if (!child->isVirtual())
+ {
+ POINT pt;
+ child->getPosition(&pt);
+ _x -= pt.x;
+ _y -= pt.y;
+ }
+ int iv = child->isVisible(1);
+ //int gpa = child->getPaintingAlpha();
+ POINT _p = Wasabi::Std::makePoint(_x, _y);
+ if (iv /*&& gpa > 0*/ && Wasabi::Std::pointInRect(r, _p))
+ {
+ // GROUP
+ ifc_window *z = child->findRootWndChild(_x, _y);
+ if (z) return z;
+ }
+ /*gpa > 0 &&*/
+ /*if (iv && _x>=r.left&&_x<=r.right&&_y>=r.top&&_y<=r.bottom && !child->isClickThrough() && child->ptInRegion(_x, _y)) {
+ return child;
+ }*/
+ }
+ return (!isClickThrough() && ptInRegion(x, y)) ? this : NULL;
+}
+
+//PORTME
+int BaseWnd::handleVirtualChildMsg(UINT uMsg, int x, int y, void *p, void *d)
+{
+#ifdef _WIN32
+ ifc_window *child = NULL;
+
+ if (curVirtualChildCaptured)
+ child = curVirtualChildCaptured;
+ else
+ child = findRootWndChild(x, y, 1); // warning, can return this which is not virtual
+
+ // ASSERT(child != NULL); // BU this came up and I don't know why, looks like it should never happen
+ // FG> actually it can happen when coming back from a popup menu when cpu usage is high, the window might be
+ // hidden (destroying) and ptInRegion returns false.
+ if (!child) return 0;
+
+ //int isvirtual = child->isVirtual();
+
+ if (child) child = child->getForwardWnd();
+
+ if (child && child->isEnabled())
+ {
+ switch (uMsg)
+ {
+ case WM_LBUTTONDOWN:
+ /* if (isvirtual && child != curVirtualChildFocus)
+ focusVirtualChild(child);*/
+ autoFocus(child);
+ if (child->wantLeftClicks())
+ child->onLeftButtonDown(x, y);
+ if (child->checkDoubleClick(uMsg, x, y) && child->wantDoubleClicks())
+ child->onLeftButtonDblClk(x, y);
+ return 1;
+ case WM_RBUTTONDOWN:
+ /* if (isvirtual && child != curVirtualChildFocus)
+ focusVirtualChild(child);*/
+ autoFocus(child);
+ if (child->wantRightClicks())
+ child->onRightButtonDown(x, y);
+ if (child->checkDoubleClick(uMsg, x, y) && child->wantDoubleClicks())
+ child->onRightButtonDblClk(x, y);
+ return 1;
+ case WM_LBUTTONUP:
+ if (child->wantLeftClicks())
+ child->onLeftButtonUp(x, y);
+ return 1;
+ case WM_RBUTTONUP:
+ if (child->wantRightClicks())
+ child->onRightButtonUp(x, y);
+ return 1;
+ case WM_MOUSEMOVE:
+ {
+ if (curVirtualChildCaptured == child || (curVirtualChildCaptured == NULL))
+ {
+ if (child->wantMouseMoves())
+ child->onMouseMove(x, y);
+ return 1;
+ }
+ return 0;
+ }
+ case WM_MOUSEHOVER:
+ ((BaseWnd *)child)->onTip();
+ break;
+ case WM_SETCURSOR:
+ int a = child->getCursorType(x, y);
+ if (!p) return 0;
+ *(int *)p = a;
+ if (a == BASEWND_CURSOR_USERSET)
+ {
+ OSCURSORHANDLE c = child->getCustomCursor(x, y);
+ if (!d) return 0;
+ *(OSCURSORHANDLE *)d = c;
+ }
+ return 1;
+ }
+ }
+#else
+#warning port me or remove me
+#endif
+ return 0;
+}
+
+int BaseWnd::onLeftButtonDown(int x, int y)
+{
+ disable_tooltip_til_recapture = 1;
+ abortTip();
+ return 0;
+}
+
+int BaseWnd::onLeftButtonUp(int x, int y)
+{
+ disable_tooltip_til_recapture = 1;
+ abortTip();
+ return 0;
+}
+
+void BaseWnd::setVirtualChildCapture(ifc_window *child)
+{
+ if (child)
+ {
+ if (!inputCaptured)
+ {
+ beginCapture();
+ }
+ }
+ else
+ {
+ endCapture();
+ }
+ curVirtualChildCaptured = child;
+}
+
+ifc_window *BaseWnd::getVirtualChildCapture()
+{
+ if (inputCaptured && Wasabi::Std::Wnd::getCapture() == getOsWindowHandle())
+ return curVirtualChildCaptured;
+ else
+ if (inputCaptured) inputCaptured = 0;
+ return NULL;
+}
+
+ifc_window *BaseWnd::getBaseTextureWindow()
+{
+ // return our base texture window if we have it
+ if (btexture)
+ return btexture;
+ // return our parent's if they have it
+ if (getParent())
+ return getParent()->getBaseTextureWindow();
+ else
+ return NULL;
+}
+
+void BaseWnd::renderBaseTexture(ifc_canvas *c, const RECT &r, int alpha)
+{
+ WASABI_API_WND->skin_renderBaseTexture(getBaseTextureWindow(), c, r, this, alpha);
+}
+
+void BaseWnd::setBaseTextureWindow(ifc_window *w)
+{
+ btexture = w;
+}
+
+void BaseWnd::setNotifyWindow(ifc_window *newnotify)
+{
+ notifyWindow = newnotify;
+}
+
+ifc_window *BaseWnd::getNotifyWindow()
+{
+ return destroying ? NULL : notifyWindow;
+}
+
+int BaseWnd::gotFocus()
+{
+ return hasfocus && curVirtualChildFocus == NULL;
+}
+
+int BaseWnd::isActive()
+{
+ OSWINDOWHANDLE h = hwnd;
+ if (h == NULL)
+ {
+ ifc_window *par = getParent();
+ if (par == NULL) return 0;
+ h = par->getOsWindowHandle();
+ }
+ if (h == NULL) return 0;
+ return (Wasabi::Std::Wnd::getActiveWindow() == h);
+}
+
+int BaseWnd::onChar(unsigned int c)
+{
+ switch (c)
+ {
+ case 9: // TAB
+ if (Std::keyModifier(STDKEY_SHIFT))
+ focusPrevious();
+ else
+ focusNext();
+ return 1;
+ }
+ return 0;
+}
+
+/*int BaseWnd::focusVirtualChild(api_window *child) {
+ if (!gotFocus()) setFocus();
+ if (!child->wantFocus()) return 0;
+ setVirtualChildFocus(child);
+ return 1;
+}*/
+
+int BaseWnd::wantFocus()
+{
+ return 0;
+}
+
+// Return 1 if there is a modal window that is not this
+int BaseWnd::checkModal()
+{
+ if (bypassModal()) return 0;
+ ifc_window *w = WASABI_API_WND->getModalWnd();
+ if (w && w != static_cast<ifc_window*>(this) && w != getDesktopParent())
+ {
+ return 1;
+ }
+ return 0;
+}
+
+int BaseWnd::cascadeRepaintFrom(ifc_window *who, int pack)
+{
+ RECT r;
+ BaseWnd::getNonClientRect(&r);
+ return BaseWnd::cascadeRepaintRect(&r, pack);
+}
+
+int BaseWnd::cascadeRepaint(int pack)
+{
+ return cascadeRepaintFrom(this, pack);
+}
+
+int BaseWnd::cascadeRepaintRgn(api_region *r, int pack)
+{
+ return cascadeRepaintRgnFrom(r, this, pack);
+}
+
+int BaseWnd::cascadeRepaintRect(RECT *r, int pack)
+{
+ return cascadeRepaintRectFrom(r, this, pack);
+}
+
+int BaseWnd::cascadeRepaintRectFrom(RECT *r, ifc_window *who, int pack)
+{
+ RegionI reg(r);
+ int rt = cascadeRepaintRgnFrom(&reg, who, pack);
+ return rt;
+}
+
+void BaseWnd::_cascadeRepaintRgn(api_region *rg)
+{
+ if (!ensureVirtualCanvasOk()) return ;
+
+ WndCanvas paintcanvas;
+ if (paintcanvas.attachToClient(this) == 0)
+ return;
+
+ virtualBeforePaint(rg);
+
+ deferedInvalidateRgn(rg);
+ paintTree(virtualCanvas, rg);
+
+ virtualAfterPaint(rg);
+
+ double ra = getRenderRatio();
+
+ RECT rcPaint;
+ rg->getBox(&rcPaint);
+
+ RECT rc;
+ getClientRect(&rc); //JF> this gets it in virtual (non-scaled) coordinates,
+ // so we need to do these comparisons before scaling.
+ rcPaint.bottom = MIN((int)rc.bottom, (int)rcPaint.bottom);
+ rcPaint.right = MIN((int)rc.right, (int)rcPaint.right);
+
+ if (renderRatioActive()) // probably faster than scaling the clone
+ {
+ rcPaint.left = (int)((rcPaint.left - 1) * ra);
+ rcPaint.top = (int)((rcPaint.top - 1) * ra);
+ rcPaint.right = (int)(rcPaint.right * ra + 0.999999);
+ rcPaint.bottom = (int)(rcPaint.bottom * ra + 0.999999);
+ }
+ rcPaint.left = MAX(0, (int)rcPaint.left);
+ rcPaint.top = MAX(0, (int)rcPaint.top);
+ rcPaint.right = MIN((int)rcPaint.right, (int)(rwidth * ra));
+ rcPaint.bottom = MIN((int)rcPaint.bottom, (int)(rheight * ra));
+
+ commitFrameBuffer(&paintcanvas, &rcPaint, ra);
+}
+
+
+void BaseWnd::packCascadeRepaintRgn(api_region *rg)
+{
+ if (!deferedCascadeRepaintRgn) deferedCascadeRepaintRgn = new RegionI;
+ deferedCascadeRepaintRgn->addRegion(rg);
+ need_flush_cascaderepaint = 1;
+}
+
+int BaseWnd::cascadeRepaintRgnFrom(api_region *_rg, ifc_window *who, int pack)
+{
+
+ api_region *rg = _rg->clone();
+
+ int j = virtualChildren.searchItem(who);
+ for (int i = 0; i < virtualChildren.getNumItems(); i++)
+ {
+ ifc_window *w = virtualChildren[i];
+ if (w != who && w->wantSiblingInvalidations())
+ w->onSiblingInvalidateRgn(rg, who, j, i);
+ }
+
+ if (!pack)
+ {
+ _cascadeRepaintRgn(rg);
+ }
+ else
+ {
+ packCascadeRepaintRgn(rg);
+ }
+
+ _rg->disposeClone(rg);
+
+ return 1;
+}
+
+void BaseWnd::setDesktopAlpha(int a)
+{
+ if (a && !Wasabi::Std::Wnd::isDesktopAlphaAvailable()) return ;
+ if (a == w2k_alpha) return ;
+ w2k_alpha = a;
+ if (!a && scalecanvas)
+ {
+ delete scalecanvas;
+ scalecanvas = NULL;
+ }
+ setLayeredWindow(w2k_alpha);
+ onSetDesktopAlpha(a);
+}
+
+void BaseWnd::onSetDesktopAlpha(int a) { }
+
+void BaseWnd::commitFrameBuffer(Canvas *paintcanvas, RECT *r, double ra)
+{
+ if (w2k_alpha && Wasabi::Std::Wnd::isDesktopAlphaAvailable() && !cloaked)
+ {
+ //CUT BLENDFUNCTION blend= {AC_SRC_OVER, 0, wndalpha, AC_SRC_ALPHA };
+ //CUT POINT pt={0,0};
+ RECT spr;
+ getWindowRect(&spr);
+ //CUT POINT sp={spr.left,spr.top};
+ //CUT SIZE ss={spr.right-spr.left, spr.bottom-spr.top};
+ int sw = spr.right - spr.left, sh = spr.bottom - spr.top;
+ //CUT SysCanvas c;
+
+ if (handleRatio() && renderRatioActive())
+ {
+ // eek slow!
+ RECT r;
+ getWindowRect(&r);
+ int w = r.right - r.left;
+ int h = r.bottom - r.top;
+ if (!scalecanvas) scalecanvas = new BltCanvas(w, h, getOsWindowHandle());
+ virtualCanvas->stretchblit(0, 0, (int)((double)virtualCanvasW * 65536.0), (int)((double)virtualCanvasH * 65536.0), scalecanvas, 0, 0, w, h);
+ }
+
+ //CUT updateLayeredWindow(hwnd, c.getHDC(), &sp, &ss, (scalecanvas ? scalecanvas : virtualCanvas)->getHDC(), &pt, 0, &blend, ULW_ALPHA);
+ Wasabi::Std::Wnd::updateLayeredWnd(hwnd, spr.left, spr.top, sw, sh, (scalecanvas ? scalecanvas : virtualCanvas)->getHDC(), wndalpha);
+ }
+ else
+ {
+ if (ABS(ra - 1.0) <= 0.01)
+ {
+ virtualCanvas->blit(r->left, r->top, paintcanvas, r->left, r->top, r->right - r->left, r->bottom - r->top);
+ }
+ else
+ {
+ RECT tr = *r;
+
+ double invra = 65536.0 / ra;
+ int lp = tr.left;
+ int tp = tr.top;
+ int w = tr.right - tr.left;
+ int h = tr.bottom - tr.top;
+
+ int sx = (int)((double)lp * invra);
+ int sy = (int)((double)tp * invra);
+ int sw = (int)((double)w * invra);
+ int sh = (int)((double)h * invra);
+
+ virtualCanvas->stretchblit(sx, sy, sw, sh, paintcanvas, lp, tp, w, h);
+ }
+ }
+}
+
+void BaseWnd::flushPaint()
+{
+ postDeferredCallback(DEFERREDCB_FLUSHPAINT, 0);
+}
+
+void BaseWnd::do_flushPaint()
+{
+ if (!deferedInvalidRgn || deferedInvalidRgn->isEmpty()) return ;
+ api_region *r = deferedInvalidRgn->clone();
+ cascadeRepaintRgn(r);
+ deferedInvalidRgn->disposeClone(r);
+ deferedInvalidRgn->empty();
+}
+
+int BaseWnd::isMouseOver(int x, int y)
+{
+ POINT pt = {x, y};
+ clientToScreen(&pt);
+
+ return (WASABI_API_WND->rootWndFromPoint(&pt) == this);
+}
+
+void BaseWnd::freeResources()
+{}
+
+void BaseWnd::reloadResources()
+{
+ invalidate();
+}
+
+double BaseWnd::getRenderRatio()
+{
+ if (!handleRatio()) return 1.0;
+ if (!ratiolinked) return ratio;
+ return getParent() ? getParent()->getRenderRatio() : ratio;
+}
+
+void BaseWnd::setRenderRatio(double r)
+{
+ // "snap" to 1.0
+ if (ABS(r - 1.0) <= 0.02f) r = 1.0;
+ if (scalecanvas)
+ {
+ delete scalecanvas;
+ scalecanvas = NULL;
+ }
+ if (isInited() && r != ratio && !isVirtual() && (!getParent() || !ratiolinked))
+ {
+ // must scale size & region accordingly
+ RECT rc;
+ BaseWnd::getWindowRect(&rc);
+ rc.right = rc.left + rwidth;
+ rc.bottom = rc.top + rheight;
+ ratio = r;
+
+ resize(&rc);
+
+ invalidate();
+ if (isPostOnInit())
+ onRatioChanged();
+ }
+}
+
+void BaseWnd::setRatioLinked(int l)
+{
+ ratiolinked = l;
+ if (isPostOnInit())
+ setRenderRatio(ratio);
+}
+
+int BaseWnd::renderRatioActive()
+{
+ return ABS(getRenderRatio() - 1.0) > 0.01f;
+}
+
+void BaseWnd::multRatio(int *x, int *y)
+{
+ double rr = getRenderRatio();
+ if (x) *x = (int)((double)(*x) * rr);
+ if (y) *y = (int)((double)(*y) * rr);
+}
+
+void BaseWnd::multRatio(RECT *r)
+{
+ Wasabi::Std::scaleRect(r, getRenderRatio());
+}
+
+void BaseWnd::divRatio(int *x, int *y)
+{
+ double rr = getRenderRatio();
+ if (x) *x = (int)((double)(*x) / rr + 0.5);
+ if (y) *y = (int)((double)(*y) / rr + 0.5);
+}
+
+void BaseWnd::divRatio(RECT *r)
+{
+ double rr = getRenderRatio();
+ Wasabi::Std::scaleRect(r, 1./rr);
+}
+
+void BaseWnd::bringVirtualToFront(ifc_window *w)
+{
+ changeChildZorder(w, 0);
+}
+
+void BaseWnd::bringVirtualToBack(ifc_window *w)
+{
+ changeChildZorder(w, virtualChildren.getNumItems()-1);
+}
+
+void BaseWnd::bringVirtualAbove(ifc_window *w, ifc_window *b)
+{
+ ASSERT(b->isVirtual());
+ int p = virtualChildren.searchItem(b);
+ if (p == -1) return ;
+ changeChildZorder(w, p);
+}
+
+void BaseWnd::bringVirtualBelow(ifc_window *w, ifc_window *b)
+{
+ ASSERT(b->isVirtual());
+ int p = virtualChildren.searchItem(b);
+ if (p == -1) return ;
+ changeChildZorder(w, p + 1);
+}
+
+void BaseWnd::changeChildZorder(ifc_window *w, int newpos)
+{
+ int p = newpos;
+ p = MAX(p, (int)0);
+ p = MIN(p, virtualChildren.getNumItems()-1);
+ RECT cr;
+ w->getClientRect(&cr);
+
+ PtrList<ifc_window> l;
+ int i;
+ for (i = 0;i < virtualChildren.getNumItems();i++)
+ if (virtualChildren[i] != w)
+ l.addItem(virtualChildren[i]);
+
+ p = virtualChildren.getNumItems() - newpos - 1;
+ virtualChildren.removeAll();
+
+ int done = 0;
+
+ for (i = 0;i < l.getNumItems();i++)
+ if (i == p && !done)
+ {
+ virtualChildren.addItem(w);
+ i--;
+ done++;
+ }
+ else
+ {
+ RECT dr, intersection;
+ l.enumItem(i)->getClientRect(&dr);
+ if (Wasabi::Std::rectIntersect(intersection, dr, &cr))
+ l[i]->invalidateRect(&intersection);
+ virtualChildren.addItem(l.enumItem(i));
+ }
+ if (i == p && !done)
+ virtualChildren.addItem(w);
+ w->invalidate();
+}
+
+int BaseWnd::onActivate()
+{
+ if (hasVirtualChildren())
+ {
+ int l = getNumVirtuals();
+ for (int i = 0; i < l; i++)
+ {
+ ifc_window *r = enumVirtualChild(i);
+ r->onActivate();
+ }
+ }
+
+ return 0;
+}
+
+int BaseWnd::onDeactivate()
+{
+ if (hasVirtualChildren())
+ {
+ int l = getNumVirtuals();
+ for (int i = 0; i < l; i++)
+ {
+ ifc_window *r = enumVirtualChild(i);
+ r->onDeactivate();
+ }
+ }
+ return 0;
+}
+
+int BaseWnd::getDesktopAlpha()
+{
+ return w2k_alpha;
+}
+
+api_region *BaseWnd::getRegion()
+{
+ return NULL;
+}
+
+//CUT int BaseWnd::isTransparencyAvailable() {
+//CUT #ifdef WIN32
+//CUT #else
+//CUT #pragma warning port me!
+//CUT #endif
+//CUT return 0;
+//CUT }
+
+int BaseWnd::handleTransparency()
+{
+ return 1; // by default all windows handle transparency, only windows blitting directly on the SCREEN (if you blit directly on the DC it's still ok),
+} // for instance, a vis or a video using overlay should return 0, this will let the layout auto manage its alpha as that window is shown/hiden
+
+void BaseWnd::setAlpha(int active, int inactive)
+{
+ if (active == 254) active = 255;
+ if (active == 1) active = 0;
+ if (inactive == 254) inactive = 255;
+ if (inactive == 1) inactive = 0;
+ int oldactivealpha = activealpha;
+ active = MIN(255, MAX(0, active));
+ if (inactive != -1) inactive = MIN(255, MAX(0, inactive));
+
+ if (active != activealpha)
+ {
+ activealpha = active;
+ if (isActive())
+ {
+ invalidate();
+ if ((oldactivealpha == 0 || activealpha == 0) && (oldactivealpha != 0 || activealpha != 0))
+ invalidateWindowRegion();
+ }
+ }
+ if (inactive == -1) inactive = active;
+ if (inactive != inactivealpha)
+ {
+ inactivealpha = inactive;
+ if (!isActive())
+ {
+ invalidate();
+ if ((oldactivealpha == 0 || activealpha == 0) && (oldactivealpha != 0 || activealpha != 0))
+ invalidateWindowRegion();
+ }
+ }
+}
+
+void BaseWnd::getAlpha(int *active, int *inactive)
+{
+ if (active) *active = activealpha;
+ if (inactive) *inactive = inactivealpha;
+}
+
+int BaseWnd::getPaintingAlpha(void)
+{
+ int a = isActive() ? MIN(255, MAX(0, activealpha)) : MIN(255, MAX(0, inactivealpha));
+ ASSERT(a >= 0 && a <= 255);
+ if (getParent() && getParent()->isVirtual())
+ {
+ int b = getParent()->getPaintingAlpha();
+ a = (int)((double)a / 255.0 * (double)b);
+ }
+ if (a == 254) a = 255;
+ if (a == 1) a = 0;
+ if (!isEnabled()) a = (int)(a*0.6);
+ return a;
+}
+
+void BaseWnd::setClickThrough(int ct)
+{
+ clickthrough = ct;
+}
+
+int BaseWnd::isClickThrough()
+{
+ return clickthrough;
+}
+
+int BaseWnd::handleRatio()
+{
+ return 1;
+}
+
+#include <api/script/objects/c_script/c_rootobj.h>
+
+int BaseWnd::createTip()
+{
+ destroyTip();
+ tooltip = new Tooltip(getTip());
+ return -1;
+}
+
+void BaseWnd::destroyTip()
+{
+ // this is to avoid pb if destroytip() is being called by a time while destroying tip
+ Tooltip *tt = tooltip;
+ tooltip = NULL;
+ delete tt;
+}
+
+
+int BaseWnd::runModal()
+{
+ //PORTME
+#ifdef _WIN32
+ ifc_window *dp = getDesktopParent();
+ if (dp && dp != this)
+ return dp->runModal();
+
+ MSG msg;
+
+ // SetCapture(NULL);
+ SetFocus(getOsWindowHandle());
+
+ WASABI_API_WND->pushModalWnd(this);
+ returnvalue = 0;
+ mustquit = 0;
+
+ // Main message loop:
+ while (!mustquit)
+ {
+ mustquit = !GetMessage(&msg, NULL, 0, 0);
+ if (!msg.hwnd || !TranslateAccelerator(msg.hwnd, NULL, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ WASABI_API_WND->popModalWnd(this);
+ // SetCapture(NULL);
+ return returnvalue;
+#else
+#warning port me
+ return 0;
+#endif
+}
+
+void BaseWnd::endModal(int ret)
+{
+ ifc_window *dp = getDesktopParent();
+ if (dp && dp != this)
+ {
+ dp->endModal(ret);
+ return ;
+ }
+ returnvalue = ret;
+ mustquit = 1;
+}
+
+int BaseWnd::wantAutoContextMenu()
+{
+ return 1;
+}
+
+void BaseWnd::onCancelCapture()
+{}
+
+ifc_window *BaseWnd::getNextVirtualFocus(ifc_window *w)
+{
+ if (w == NULL)
+ {
+ if (childtabs.getNumItems() > 0)
+ return childtabs.getFirst()->wnd;
+ }
+
+ int a = getTabOrderEntry(w) + 1;
+
+ if (a < childtabs.getNumItems())
+ return childtabs.enumItem(a)->wnd;
+
+ return NULL;
+}
+
+
+void BaseWnd::setVirtualChildFocus(ifc_window *w)
+{
+ ASSERT(w && w->isVirtual());
+ if (curVirtualChildFocus)
+ curVirtualChildFocus->onKillFocus();
+ curVirtualChildFocus = w;
+ onSetRootFocus(w);
+ Wasabi::Std::Wnd::setFocus(getOsWindowHandle());
+ if (curVirtualChildFocus)
+ curVirtualChildFocus->onGetFocus();
+}
+
+int BaseWnd::ptInRegion(int x, int y)
+{
+ RECT cr;
+ getNonClientRect(&cr);
+ POINT pt = {x - cr.left, y - cr.top};
+ api_region *reg = getRegion();
+ if (isRectRgn())
+ return (x >= cr.left && x <= cr.right && y >= cr.top && y <= cr.bottom);
+ return reg ? reg->ptInRegion(&pt) : 0;
+}
+
+api_region *BaseWnd::getComposedRegion()
+{
+ ensureWindowRegionValid();
+ return composedrgn;
+}
+
+api_region *BaseWnd::getSubtractorRegion()
+{
+ ensureWindowRegionValid();
+ return subtractorrgn;
+}
+
+int BaseWnd::ensureWindowRegionValid()
+{
+ if (!isInited()) return 0;
+ if (wndregioninvalid)
+ {
+ computeComposedRegion();
+ return 1;
+ }
+ return 0;
+}
+
+void BaseWnd::invalidateWindowRegion()
+{
+ wndregioninvalid = 1;
+ if (getParent()) getParent()->invalidateWindowRegion();
+}
+
+void BaseWnd::computeComposedRegion()
+{
+ if (!isPostOnInit()) return ;
+
+ wndregioninvalid = 0;
+
+ RECT r;
+ getNonClientRect(&r);
+
+ api_region *reg = getRegion();
+ RegionI *_reg = NULL;
+
+ if (!reg)
+ {
+ _reg = new RegionI;
+ reg = _reg;
+ if (isRectRgn())
+ reg->setRect(&r);
+ }
+ else
+ if (isRectRgn())
+ reg->setRect(&r);
+
+ api_region *wr = reg->clone();
+
+ if (!subtractorrgn) subtractorrgn = new RegionI();
+ subtractorrgn->empty();
+ if (!composedrgn) composedrgn = new RegionI;
+ composedrgn->empty();
+
+ RegionI *subme = NULL;
+ RegionI *andme = NULL;
+ RegionI *orme = NULL;
+
+ // if subregion is now empty, we need to only use our region
+ RECT gr;
+ getNonClientRect(&gr);
+ for (int i = 0;i < virtualChildren.getNumItems();i++)
+ {
+ ifc_window *srw = virtualChildren.enumItem(i);
+ if (!srw->isVisible(1) || srw->getPaintingAlpha() == 0) continue;
+ if (srw->getRegionOp() != REGIONOP_NONE)
+ {
+ api_region *sr = srw->getComposedRegion();
+ if (sr)
+ {
+ api_region *osr = sr->clone();
+ RECT r;
+ srw->getNonClientRect(&r);
+ r.left -= gr.left;
+ r.top -= gr.top;
+ osr->offset(r.left, r.top);
+ /* sr->debug();
+ osr->debug();*/
+ if (srw->getRegionOp() == REGIONOP_OR)
+ {
+ if (!orme) orme = new RegionI;
+ orme->addRegion(osr);
+ }
+ else if (srw->getRegionOp() == REGIONOP_AND)
+ {
+ if (!andme) andme = new RegionI;
+ andme->addRegion(osr);
+ }
+ else if (srw->getRegionOp() == REGIONOP_SUB)
+ {
+ if (!subme) subme = new RegionI;
+ subme->addRegion(osr);
+ }
+ else if (srw->getRegionOp() == REGIONOP_SUB2)
+ {
+ if (!subme) subme = new RegionI;
+ subtractorrgn->addRegion(osr);
+ }
+ sr->disposeClone(osr);
+ }
+ }
+ api_region *sr = srw->getSubtractorRegion();
+ if (sr != NULL && !sr->isEmpty())
+ {
+ api_region *osr = sr->clone();
+ RECT r;
+ srw->getNonClientRect(&r);
+ r.left -= gr.left;
+ r.top -= gr.top;
+ osr->offset(r.left, r.top);
+ subtractorrgn->addRegion(osr);
+ sr->disposeClone(osr);
+ }
+ }
+
+ if (andme)
+ {
+ wr->andRegion(andme);
+ delete andme;
+ }
+ if (orme)
+ {
+ wr->addRegion(orme);
+ delete orme;
+ }
+ if (subme)
+ {
+ wr->subtractRgn(subme);
+ delete subme;
+ }
+
+ composedrgn->addRegion(wr);
+ reg->disposeClone(wr);
+ delete _reg;
+}
+
+void BaseWnd::updateWindowRegion()
+{
+ if (!isPostOnInit() || isVirtual()) return ;
+ if (getDesktopAlpha())
+ {
+ // if desktopalpha is on, we can't use regions (thanks MS), we have to rely on the framebuffer correctness
+ //CUT SetWindowRgn(getOsWindowHandle(), NULL, FALSE);
+ Wasabi::Std::Wnd::setWndRegion(getOsWindowHandle(), NULL);
+ return ;
+ }
+ api_region *_r = getComposedRegion();
+ api_region *_s = getSubtractorRegion();
+ ASSERT(_r != NULL && _s != NULL);
+
+ api_region *z = _r->clone();
+ z->subtractRgn(_s);
+
+ assignWindowRegion(z);
+ _r->disposeClone(z);
+}
+
+// wr is NOT scaled!!!
+void BaseWnd::assignWindowRegion(api_region *wr)
+{
+ ASSERT(wr != NULL);
+
+ if (!isPostOnInit()) return ;
+
+ int isrect = wr->isRect();
+
+ RECT r;
+ BaseWnd::getWindowRect(&r);
+
+ //DebugStringW( L"\nBaseWnd::assignWindowRegion() r before - x = %d, y = %d, w = %d, h = %d \n", r.left, r.top, r.right - r.left, r.bottom - r.top );
+
+ r.right -= r.left;
+ r.left = 0;
+ r.bottom -= r.top;
+ r.top = 0;
+
+ //DebugStringW( L"BaseWnd::assignWindowRegion() r after - x = %d, y = %d, w = %d, h = %d \n", r.left, r.top, r.right - r.left, r.bottom - r.top );
+
+ RECT z;
+ wr->getBox(&z);
+
+ //DebugStringW( L"BaseWnd::assignWindowRegion() z before - x = %d, y = %d, w = %d, h = %d \n", z.left, z.top, z.right - z.left, z.bottom - z.top );
+
+ z.left = 0;
+ z.top = 0;
+
+ //DebugStringW( L"BaseWnd::assignWindowRegion() z after - x = %d, y = %d, w = %d, h = %d \n", z.left, z.top, z.right - z.left, z.bottom - z.top );
+
+ if (renderRatioActive())
+ {
+ double i = getRenderRatio();
+ wr->scale(i, i, FALSE);
+ }
+
+ RECT sz;
+ wr->getBox(&sz);
+
+ //DebugStringW( L"BaseWnd::assignWindowRegion() sz before - x = %d, y = %d, w = %d, h = %d \n", sz.left, sz.top, sz.right - sz.left, sz.bottom - sz.top );
+
+ sz.right -= sz.left;
+ sz.bottom -= sz.top;
+ sz.left = 0;
+ sz.top = 0;
+
+ //DebugStringW( L"BaseWnd::assignWindowRegion() sz after - x = %d, y = %d, w = %d, h = %d \n", sz.left, sz.top, sz.right - sz.left, sz.bottom - sz.top );
+
+ if (isrect &&
+ ((z.right == rwidth && z.bottom == rheight) ||
+ (sz.left == r.left && sz.right == r.right && sz.top == r.top && sz.bottom == r.bottom) ||
+ (0)
+ )
+ )
+ {
+ //CUT SetWindowRgn(getOsWindowHandle(), NULL, TRUE);
+ if (!lastnullregion)
+ {
+ Wasabi::Std::Wnd::setWndRegion(getOsWindowHandle(), NULL, TRUE);
+ lastnullregion = 1;
+ }
+ }
+ else
+ {
+ //DebugStringW(L"setting region, rwidth = %d, rheight = %d, z.right = %d, z.bottom = %d\n", rwidth, rheight, z.right, z.bottom);
+ //CUT SetWindowRgn(getOsWindowHandle(), wr->makeWindowRegion(), TRUE);
+ Wasabi::Std::Wnd::setWndRegion(getOsWindowHandle(), wr->makeWindowRegion(), TRUE);
+ lastnullregion = 0;
+ }
+}
+
+void BaseWnd::performBatchProcesses()
+{
+ // recompute the window region if needed and apply it to the HWND
+ if (wndregioninvalid && !isVirtual())
+ if (ensureWindowRegionValid())
+ updateWindowRegion();
+ if (need_flush_cascaderepaint)
+ {
+ _cascadeRepaintRgn(deferedCascadeRepaintRgn);
+ deferedCascadeRepaintRgn->empty();
+ need_flush_cascaderepaint = 0;
+ }
+}
+
+int BaseWnd::getRegionOp()
+{
+ return regionop;
+}
+
+void BaseWnd::setRegionOp(int op)
+{
+ if (regionop != op)
+ {
+ regionop = op;
+ invalidateWindowRegion();
+ }
+}
+
+int BaseWnd::isRectRgn()
+{
+ return rectrgn;
+}
+
+void BaseWnd::setRectRgn(int i)
+{
+ rectrgn = i;
+}
+
+TimerClient *BaseWnd::timerclient_getMasterClient()
+{
+ if (!isVirtual()) return this;
+ ifc_window *w = getParent();
+ if (w)
+ {
+ TimerClient *tc = w->getTimerClient();
+ if (tc)
+ return tc->timerclient_getMasterClient();
+ }
+ return NULL;
+}
+
+void BaseWnd::timerclient_onMasterClientMultiplex()
+{
+ performBatchProcesses();
+}
+
+TimerClient *BaseWnd::getTimerClient()
+{
+ return this;
+}
+
+ifc_dependent *BaseWnd::rootwnd_getDependencyPtr()
+{
+ return this;
+}
+
+ifc_dependent *BaseWnd::timerclient_getDependencyPtr()
+{
+ return this;
+}
+
+void BaseWnd::addMinMaxEnforcer(ifc_window *w)
+{
+ minmaxEnforcers.addItem(w);
+ signalMinMaxEnforcerChanged();
+}
+
+void BaseWnd::removeMinMaxEnforcer(ifc_window *w)
+{
+ minmaxEnforcers.removeItem(w);
+ signalMinMaxEnforcerChanged();
+}
+
+void BaseWnd::signalMinMaxEnforcerChanged(void)
+{
+ ifc_window *w = getDesktopParent();
+ if (w == NULL || w == this) onMinMaxEnforcerChanged();
+ else w->signalMinMaxEnforcerChanged();
+}
+
+int BaseWnd::getNumMinMaxEnforcers()
+{
+ return minmaxEnforcers.getNumItems();
+}
+
+ifc_window *BaseWnd::enumMinMaxEnforcer(int n)
+{
+ return minmaxEnforcers.enumItem(n);
+}
+
+int BaseWnd::onAction(const wchar_t *action, const wchar_t *param, int x, int y, intptr_t p1, intptr_t p2, void *data, size_t datalen, ifc_window *source)
+{
+ return 1;
+}
+
+int BaseWnd::sendAction(ifc_window *target, const wchar_t *action, const wchar_t *param, int x, int y, intptr_t p1, intptr_t p2, void *data, size_t datalen)
+{
+ ASSERT(target != NULL);
+ return target->onAction(action, param, x, y, p1, p2, data, datalen, this);
+}
+
+int BaseWnd::virtualBeforePaint(api_region *r)
+{
+ if (!virtualCanvas) return 0;
+ PaintCallbackInfoI pc(virtualCanvas, r);
+ dependent_sendEvent(BaseWnd::depend_getClassGuid(), Event_ONPAINT, PaintCallback::BEFOREPAINT, &pc);
+ return 1;
+}
+
+int BaseWnd::virtualAfterPaint(api_region *r)
+{
+ if (!virtualCanvas) return 0;
+ PaintCallbackInfoI pc(virtualCanvas, r);
+ dependent_sendEvent(BaseWnd::depend_getClassGuid(), Event_ONPAINT, PaintCallback::AFTERPAINT, &pc);
+ return 1;
+}
+
+int BaseWnd::timerclient_onDeferredCallback(intptr_t p1, intptr_t p2)
+{
+ TimerClientI::timerclient_onDeferredCallback(p1, p2);
+ return onDeferredCallback(p1, p2);
+}
+
+void BaseWnd::timerclient_timerCallback(int id)
+{
+ TimerClientI::timerclient_timerCallback(id);
+ timerCallback(id);
+}
+
+int BaseWnd::setTimer(int id, int ms)
+{
+ return timerclient_setTimer(id, ms);
+}
+
+int BaseWnd::killTimer(int id)
+{
+ return timerclient_killTimer(id);
+}
+
+void BaseWnd::postDeferredCallback(intptr_t p1, intptr_t p2, int mindelay)
+{
+#ifdef _WIN32
+ // TODO: re-enable, but post to some other window (e.g. some singleton window), not this window
+ // because our message pump might be blocked
+ // maybe make a hidden window in api_timer for this purpose
+
+ //if (mindelay)
+ timerclient_postDeferredCallback(p1, p2, mindelay);
+ //else
+ //PostMessage(hwnd, WM_DEFER_CALLBACK, p1, p2);
+#else
+#warning "port me - I can be optimized - don't use timers for this, use mac os x equiv of PostMessage!"
+ timerclient_postDeferredCallback(p1, p2, mindelay);
+#endif
+}
+
+int BaseWnd::bypassModal()
+{
+ return 0;
+}
+
+void BaseWnd::setRenderBaseTexture(int r)
+{
+ renderbasetexture = r;
+ if (isInited()) invalidate();
+}
+
+int BaseWnd::getRenderBaseTexture()
+{
+ return renderbasetexture;
+}
+
+GuiObject *BaseWnd::getGuiObject()
+{
+ if (my_guiobject == NULL)
+ {
+ my_guiobject = static_cast<GuiObject *>(getInterface(guiObjectGuid));
+ }
+ return my_guiobject;
+}
+
+//CUT someday
+int BaseWnd::getFlag(int flag)
+{
+ /* switch (flag) {
+ }*/
+ return 0;
+}
+
+int BaseWnd::triggerEvent(int event, intptr_t p1, intptr_t p2)
+{
+ //PORTME
+ switch (event)
+ {
+ case TRIGGER_ONRESIZE:
+ if (isPostOnInit())
+ onResize();
+ break;
+ case TRIGGER_INVALIDATE:
+ if (isPostOnInit())
+ invalidate();
+ break;
+ }
+ return 0;
+}
+
+void BaseWnd::registerAcceleratorSection(const wchar_t *name, int global)
+{
+#if defined(WASABI_COMPILE_LOCALES)
+ WASABI_API_LOCALE->locales_registerAcceleratorSection(name, this, global);
+#endif
+}
+
+int BaseWnd::onAcceleratorEvent(const wchar_t *name)
+{
+ for (int i = 0;i < getNumRootWndChildren();i++)
+ if (enumRootWndChildren(i)->onAcceleratorEvent(name))
+ return 1;
+ return 0;
+}
+
+int BaseWnd::allowDeactivation()
+{
+ return allow_deactivate & ((WASABI_API_WND == NULL) || WASABI_API_WND->appdeactivation_isallowed(this));
+}
+
+void BaseWnd::onMinimize()
+{
+ if (!isVirtual())
+ {
+ dropVirtualCanvas();
+ }
+}
+
+void BaseWnd::dropVirtualCanvas()
+{
+ deferedInvalidate();
+ delete virtualCanvas;
+ virtualCanvas = NULL;
+}
+
+void BaseWnd::onRestore()
+{
+ if (getDesktopParent() == this)
+ {
+ cascadeRepaint(TRUE);
+ }
+}
+
+ifc_window *BaseWnd::findWindow(const wchar_t *id)
+{
+ RootWndFinder find_object;
+ find_object.reset();
+ find_object.setFindId(id);
+ ifc_window *ret = findWindowChain(&find_object);
+
+#ifdef _DEBUG
+ if (ret == NULL)
+ DebugStringW(L"findWindow : window not found by id ! %s \n", id);
+#endif
+
+ return ret;
+}
+
+ifc_window *BaseWnd::findWindowByInterface(GUID interface_guid)
+{
+ RootWndFinder find_object;
+ find_object.reset();
+ find_object.setFindGuid(interface_guid);
+ ifc_window *ret = findWindowChain(&find_object);
+
+#ifdef _DEBUG
+ char str[256] = {0};
+ nsGUID::toChar(interface_guid, str);
+ if (ret == NULL)
+ DebugStringW(L"findWindow : object not found by guid ! %s \n", str);
+#endif
+
+ return ret;
+}
+
+ifc_window *BaseWnd::findWindowByCallback(FindObjectCallback *cb)
+{
+ ifc_window *ret = findWindowChain(cb);
+#ifdef _DEBUG
+ if (ret == NULL)
+ DebugStringW(L"findWindow : object not found by callback!\n");
+#endif
+
+ return ret;
+}
+
+ifc_window *BaseWnd::findWindowChain(FindObjectCallback *cb, ifc_window *wcaller)
+{
+
+ if (!cb) return NULL;
+
+ if (cb->findobjectcb_matchObject(this)) return this;
+
+ // first lets not look in subdirectories
+
+ for (int i = 0;i < getNumRootWndChildren();i++)
+ {
+ ifc_window *child = enumRootWndChildren(i);
+ if (!child || child == wcaller) continue;
+ if (cb->findobjectcb_matchObject(child))
+ return child;
+ }
+
+ // ok so it wasn't in our content, lets try to find it as a grandchildren
+
+ for (int i = 0;i < getNumRootWndChildren();i++)
+ {
+ ifc_window *child = enumRootWndChildren(i);
+ if (child->getNumRootWndChildren() > 0)
+ {
+ ifc_window *ret = child->findWindowChain(cb, this);
+ if (ret) return ret;
+ }
+ }
+
+ // so it wasnt one of our children, we'll hop the tree up one level and ask our parent to find it
+ // for us. of course, our parents are smart, they won't ask us back when asking our sibblings
+ ifc_window *p = getParent();
+ if (p != NULL && wcaller != p)
+ {
+ return p->findWindowChain(cb, this);
+ }
+
+ return NULL;
+}
+
+
+const wchar_t *BaseWnd::timerclient_getName()
+{
+ tcname = StringPrintfW(L"name=\"%S\", id=\"%s\"", getRootWndName(), getId());
+ return tcname;
+}
+
+void BaseWnd::setTabOrder(int a)
+{
+ if (getParent() != NULL)
+ getParent()->setVirtualTabOrder(this, a);
+}
+
+int BaseWnd::getTabOrder()
+{
+ if (getParent() != NULL)
+ return getParent()->getVirtualTabOrder(this);
+ return -1;
+}
+
+void BaseWnd::recursive_setVirtualTabOrder(ifc_window *w, float a, float lambda)
+{
+ ASSERT(w != NULL);
+ childtabs.setAutoSort(0);
+ int i = getTabOrderEntry(a);
+ if (i != -1)
+ {
+ TabOrderEntry *toe = childtabs.enumItem(i);
+ if (toe->wnd != w)
+ {
+ lambda += TABORDER_K;
+ if (lambda != 1.0)
+ recursive_setVirtualTabOrder(toe->wnd, a + lambda, lambda);
+ }
+ else
+ {
+ return ;
+ }
+ }
+ i = getTabOrderEntry(w);
+ if (i != -1)
+ {
+ delete childtabs.enumItem(i);
+ childtabs.removeByPos(i);
+ }
+ TabOrderEntry *toe = new TabOrderEntry;
+ toe->wnd = w;
+ toe->order = a;
+ childtabs.addItem(toe);
+}
+
+void BaseWnd::setVirtualTabOrder(ifc_window *w, int a)
+{
+ if (a == -1)
+ {
+ delTabOrderEntry(w);
+ return ;
+ }
+ recursive_setVirtualTabOrder(w, (float)a);
+}
+
+int BaseWnd::getVirtualTabOrder(ifc_window *w)
+{
+ int a = (int)getTabOrderEntry(w);
+ if (a == -1) return -1;
+ return (int)childtabs.enumItem(a);
+}
+
+int BaseWnd::getTabOrderEntry(ifc_window *w)
+{
+ foreach(childtabs)
+ if (childtabs.getfor()->wnd == w)
+ return foreach_index;
+ endfor;
+ return -1;
+}
+
+void BaseWnd::delTabOrderEntry(int i)
+{
+ int a = getTabOrderEntry((float)i);
+ if (a == -1) return ;
+ childtabs.removeByPos(a);
+}
+
+void BaseWnd::delTabOrderEntry(ifc_window *w)
+{
+ int a = getTabOrderEntry(w);
+ if (a == -1) return ;
+ delete childtabs.enumItem(a);
+ childtabs.removeByPos(a);
+}
+
+int BaseWnd::getTabOrderEntry(float order)
+{
+ foreach(childtabs)
+ if (childtabs.getfor()->order == order)
+ return foreach_index;
+ endfor;
+ return -1;
+}
+
+void BaseWnd::setAutoTabOrder()
+{
+ if (!getParent()) return ;
+ getParent()->setVirtualAutoTabOrder(this);
+}
+
+void BaseWnd::setVirtualAutoTabOrder(ifc_window *w)
+{
+ delTabOrderEntry(w);
+ float o = 0;
+ for (int i = 0;i < childtabs.getNumItems();i++)
+ {
+ o = MAX(o, childtabs.enumItem(i)->order);
+ }
+ setVirtualTabOrder(w, ((int)o) + 1);
+}
+
+void BaseWnd::focusNext()
+{
+ ifc_window *dp = getDesktopParent();
+ if (dp != this)
+ {
+ if (dp != NULL)
+ dp->focusNext();
+ return ;
+ }
+ ifc_window *w = getTab(TAB_GETNEXT);
+ if (w != NULL) w->setFocus();
+}
+
+void BaseWnd::focusPrevious()
+{
+ ifc_window *dp = getDesktopParent();
+ if (dp != this)
+ {
+ if (dp != NULL)
+ getDesktopParent()->focusPrevious();
+ return ;
+ }
+ ifc_window *w = getTab(TAB_GETPREVIOUS);
+ if (w != NULL) w->setFocus();
+}
+
+void BaseWnd::recursive_buildTabList(ifc_window *from, PtrList<ifc_window> *list)
+{
+ for (int i = 0;i < from->getNumTabs();i++)
+ {
+ ifc_window *r = from->enumTab(i);
+ if (r->isVisible() && r->getPaintingAlpha() > 0)
+ {
+ if (r->wantFocus())
+ list->addItem(r);
+ recursive_buildTabList(r, list);
+ }
+ }
+}
+
+ifc_window *BaseWnd::getTab(int what)
+{
+ PtrList<ifc_window> listnow;
+
+ recursive_buildTabList(this, &listnow);
+
+ int p = listnow.searchItem(rootfocus);
+
+ if (p == -1)
+ for (int i = 0; i < listnow.getNumItems(); i++)
+ {
+ ifc_window *r = listnow.enumItem(i);
+ if (r->gotFocus())
+ {
+ //DebugString("desync of rootfocus, fixing\n");
+ p = i;
+ assignRootFocus(r);
+ break;
+ }
+ }
+
+ if (what == TAB_GETNEXT && rootfocus != NULL)
+ {
+
+ p++;
+ if (p >= listnow.getNumItems())
+ p = 0;
+ return listnow.enumItem(p);
+
+ }
+ else if (what == TAB_GETPREVIOUS && rootfocus != NULL)
+ {
+
+ p--;
+ if (p < 0) p = listnow.getNumItems() - 1;
+ return listnow.enumItem(p);
+
+ }
+ else if (what == TAB_GETCURRENT)
+ {
+
+ return rootfocus;
+
+ }
+ else if (what == TAB_GETFIRST || (what == TAB_GETNEXT && rootfocus == NULL))
+ {
+
+ return listnow.getFirst();
+
+ }
+ else if (what == TAB_GETLAST || (what == TAB_GETPREVIOUS && rootfocus == NULL))
+ {
+
+ return listnow.getLast();
+
+ }
+
+ return NULL;
+}
+
+int BaseWnd::getNumTabs()
+{
+ return childtabs.getNumItems();
+}
+
+ifc_window *BaseWnd::enumTab(int i)
+{
+ childtabs.sort();
+ return childtabs.enumItem(i)->wnd;
+}
+
+void BaseWnd::onSetRootFocus(ifc_window *w)
+{
+ assignRootFocus(w);
+ ifc_window *dp = getDesktopParent();
+ if (dp && dp != this) dp->onSetRootFocus(w);
+}
+
+void BaseWnd::autoFocus(ifc_window *w)
+{
+ if (w->getFocusOnClick() && w->wantFocus())
+ {
+ w->setFocus();
+ return ;
+ }
+ ifc_window *g = w;
+ while (1)
+ {
+ ifc_window *p = g->getParent();
+ if (p == NULL) break;
+ ifc_window *dp = p->getDesktopParent();
+ if (dp && dp != p)
+ {
+ if (p->wantFocus() && p->getFocusOnClick())
+ {
+ p->setFocus();
+ return ;
+ }
+ g = p;
+ }
+ else
+ break;
+ }
+}
+
+void BaseWnd::setNoLeftClicks(int no)
+{
+ noleftclick = no;
+}
+
+void BaseWnd::setNoRightClicks(int no)
+{
+ norightclick = no;
+}
+
+void BaseWnd::setNoDoubleClicks(int no)
+{
+ nodoubleclick = no;
+}
+
+void BaseWnd::setNoMouseMoves(int no)
+{
+ nomousemove = no;
+}
+
+void BaseWnd::setNoContextMenus(int no)
+{
+ nocontextmnu = no;
+}
+
+void BaseWnd::setDefaultCursor(Cursor *c)
+{
+ customdefaultcursor = c;
+}
+
+
+OSCURSORHANDLE BaseWnd::getCustomCursor(int x, int y)
+{
+#ifdef _WIN32
+ return customdefaultcursor ? customdefaultcursor->getOSHandle() : NULL;
+#else
+#warning port me
+ return 0;
+#endif
+}
+
+Accessible *BaseWnd::createNewAccObj()
+{
+ waServiceFactory *f = WASABI_API_SVC->service_enumService(WaSvc::ACCESSIBILITY, 0);
+ if (f != NULL)
+ {
+ svc_accessibility *svc = castService<svc_accessibility>(f);
+ if (svc != NULL)
+ {
+ Accessible *a = svc->createAccessibleObject(this);
+ WASABI_API_SVC->service_release(svc);
+ return a;
+ }
+ }
+ return NULL;
+}
+
+Accessible *BaseWnd::getAccessibleObject(int createifnotexist)
+{
+ if (!createifnotexist) return accessible;
+ if (!accessible)
+ accessible = createNewAccObj();
+ else
+ accessible->addRef();
+ return accessible;
+}
+
+int BaseWnd::accessibility_getState()
+{
+ int state = 0;
+ if (!isVisible()) state |= STATE_SYSTEM_INVISIBLE;
+ //if (isVirtual() && !wantFocus()) state |= STATE_SYSTEM_INVISIBLE;
+ if (gotFocus()) state |= STATE_SYSTEM_FOCUSED;
+ return state;
+}
+
+void BaseWnd::activate()
+{
+ Wasabi::Std::Wnd::setActiveWindow(getRootParent()->getOsWindowHandle());
+}
+
+void BaseWnd::setOSWndName(const wchar_t *name)
+{
+ if (isVirtual()) return ;
+//#ifdef COMPILE_WASABI_SKIN // for some reason this isn't being correctly defined
+ if (name)
+ {
+ Wasabi::Std::Wnd::setWndName(getOsWindowHandle(), name);
+ }
+ else
+ Wasabi::Std::Wnd::setWndName(getOsWindowHandle(), L"");
+
+}
+
+const wchar_t *BaseWnd::getOSWndName()
+{
+ if (isVirtual()) return NULL;
+ wchar_t str[4096] = {0};
+ Wasabi::Std::Wnd::getWndName(getOsWindowHandle(), str, 4095);
+ str[4095] = '\0';
+ osname = str;
+ return osname;
+}
+
+#ifdef EXPERIMENTAL_INDEPENDENT_AOT
+void BaseWnd::setAlwaysOnTop(int i)
+{
+ // this function should not optimize itself
+ if (getDesktopParent() == this)
+ {
+ if (i)
+ {
+ //CUT SetWindowPos(getOsWindowHandle(), HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOOWNERZORDER);
+ Wasabi::Std::Wnd::setTopmost(getOsWindowHandle(), TRUE);
+ }
+ else
+ {
+ saveTopMosts();
+ //CUT SetWindowPos(getOsWindowHandle(), HWND_NOTOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOOWNERZORDER);
+ Wasabi::Std::Wnd::setTopmost(getOsWindowHandle(), FALSE);
+ restoreTopMosts();
+ }
+ alwaysontop = i;
+ return ;
+ }
+ ifc_window *p = getParent();
+ if (p != NULL)
+ p->setAlwaysOnTop(i);
+}
+
+int BaseWnd::getAlwaysOnTop()
+{
+ if (getDesktopParent() == this)
+ return alwaysontop;
+ ifc_window *p = getParent();
+ if (!p) return 0;
+ return p->getAlwaysOnTop();
+}
+#endif
+
+void BaseWnd::wndwatcher_onDeleteWindow(ifc_window *w)
+{
+ if (w == rootfocus)
+ {
+ rootfocus = NULL;
+ }
+}
+
+void BaseWnd::assignRootFocus(ifc_window *w)
+{
+ rootfocuswatcher.watchWindow(w);
+ rootfocus = w;
+}
+
+
+Canvas *BaseWnd::getFrameBuffer()
+{
+ return virtualCanvas;
+}
+
+void BaseWnd::setForeignWnd(int i)
+{
+ m_takenOver = i;
+}
+
+int BaseWnd::bufferizeLockedUIMsg(int uMsg, int wParam, int lParam)
+{
+ if (WASABI_API_SKIN && !WASABI_API_SKIN->skin_getLockUI()) return 0;
+ if (!uiwaslocked)
+ {
+ uiwaslocked = 1;
+ setTimer(BUFFEREDMSG_TIMER_ID, 20);
+ }
+ bufferedMsgStruct msg;
+ msg.msg = uMsg;
+ msg.wparam = wParam;
+ msg.lparam = lParam;
+ bufferedmsgs.addItem(msg);
+ return 1;
+}
+
+void BaseWnd::checkLockedUI()
+{
+ //PORTME :(
+#ifdef _WIN32
+
+ if (WASABI_API_SKIN && !WASABI_API_SKIN->skin_getLockUI())
+ {
+ uiwaslocked = 0;
+ killTimer(BUFFEREDMSG_TIMER_ID);
+ while (bufferedmsgs.getNumItems() > 0)
+ {
+ bufferedMsgStruct msg = bufferedmsgs.enumItem(0);
+ bufferedmsgs.delByPos(0);
+ SendMessageW(gethWnd(), msg.msg, msg.wparam, msg.lparam);
+ }
+ uiwaslocked = 0;
+ killTimer(BUFFEREDMSG_TIMER_ID);
+ }
+#else
+#warning port me
+#endif
+}
+
+int BaseWnd::isMinimized()
+{
+ ifc_window *w = getDesktopParent();
+ if (w == this || w == NULL) return minimized;
+ return w->isMinimized();
+}
+
+int BaseWnd::reinit()
+{
+#ifdef _WIN32
+ int nochild = (GetWindowLong(gethWnd(), GWL_STYLE) & WS_POPUP) ? 1 : 0;
+ int r = reinit(parentWnd ? parentWnd : WASABI_API_WND->main_getRootWnd(), nochild);
+
+ if (w2k_alpha)
+ setLayeredWindow(1);
+
+ return r;
+#else
+#warning port me!
+#endif
+}
+
+
+int BaseWnd::reinit(ifc_window *parWnd, int nochild)
+{
+ OSWINDOWHANDLE phwnd = parWnd->getOsWindowHandle();
+ ASSERT(phwnd != NULL);
+ int ret;
+ if (!nochild) parentWnd = parWnd;
+ else parentWnd = NULL;
+ ret = reinit(parWnd->getOsModuleHandle(), phwnd, nochild);
+ if (!ret) parentWnd = NULL; // abort
+ return ret;
+}
+
+int BaseWnd::reinit(OSMODULEHANDLE moduleHandle, OSWINDOWHANDLE parent, int nochild)
+{
+ RECT r;
+ int w, h;
+
+ onBeforeReinit();
+
+ pushWindowRect();
+ preventcancelcapture = 1;
+
+ int _isvisible = isVisible(1);
+ int hadcapture = inputCaptured;
+ //DebugString("had capture = %d\n", hadcapture);
+ Wasabi::Std::Wnd::releaseCapture();
+
+ unparentHWNDChildren();
+
+ BaseWnd::getClientRect(&r);
+
+ hinstance = moduleHandle;
+
+ ASSERT(hinstance != NULL);
+
+ w = (r.right - r.left);
+ h = (r.bottom - r.top);
+
+ rwidth = w;
+ rheight = h;
+ rx = r.left;
+ ry = r.top;
+
+ WASABI_API_WND->appdeactivation_push_disallow(this);
+
+ // destroy old window
+ Wasabi::Std::Wnd::hideWnd(hwnd); //Wasabi::Std::Wnd::destroyWnd(hwnd);
+ ghosthwnd.addItem(hwnd);
+
+ hwnd = Wasabi::Std::Wnd::createWnd(&r, nochild, acceptExternalDrops(), parent, hinstance, static_cast<ifc_window*>(this));
+#ifdef __APPLE__
+#warning remove me
+ Wasabi::Std::Wnd::showWnd(hwnd);
+#endif
+
+ WASABI_API_WND->appdeactivation_pop_disallow(this);
+
+ //ASSERT(hwnd != NULL); // lets fail nicely, this could happen for some win32 reason, we don't want to fail the whole app for it, so lets just fail the wnd
+ if (hwnd == NULL)
+ {
+ preventcancelcapture = 0;
+ return 0;
+ }
+
+ //CUT nreal++;
+
+#ifdef _WIN32
+ //FUCKO
+#ifdef URLDROPS
+ if (acceptExternalDrops()) RegisterDragDrop(hwnd, &m_target);
+#elif !defined(WA3COMPATIBILITY)
+ if (!m_target && WASABI_API_WND != NULL)
+ m_target = WASABI_API_WND->getDefaultDropTarget();
+ if (m_target != NULL)
+ {
+ RegisterDragDrop(hwnd, (IDropTarget *)m_target);
+ }
+#endif
+#else
+#warning port me - register drag & drop
+#endif
+
+ this_visible = _isvisible;
+
+ //onInit();
+ //this_visible = !start_hidden;
+
+ reparentHWNDChildren();
+
+ popWindowRect();
+
+ invalidateWindowRegion();
+ updateWindowRegion();
+
+ if (this_visible)
+ Wasabi::Std::Wnd::showWnd(hwnd, FALSE);
+
+ if (hadcapture)
+ {
+ Wasabi::Std::Wnd::setCapture(hwnd);
+ }
+ preventcancelcapture = 0;
+
+ forcedOnResize();
+ redrawHWNDChildren();
+ //onPostOnInit();
+
+ onAfterReinit();
+
+#ifdef WASABI_ON_REPARENT
+ WASABI_ON_REINIT(getOsWindowHandle());
+#endif
+
+ return 1;
+}
+
+ReparentWndEntry::ReparentWndEntry(OSWINDOWHANDLE _wnd, OSWINDOWHANDLE parentwnd)
+{
+ wnd = _wnd;
+ Wasabi::Std::Wnd::getWindowRect(wnd, &rect);
+ Wasabi::Std::Wnd::screenToClient(wnd, (int *)&(rect.left), (int *)&(rect.top));
+ Wasabi::Std::Wnd::clientToScreen(parentwnd, (int *)&(rect.left), (int *)&(rect.top));
+}
+
+void ReparentWndEntry::unparent()
+{
+ Wasabi::Std::Wnd::setWndPos(wnd, NULL, rect.left, -30000, 0, 0, TRUE, TRUE, FALSE, FALSE, TRUE);
+ Wasabi::Std::Wnd::setParent(wnd, NULL);
+}
+
+void ReparentWndEntry::reparent(OSWINDOWHANDLE newparent)
+{
+ Wasabi::Std::Wnd::setParent(wnd, newparent);
+ Wasabi::Std::Wnd::setWndPos(wnd, NULL, rect.left, rect.top, 0, 0, TRUE, TRUE, FALSE, FALSE, TRUE);
+}
+
+#ifdef _WIN32
+void BaseWnd::unparentHWNDChildren()
+{
+ // just in case
+ reparentwnds.deleteAll();
+
+#ifndef WIN32
+#error port me ! // make a list of all the children oswindows and reparent them to the desktop somewhere we can't see
+#endif
+
+ OSWINDOWHANDLE wnd = GetWindow(getOsWindowHandle(), GW_CHILD);
+ while (wnd)
+ {
+ reparentwnds.addItem(new ReparentWndEntry(wnd, getOsWindowHandle()));
+ wnd = GetWindow(wnd, GW_HWNDNEXT);
+ }
+ foreach(reparentwnds)
+ reparentwnds.getfor()->unparent();
+ endfor;
+}
+#endif
+
+void BaseWnd::reparentHWNDChildren()
+{
+ // reparent to the new oswindowhandle
+ foreach(reparentwnds)
+ reparentwnds.getfor()->reparent(getOsWindowHandle());
+ endfor;
+}
+
+void BaseWnd::redrawHWNDChildren()
+{
+ // reparent to the new oswindowhandle
+ foreach(reparentwnds)
+ Wasabi::Std::Wnd::update(getOsWindowHandle());
+ endfor;
+}
+
+void BaseWnd::maximize(int axis)
+{
+ //DebugString("maximize!\n");
+ // if already maximized, don't use current rect, use restore_rect
+ if (!maximized)
+ {
+ restore_rect.left = rx;
+ restore_rect.top = ry;
+ restore_rect.right = rx + rwidth;
+ restore_rect.bottom = ry + rheight;
+ }
+
+ RECT nr = restore_rect;
+ RECT dr;
+
+ Wasabi::Std::getViewport(&dr, NULL, NULL, getOsWindowHandle(), 0);
+
+ if (axis & MAXIMIZE_WIDTH)
+ {
+ nr.left = dr.left;
+ nr.right = dr.right;
+ }
+ if (axis & MAXIMIZE_HEIGHT)
+ {
+ nr.top = dr.top;
+ nr.bottom = dr.bottom;
+ }
+ maximized = 1;
+ if (axis != 0) resize(&nr);
+ onMaximize();
+}
+
+void BaseWnd::restore(int what)
+{
+ if (maximized)
+ {
+ //DebugString("restore!\n");
+ if (what == (RESTORE_X | RESTORE_Y | RESTORE_WIDTH | RESTORE_HEIGHT))
+ resize(&restore_rect);
+ else
+ {
+ resize((what & RESTORE_X) ? restore_rect.left : NOCHANGE,
+ (what & RESTORE_Y) ? restore_rect.top : NOCHANGE,
+ (what & RESTORE_WIDTH) ? restore_rect.right - restore_rect.left : NOCHANGE,
+ (what & RESTORE_HEIGHT) ? restore_rect.bottom - restore_rect.top : NOCHANGE);
+ }
+ maximized = 0;
+ onRestore();
+ }
+}
+
+void BaseWnd::pushWindowRect()
+{
+ //DebugString("pushWindowRect\n");
+ RECT wr;
+ getWindowRect(&wr);
+ wr.right = wr.left + rwidth;
+ wr.bottom = wr.top + rheight;
+ windowrectstack.push(wr);
+}
+
+int BaseWnd::popWindowRect(RECT *rc, int applyhow)
+{
+ //DebugString("popWindowRect\n");
+ if (windowrectstack.peek() == 0) return 0;
+ RECT _rc;
+ windowrectstack.pop(&_rc);
+ RECT r;
+ getWindowRect(&r);
+ divRatio(&r);
+ if (applyhow)
+ {
+ if (applyhow == PWR_POSITION)
+ {
+ move(_rc.left, _rc.top);
+ if (rc)
+ {
+ int w = r.right - r.left;
+ int h = r.bottom - r.top;
+ rc->left = _rc.left;
+ rc->top = _rc.top;
+ rc->right = rc->left + w;
+ rc->bottom = rc->top + h;
+ }
+ }
+ else
+ {
+ if (applyhow & PWR_X) r.left = _rc.left;
+ if (applyhow & PWR_Y) r.top = _rc.top;
+ if (applyhow & PWR_WIDTH) r.right = r.left + (_rc.right - _rc.left);
+ if (applyhow & PWR_HEIGHT) r.bottom = r.top + (_rc.bottom - _rc.top);
+ resizeToRect(&r);
+ if (rc) *rc = _rc;
+ }
+ }
+ else if (rc) *rc = _rc;
+ return 1;
+}
+
+void BaseWnd::setRestoredRect(RECT *r)
+{
+ if (!r)
+ return ;
+
+ restore_rect = *r;
+ maximized = 1;
+}
+
+int BaseWnd::getRestoredRect(RECT *r)
+{
+ if (!r)
+ return 0;
+
+ if (!maximized)
+ return 0;
+
+ *r = restore_rect;
+
+ return 1;
+}
+
+void BaseWnd::notifyDeferredMove(int x, int y)
+{
+ rx = x;
+ ry = y;
+}
+
+void BaseWnd::setWindowTitle(const wchar_t *title)
+{
+ Layout *l = static_cast<Layout *>(getInterface(layoutGuid));
+ if (l)
+ {
+ Container *c = l->getParentContainer();
+ if (c)
+ {
+ c->setName(title);
+ }
+ }
+}
+
+#ifdef __APPLE__
+OSStatus BaseWnd::eventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
+{
+ return eventNotHandledErr;
+}
+#endif
diff --git a/Src/Wasabi/api/wnd/basewnd.h b/Src/Wasabi/api/wnd/basewnd.h
new file mode 100644
index 00000000..b8747af0
--- /dev/null
+++ b/Src/Wasabi/api/wnd/basewnd.h
@@ -0,0 +1,944 @@
+//NONPORTABLE
+#ifndef _BASEWND_H
+#define _BASEWND_H
+
+#include <api/wnd/api_wnd.h>
+#include <api/timer/api_timer.h>
+#include <bfc/wasabi_std.h>
+#include <bfc/common.h>
+#include <api/wnd/api_window.h>
+#include <api/wnd/drag.h>
+#include <bfc/ptrlist.h>
+#include <bfc/tlist.h>
+#include <bfc/named.h>
+#include <api/timer/timerclient.h>
+#include <api/wnd/findobjectcb.h>
+#include <bfc/stack.h>
+#include <api/wnd/rootwnd.h>
+class BaseWnd;
+#include <tataki/canvas/bltcanvas.h>
+class FilenamePS;
+class Canvas;
+class ifc_canvas;
+class RegionI;
+class DragSet;
+class VirtualWnd;
+class Tooltip;
+class svc_toolTipsRenderer;
+class Accessible;
+
+// for triggerEvent()
+#define TRIGGER_ONRESIZE 1000
+#define TRIGGER_INVALIDATE 2000
+
+// it is safe to use anything higher than this for your own funky messages
+#define BASEWND_NOTIFY_USER NUM_NOTIFY_MESSAGES
+
+#define BASEWND_CURSOR_USERSET -1// window will do own setting
+#define BASEWND_CURSOR_POINTER 1
+#define BASEWND_CURSOR_NORTHSOUTH 2
+#define BASEWND_CURSOR_EASTWEST 3
+#define BASEWND_CURSOR_NORTHWEST_SOUTHEAST 4
+#define BASEWND_CURSOR_NORTHEAST_SOUTHWEST 5
+#define BASEWND_CURSOR_4WAY 6
+#define BASEWND_CURSOR_EDIT 7
+
+// Our own defined window messages
+
+#define WM_WA_CONTAINER_TOGGLED WM_USER+0x1338
+#define WM_WA_COMPONENT_TOGGLED WM_USER+0x1339
+#define WM_WA_RELOAD WM_USER+0x133A
+#define WM_WA_GETFBSIZE WM_USER+0x133B
+
+#define DEFERREDCB_FLUSHPAINT 0x200
+
+#define SYSRGN 4
+
+#define REGIONOP_NONE 0
+#define REGIONOP_OR 1
+#define REGIONOP_AND 2
+#define REGIONOP_SUB -1
+#define REGIONOP_SUB2 -2
+
+#define TABORDER_K 0.0001f
+
+class ReparentWndEntry {
+ public:
+ ReparentWndEntry(OSWINDOWHANDLE wnd, OSWINDOWHANDLE parentwnd);
+ virtual ~ReparentWndEntry() {}
+ void unparent();
+ void reparent(OSWINDOWHANDLE newparent);
+ private:
+ RECT rect;
+ OSWINDOWHANDLE wnd;
+};
+
+class virtualChildTimer {
+ public:
+ virtualChildTimer(int _id, ifc_window *_child) : id(_id), child(_child) { }
+ virtual ~virtualChildTimer() {}
+ int id;
+ ifc_window *child;
+};
+
+class RootWndFinder : public FindObjectCallbackI {
+ public:
+
+ RootWndFinder() { findobject_guid = INVALID_GUID; }
+ virtual ~RootWndFinder() { }
+
+ void reset() { findobject_id = L""; findobject_guid = INVALID_GUID; }
+ void setFindId(const wchar_t *id) { findobject_id = id; }
+ void setFindGuid(GUID guid) { findobject_guid = guid; }
+
+ virtual int findobjectcb_matchObject(ifc_window *w) {
+ if (!findobject_id.isempty()) {
+ if (w != NULL) {
+ const wchar_t *id = w->getId();
+ return WCSCASEEQLSAFE(id, findobject_id);
+ }
+ } else if (findobject_guid != INVALID_GUID) {
+ return (w->getInterface(findobject_guid) != NULL);
+ }
+ return 0;
+ }
+
+ private:
+
+ StringW findobject_id;
+ GUID findobject_guid;
+};
+
+#ifdef _WIN32
+typedef struct {
+ HWND owner;
+ HWND hthis;
+ PtrList<ifc_window> *hlist;
+} enumownedstruct;
+#endif
+
+class WndWatcher: public DependentViewerI {
+ public:
+ WndWatcher(BaseWnd *b) : watched(NULL), dep(NULL), watcher(b) { ASSERT(watcher != NULL); }
+ WndWatcher() : watched(NULL), dep(NULL), watcher(NULL) { }
+ virtual ~WndWatcher() {}
+
+ virtual void setWatcher(BaseWnd *w) {
+ if (watcher != NULL)
+ watchWindow(NULL);
+ watcher = w;
+ }
+
+ virtual void watchWindow(ifc_window *w) {
+ ASSERT(watcher != NULL);
+ if (dep != NULL) {
+ viewer_delViewItem(dep);
+ dep = NULL;
+ watched = NULL;
+ }
+ if (w != NULL) {
+ watched = w;
+ dep = w->getDependencyPtr();
+ viewer_addViewItem(dep);
+ }
+ }
+
+ virtual int viewer_onItemDeleted(ifc_dependent *item);
+
+ private:
+ ifc_window *watched;
+ ifc_dependent *dep;
+ BaseWnd *watcher;
+};
+
+#ifdef _WIN32
+BOOL CALLBACK EnumOwnedTopMostWindows(HWND hwnd, LPARAM lParam);
+#endif
+
+class TabOrderEntry {
+ public:
+ ifc_window *wnd;
+ float order; // yes, float. if a wnd tries to set order n and n is already set for another wnd, that other wnd will be pushed to n+k
+ // with k = 0.0001 . recursively, if n+k is taken, it'll push that wnd to n+2k, which if taken has its wnd pushed to n+3k, etc
+ // if n+xk >= n+1 (when x = 10000), the 10000th entry is discarded (if you manage to make a dialog with 10000 keyboard fields inside
+ // a single group, you're nuts anyway, and you should die a painful death)
+};
+
+class TabOrderSort {
+public:
+ static int compareItem(TabOrderEntry *p1, TabOrderEntry *p2) {
+ if (p1->order < p2->order) return -1;
+ if (p1->order > p2->order) return 1;
+ return 0;
+ }
+};
+
+
+// base class
+#define BASEWND_PARENT RootWndI
+class NOVTABLE BaseWnd :
+ public RootWndI,
+ public DragInterface,
+ public NamedW,
+ public DependentI,
+ public TimerClientI
+{
+
+ friend class VirtualWnd;
+
+protected:
+ // override constructor to init your data, but don't create anything yet
+ BaseWnd();
+
+public:
+
+ virtual ~BaseWnd();
+
+//INITIALIZATION
+ // these actually create the window
+ // try REALLY hard to not have to override these, and if you do,
+ // override the second one
+ virtual int init(ifc_window *parent, int nochild=FALSE);
+ virtual int init(OSMODULEHANDLE hInstance, OSWINDOWHANDLE parent, int nochild=FALSE);
+ virtual int isInited(); // are we post init() ?
+ virtual int isPostOnInit() { return postoninit; }
+
+ virtual int setVirtual(int i) { return 0; }
+
+ // if at all possible put your init stuff in this one, and call up the
+ // heirarchy BEFORE your code
+ virtual int onInit();
+ virtual int onPostOnInit(); // this one is called after onInit so you get a chance to do something after your inheritor override
+
+ // use this to return the cursor type to show
+ virtual int getCursorType(int x, int y);
+
+// WINDOW SIZING/MOVEMENT/CONTROL
+ virtual int getFontSize() { return 0; }
+ virtual int setFontSize(int size) { return -1; }
+
+ // if you override it, be sure to call up the heirarchy
+ virtual void resize(int x, int y, int w, int h, int wantcb=1); // resize yourself
+ void resize(RECT *r, int wantcb=1);
+ void resizeToRect(RECT *r) { resize(r); }//helper
+
+ // called after resize happens, return TRUE if you override
+ virtual int onResize();
+ virtual int onAfterResize() { return 1; }
+ void resizeToClient(BaseWnd *wnd); // resize a window to match you
+ virtual int onPostedMove(); // whenever WM_WINDOWPOSCHANGED happens, use mainly to record positions when moved by the window tracker, avoid using for another prupose, not portable
+
+ // move only, no resize
+ virtual void move(int x, int y);
+
+ virtual void notifyDeferredMove(int x, int y);
+
+ // puts window on top of its siblings
+ virtual void bringToFront();
+ // puts window behind its siblings
+ virtual void bringToBack();
+
+ // fired when a sibbling invalidates a region. you can change the region before returning, use with care, can fuck up everything if not used well
+ virtual int onSiblingInvalidateRgn(api_region *r, ifc_window *who, int who_idx, int my_idx) { return 0; }
+
+ // set window's visibility
+ virtual void setVisible(int show);
+ virtual void setCloaked(int cloak);
+ virtual void onSetVisible(int show); // override this one
+ virtual void onChildInvalidate(api_region *r, ifc_window *w) {}
+
+ // enable/disable window for input
+ virtual void setEnabled(int en);
+ // grab the keyboard focus
+ virtual void setFocus();
+ virtual void setFocusOnClick(int f);
+ virtual int getFocusOnClick() { return focus_on_click; }
+
+ virtual int pointInWnd(POINT *p);
+
+ // repaint yourself
+ virtual void invalidate(); // mark entire window for repainting
+ virtual void invalidateRect(RECT *r);// mark specific rect for repainting
+ virtual void invalidateRgn(api_region *r);// mark specific rgn for repainting
+ virtual void invalidateFrom(ifc_window *who); // mark entire window for repainting
+ virtual void invalidateRectFrom(RECT *r, ifc_window *who);// mark specific rect for repainting
+ virtual void invalidateRgnFrom(api_region *r, ifc_window *who);// mark specific rgn for repainting
+ virtual void validate(); // unmark the entire window from repainting
+ virtual void validateRect(RECT *r); // unmark specific rect from repainting
+ virtual void validateRgn(api_region *reg); // unmark specific region from repainting
+
+ // no virtual on these please
+ void deferedInvalidateRgn(api_region *h);
+ void deferedInvalidateRect(RECT *r);
+ void deferedInvalidate();
+ void deferedValidateRgn(api_region *h);
+ void deferedValidateRect(RECT *r);
+ void deferedValidate();
+ api_region *getDeferedInvalidRgn();
+ int hasVirtualChildren();
+ virtual void setVirtualChildFocus(ifc_window *w);
+ virtual ifc_window *getNextVirtualFocus(ifc_window *w);
+ void setVirtualTabOrder(ifc_window *w, int a);
+ int getVirtualTabOrder(ifc_window *w);
+ virtual void setTabOrder(int a);
+ virtual int getTabOrder();
+ virtual void setAutoTabOrder();
+ virtual void setVirtualAutoTabOrder(ifc_window *w);
+ virtual void focusNext();
+ virtual void focusPrevious();
+ virtual ifc_window *getCurVirtualChildFocus() { return curVirtualChildFocus; }
+ virtual ifc_window *getTab(int what=TAB_GETNEXT);
+
+private:
+ //virtual int focusVirtualChild(api_window *child);
+ virtual void physicalInvalidateRgn(api_region *r);
+ void autoFocus(ifc_window *w);
+protected:
+ virtual int ensureVirtualCanvasOk();
+ virtual void setVirtualCanvas(Canvas *c);
+ virtual void setRSize(int x, int y, int w, int h);
+
+public:
+ virtual void repaint(); // repaint right now!
+
+ // override this to add decorations
+ virtual void getClientRect(RECT *);
+ RECT clientRect(); // helper
+ virtual void getNonClientRect(RECT *);
+ RECT nonClientRect(); // helper
+ virtual void getWindowRect(RECT *); // windows coords in screen system
+ RECT windowRect(); // helper
+ virtual void getPosition(POINT *pt); // window coord relative to os window (instead of rootparent)
+
+ virtual void *getInterface(GUID interface_guid) { return NULL; }
+ virtual void *dependent_getInterface(const GUID *classguid);
+
+ virtual void clientToScreen(int *x, int *y); // convenience fn
+ virtual void screenToClient(int *x, int *y); // convenience fn
+ virtual void clientToScreen(POINT *pt); // convenience fn
+ virtual void screenToClient(POINT *pt); // convenience fn
+ virtual void clientToScreen(RECT *r); // convenience fn
+ virtual void screenToClient(RECT *r); // convenience fn
+
+ void setIcon(OSICONHANDLE icon, int _small);
+ virtual void setSkinId(int id);
+
+ virtual int getPreferences(int what);
+ virtual void setPreferences(int what, int v);
+ virtual void setStartHidden(int wtf);
+
+ virtual void setDefaultCursor(Cursor *c);
+ virtual Canvas *getFrameBuffer();
+
+ void setWindowTitle(const wchar_t *title);
+
+
+// from api_window
+protected:
+ virtual DragInterface *getDragInterface();
+ virtual ifc_window *rootWndFromPoint(POINT *pt);
+ virtual int rootwnd_paintTree(ifc_canvas *canvas, api_region *r);
+
+ void assignRootFocus(ifc_window *w);
+
+public:
+ // override for custom processing (NONPORTABLE!)
+#ifdef _WIN32
+ virtual LRESULT wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+#elif defined(__APPLE__)
+ virtual OSStatus eventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData);
+#endif
+ virtual void performBatchProcesses(); // this is called after wndProc is called (under win32) to recompute batch operations such as calculating window regions, cascaderepainting, etc. this prevents N children from independently calling repaintTree for the whole gui on overlaping zones of the framebuffer. under OSes other than win32, this should be called after you've executed all your window events for this poll, try not to use it, or use a dirty bit to cut down on your job
+ virtual const wchar_t *getRootWndName();
+ virtual const wchar_t *getId();
+// end from api_window
+
+ // or override these, they're more portable
+ virtual int onContextMenu(int x, int y); // always return 1 if accept msg
+ virtual int onChildContextMenu(int x, int y); // always return 1 if accept msg
+
+ // called on WM_PAINT by onPaint(Canvas, api_region *), if the canvas is null, create your own, if not, it will have update regions clipped for you
+ virtual int onPaint(Canvas *canvas);
+ void setTransparency(int amount); // 0..255
+ int getTransparency();
+
+ // override those two
+ virtual void timerCallback(int id);
+ virtual int onDeferredCallback(intptr_t p1, intptr_t p2);
+
+ int setTimer(int id, int ms);
+ int killTimer(int id);
+ void postDeferredCallback(intptr_t p1, intptr_t p2=0, int mindelay=0);
+
+ // from timerclient
+ virtual int timerclient_onDeferredCallback(intptr_t p1, intptr_t p2);
+ virtual void timerclient_timerCallback(int id);
+ virtual TimerClient *timerclient_getMasterClient();
+ virtual void timerclient_onMasterClientMultiplex();
+ virtual TimerClient *getTimerClient();
+ virtual const wchar_t *timerclient_getName();
+
+private:
+ virtual int onPaint(Canvas *canvas, api_region *r);
+
+public:
+ // click-drag. FYI, the drag-drop handling overrides these
+ virtual int onLeftButtonDown(int x, int y);
+ virtual int onRightButtonDown(int x, int y) { return 0; }
+ virtual int onMouseMove(int x, int y); // only called when mouse captured
+ virtual int onLeftButtonUp(int x, int y);
+ virtual int onRightButtonUp(int x, int y) { return 0; }
+ virtual int onMouseWheelUp(int click, int lines);
+ virtual int onMouseWheelDown(int click, int lines);
+ virtual int beginCapture();
+ virtual int endCapture();
+ virtual int getCapture(); // returns 1 if this window has mouse/keyb captured
+ virtual void onCancelCapture(); // called when someone steals the capture from you
+ virtual void cancelCapture();
+
+ // these will not be called in the middle of a drag operation
+ virtual int onLeftButtonDblClk(int x, int y);
+ virtual int onRightButtonDblClk(int x, int y);
+
+ virtual int onGetFocus(); // you have the keyboard focus
+ virtual int onKillFocus(); // you lost the keyboard focus
+ virtual int gotFocus();
+ virtual int isActive();
+ virtual int onActivate();
+ virtual void activate();
+ virtual int onDeactivate();
+ virtual int onEnable(int en);
+ virtual int isEnabled(int within=0);
+
+ virtual void registerAcceleratorSection(const wchar_t *name, int global=0);
+ virtual int onAcceleratorEvent(const wchar_t *name);
+
+ virtual int onChar(unsigned int c);
+ virtual int onKeyDown(int keyCode) { return 0; }
+ virtual int onKeyUp(int keyCode) { return 0; }
+ virtual int onSysKeyDown(int keyCode, int keyData) { return 0; }
+ virtual int onSysKeyUp(int keyCode, int keyData) { return 0; }
+
+ virtual int onEraseBkgnd(HDC dc);// override and return 0 to authorize bkg painting, 1 to avoid it (default to 1)
+ virtual int onUserMessage(int msg, int w, int l, int *r);
+
+//CHILD->PARENT MESSAGES
+ // feel free to override for your own messages, but be sure to call up the
+ // chain for unhandled msgs
+ // children should not call this directly if they don't have to; use
+ // notifyParent on yourself instead
+ // message ids should be put in notifmsg.h to avoid conflicts
+ virtual int childNotify(ifc_window *child, int msg,
+ int param1=0, int param2=0);
+
+
+ // don't try to override these
+ void setParent(ifc_window *newparent);
+ ifc_window *getParent();
+ virtual ifc_window *getRootParent();
+ virtual ifc_window *getDesktopParent();
+
+ // avoid overriding this one if you can
+ virtual int reparent(ifc_window *newparent);
+
+ // override this one
+ virtual void onSetParent(ifc_window *newparent) {}
+
+ virtual api_region *getRegion(); // override to return your client region
+ virtual void setRegionOp(int op); // 0 = none, 1 == or, 2=and, 3=xor, -1 = sub, -2 = sub thru groups
+ virtual void setRectRgn(int i); // set to 1 if you don't want your region to clip your clicks
+
+ virtual void invalidateWindowRegion(); // call this when your region has changed
+
+ api_region *getComposedRegion(); // returns the result of and/or/subing your children regions with your region
+ api_region *getSubtractorRegion(); // returns the composed subtracting region, that region is automatically subtracted from the desktop root parent's region
+ int ptInRegion(int x, int y); // handled automatically if you override getRegion and isRectRgn, but you can still override it if you need
+ virtual int getRegionOp(); //
+ virtual int isRectRgn();
+
+ // call this to notify your parent via its childNotify method
+ virtual int notifyParent(int msg, int param1=0, int param2=0);
+
+ // call this when you have received a childNotify and wish to
+ // defer the notification to your own notify object.
+ virtual int passNotifyUp(ifc_window *child, int msg,
+ int param1=0, int param2=0);
+
+ // This allows you to set a custom integer ID for any object you control,
+ // such that you can use its ID in a switch statement by calling getNotifyId()
+ // which is dispatched through api_window.
+ void setNotifyId(int id);
+ virtual int getNotifyId();
+
+ // from class Named
+ virtual void onSetName();
+ // non-virtuals only: sets the exported name of the OS window WITHOUT changing the Named member (getRootWndName() will not return this string)
+ virtual void setOSWndName(const wchar_t *name);
+ // non-virtuals only: retreive the exported name of the OS window. This is NOT the same as getRootWndName().
+ virtual const wchar_t *getOSWndName();
+
+ virtual const wchar_t *getTip();
+ virtual void setTip(const wchar_t *tooltip);
+ virtual int getStartHidden();
+ virtual void abortTip();
+ virtual int isVisible(int within=0);
+
+ // Virtual windows functions
+ virtual Canvas *createFrameBuffer(int w, int h);
+ virtual void prepareFrameBuffer(Canvas *canvas, int w, int h);
+ virtual void deleteFrameBuffer(Canvas *canvas);
+
+ virtual void registerRootWndChild(ifc_window *child);
+ virtual void unregisterRootWndChild(ifc_window *child);
+ virtual ifc_window *findRootWndChild(int x, int y, int only_virtuals=0);
+ virtual ifc_window *enumRootWndChildren(int _enum);
+ virtual int getNumRootWndChildren();
+
+ virtual int isVirtual();
+ virtual ifc_window *enumVirtualChild(int _enum);
+ virtual int getNumVirtuals();
+
+ virtual int handleVirtualChildMsg(UINT uMsg,int x, int y, void *p=NULL, void *d=NULL);
+ virtual void setVirtualChildCapture(ifc_window *child);
+ virtual ifc_window *getVirtualChildCapture();
+
+ virtual int cascadeRepaintFrom(ifc_window *who, int pack=1);
+ virtual int cascadeRepaintRgnFrom(api_region *reg, ifc_window *who, int pack=1);
+ virtual int cascadeRepaintRectFrom(RECT *r, ifc_window *who, int pack=1);
+ virtual int cascadeRepaint(int pack=1);
+ virtual int cascadeRepaintRgn(api_region *reg, int pack=1);
+ virtual int cascadeRepaintRect(RECT *r, int pack=1);
+ virtual void flushPaint();
+
+ virtual void onMinimize();
+ virtual void onRestore();
+ virtual int isMinimized();
+ virtual int isMaximized() { return maximized; }
+ virtual void onMaximize() { }
+
+ virtual void freeResources();
+ virtual void reloadResources();
+ virtual int getDesktopAlpha();
+ virtual int handleDesktopAlpha() { return isVirtual(); }
+ virtual int getPaintingAlpha(); // this one is a hint for painting, it returns either activealpha or inactivealpha
+ virtual void setAlpha(int activealpha, int inactivealpha=-1); // -1 means same as activealpha
+ virtual void getAlpha(int *activealpha=NULL, int *inactivealpha=NULL);
+ virtual int getFlag(int flag);
+ virtual int triggerEvent(int event, intptr_t p1, intptr_t p2);
+
+ void commitFrameBuffer(Canvas *canvas, RECT *r, double ratio);
+
+ virtual int paint(Canvas *canvas, api_region *r);
+
+protected:
+ void do_flushPaint();
+ virtual int paintTree(Canvas *canvas, api_region *r);
+ virtual int virtualBeforePaint(api_region *r);
+ virtual int virtualAfterPaint(api_region *r);
+ int virtualOnPaint();
+ virtual void setDesktopAlpha(int do_alpha);
+ virtual void onSetDesktopAlpha(int a);
+
+public:
+
+ virtual OSWINDOWHANDLE getOsWindowHandle();
+ virtual OSMODULEHANDLE getOsModuleHandle();
+
+public:
+
+ bool getNoCopyBits(void);
+ void setNoCopyBits(bool ncb);
+ BltCanvas *scalecanvas;
+
+protected:
+ virtual int checkDoubleClick(int button, int x, int y);
+
+//MISC
+public:
+ virtual int isDestroying(); // in the middle of dying
+
+//DRAGGING AND DROPPING -- (derived from DragInterface)
+
+ // derived windows should call this if they detect a drag beginning
+ // call once per datum per type of data being exposed. order is maintained
+ int addDragItem(const wchar_t *droptype, void *item);
+ // returns TRUE if drop was accepted
+ int handleDrag();
+ int resetDragSet(); // you don't need to call this
+
+ // (called on dest) when dragged item enters the winder
+ virtual int dragEnter(ifc_window *sourceWnd);
+ // (called on dest) during the winder
+ // FG> x/y are in screen corrdinates because target is a rootwnd
+ virtual int dragOver(int x, int y, ifc_window *sourceWnd) { return 0; }
+ // (called on src)
+ virtual int dragSetSticky(ifc_window *wnd, int left, int right, int up, int down);
+ // (called on dest) when dragged item leaves the winder
+ virtual int dragLeave(ifc_window *sourceWnd) { return 0; }
+
+ // when it finally is dropped:
+
+ // called on destination window
+ // FG> x/y are in screen corrdinates because target is a rootwnd
+ virtual int dragDrop(ifc_window *sourceWnd, int x, int y) { return 0; }
+ // called on source window
+ virtual int dragComplete(int success) { return 0; }
+ // in that order
+ // must be called right before handleDrag(); (sender)
+ void setSuggestedDropTitle(const wchar_t *title);
+
+ // must be called from dragDrop(); (receiver)
+ virtual const wchar_t *dragGetSuggestedDropTitle(void);
+ virtual int dragCheckData(const wchar_t *type, int *nitems=NULL);
+ virtual void *dragGetData(int slot, int itemnum);
+ virtual int dragCheckOption(int option) { return 0; }
+
+ // return TRUE if you support any of the datatypes this window is exposing
+ virtual int checkDragTypes(ifc_window *sourceWnd) { return 0; }
+
+// external drops
+ // override this and return 1 to receive drops from the OS
+ virtual int acceptExternalDrops() { return 0; }
+
+ virtual void onExternalDropBegin() {}
+ virtual void onExternalDropDirScan(const wchar_t *dirname) {}
+ virtual void onExternalDropEnd() {}
+
+ virtual int bypassModal();
+
+ virtual ifc_window *findWindow(const wchar_t *id);
+ virtual ifc_window *findWindowByInterface(GUID interface_guid);
+ virtual ifc_window *findWindowByCallback(FindObjectCallback *cb);
+ virtual ifc_window *findWindowChain(FindObjectCallback *cb, ifc_window *wcaller=NULL);
+
+private:
+ void addDroppedFile(const wchar_t *filename, PtrList<FilenamePS> *plist); // recursive
+ void setLayeredWindow(int i);
+ Accessible *createNewAccObj();
+
+public:
+//FG> alternate notify window
+ virtual void setNotifyWindow(ifc_window *newnotify);
+ virtual ifc_window *getNotifyWindow();
+
+ virtual double getRenderRatio();
+ virtual void setRenderRatio(double r);
+ virtual void onRatioChanged() {}
+ virtual void setRatioLinked(int l);
+ virtual int handleRatio();
+ int renderRatioActive();
+ void multRatio(int *x, int *y=NULL);
+ void multRatio(RECT *r);
+ void divRatio(int *x, int *y=NULL);
+ void divRatio(RECT *r);
+ virtual int isClickThrough();
+ virtual void setClickThrough(int ct);
+ virtual ifc_window *getForwardWnd() { return this; }
+
+ virtual void setNoLeftClicks(int no);
+ virtual void setNoRightClicks(int no);
+ virtual void setNoDoubleClicks(int no);
+ virtual void setNoMouseMoves(int no);
+ virtual void setNoContextMenus(int no);
+
+ // these functions are override that can be changed via XML. They are not intended to describe how your wnd should receive its messages, they are here rather
+ // to allow a skinner to disable part of the functionality of an object (ie: removing the context menu via nocontextmenu="1").
+ virtual int wantDoubleClicks() { return !nodoubleclick; }
+ virtual int wantLeftClicks() { return !noleftclick; }
+ virtual int wantRightClicks() { return !norightclick; }
+ virtual int wantMouseMoves() { return !nomousemove; }
+ virtual int wantContextMenus() { return !nocontextmnu; }
+
+
+// DERIVED WINDOW BEHAVIORAL PREFERENCES
+protected:
+ // return 1 to get onMouseOver even if mouse isn't captured
+ virtual int wantSiblingInvalidations();
+
+ virtual int wantFocus();
+ virtual int wantAutoContextMenu(); // return 1 if you want to auto popup the main app context menu
+
+protected:
+
+ void onTipMouseMove();
+ void renderBaseTexture(ifc_canvas *c, const RECT &r, int alpha=255);
+ void rootwnd_renderBaseTexture(ifc_canvas *c, const RECT *r, int alpha=255) { renderBaseTexture(c, *r, alpha); }
+
+ int getTabOrderEntry(ifc_window *w);
+ void delTabOrderEntry(int i);
+ int getTabOrderEntry(float order);
+ void delTabOrderEntry(ifc_window *w);
+
+ virtual OSCURSORHANDLE getCustomCursor(int x, int y);
+
+public:
+ virtual ifc_window *getBaseTextureWindow();
+ void setBaseTextureWindow(ifc_window *w);
+ virtual int isMouseOver(int x, int y);
+
+ virtual void bringVirtualToFront(ifc_window *w);
+ virtual void bringVirtualToBack(ifc_window *w);
+ virtual void bringVirtualAbove(ifc_window *w, ifc_window *b);
+ virtual void bringVirtualBelow(ifc_window *w, ifc_window *b);
+ void changeChildZorder(ifc_window *w, int newpos);
+
+//CUT static int isDesktopAlphaAvailable();
+//CUT static int isTransparencyAvailable();
+ virtual int handleTransparency(); // return 0 if you use overlay mode to render your stuff
+ virtual int runModal();
+ virtual int exec() { return runModal(); }
+ virtual void endModal(int ret);
+
+ ifc_dependent *rootwnd_getDependencyPtr();
+ ifc_dependent *timerclient_getDependencyPtr();
+
+ virtual void signalMinMaxEnforcerChanged(void);
+ virtual void onMinMaxEnforcerChanged(void) {}
+ virtual void addMinMaxEnforcer(ifc_window *w);
+ virtual void removeMinMaxEnforcer(ifc_window *w);
+ virtual ifc_window *enumMinMaxEnforcer(int n);
+ virtual int getNumMinMaxEnforcers();
+ virtual int onAction(const wchar_t *action, const wchar_t *param=NULL, int x=-1, int y=-1, intptr_t p1=0, intptr_t p2=0, void *data=NULL, size_t datalen=0, ifc_window *source=NULL);
+ virtual int sendAction(ifc_window *target, const wchar_t *action, const wchar_t *param=NULL, int x=0, int y=0, intptr_t p1=0, intptr_t p2=0, void *data=NULL, size_t datalen=0);
+
+ virtual void setRenderBaseTexture(int r);
+ virtual int getRenderBaseTexture();
+
+ virtual GuiObject *getGuiObject();
+
+ void setAutoResizeAfterInit(int tf) { want_autoresize_after_init = tf; }
+ virtual void setAllowDeactivation(int allow) { allow_deactivate = allow; }
+ virtual int allowDeactivation();
+
+ int getNumTabs();
+ ifc_window *enumTab(int i);
+ virtual void onSetRootFocus(ifc_window *w);
+
+ virtual int wantActivation() { return 1; } // return 0 if you don't want activation upon click
+
+ virtual Accessible *getAccessibleObject(int createifnotexists=1);
+
+ virtual int accessibility_getState();
+
+#ifdef EXPERIMENTAL_INDEPENDENT_AOT
+ virtual void setAlwaysOnTop(int i);
+ virtual int getAlwaysOnTop();
+#endif
+ virtual void wndwatcher_onDeleteWindow(ifc_window *w);
+
+ virtual void setOSModuleHandle(OSMODULEHANDLE module) { hinstance = module; }
+
+#ifndef WA3COMPATIBILITY
+ virtual void setDropTarget(void *dt);
+ virtual void *getDropTarget();
+#endif
+
+ virtual void pushWindowRect();
+ virtual int popWindowRect(RECT *rc=NULL, int applyhow=PWR_DIMENTIONS|PWR_POSITION);
+
+ virtual void maximize(int axis=MAXIMIZE_WIDTH|MAXIMIZE_HEIGHT);
+ virtual void restore(int what=RESTORE_X|RESTORE_Y|RESTORE_WIDTH|RESTORE_HEIGHT);
+ virtual int getRestoredRect(RECT *r);
+ virtual void setRestoredRect(RECT *r); // turns maximized state on automatically
+ virtual int forcedOnResize();
+ virtual void forcedOnResizeChain(ifc_window *w);
+
+protected:
+
+ void setForeignWnd(int i); // set to 1 if this basewnd was wrapped around an OSWINDOWHANDLE
+ // this means mainly that the destructor will not destroy the window handle.
+
+protected:
+ // ATTENTION: note the capitalization on these -- so as not to mix up with
+ // wndProc()'s hWnd
+ OSMODULEHANDLE hinstance;
+ OSWINDOWHANDLE hwnd;
+
+private:
+ ifc_window *parentWnd;
+
+ int inputCaptured;
+
+ void onTab();
+//CUT HWND createWindow(int x, int y, int w, int h, int nochild, HWND parent, HINSTANCE hinstance);
+ void recursive_setVirtualTabOrder(ifc_window *w, float a, float lambda=TABORDER_K);
+ void recursive_buildTabList(ifc_window *from, PtrList<ifc_window> *list);
+
+ RECT restore_rect;
+ int maximized;
+
+protected:
+
+ void dropVirtualCanvas();
+ int bufferizeLockedUIMsg(int uMsg, int wParam, int lParam);
+ void clearBufferizedUI() { bufferedmsgs.removeAll(); }
+ void checkLockedUI();
+ int checkModal();
+ void hintDestroying() { destroying=TRUE; } // call that in your destructor if you'd otherwise generate virtual calls after your destructor
+ virtual int forceTransparencyFlag();
+
+ int dragging;
+
+ Canvas *virtualCanvas;
+
+ void updateWindowRegion();
+ int isWindowRegionValid() { return !wndregioninvalid; }
+ virtual int wantRedrawOnResize() { return 1; }
+ int ensureWindowRegionValid();
+ int disable_tooltip_til_recapture;
+
+ virtual int reinit(); // calls reinit(api_window *parWnd, int nochild);
+ virtual int reinit(ifc_window *parWnd, int nochild); // calls reinit(OSMODULEHANDLE moduleHandle, OSWINDOWHANDLE parent, int nochild);
+ virtual int reinit(OSMODULEHANDLE moduleHandle, OSWINDOWHANDLE parent, int nochild);
+
+ int inonresize;
+
+ virtual void onBeforeReinit() {}
+ virtual void onAfterReinit() {}
+
+ StringW tip;
+private:
+ void reparentHWNDChildren();
+ void redrawHWNDChildren();
+ void unparentHWNDChildren();
+
+#ifdef EXPERIMENTAL_INDEPENDENT_AOT
+ void saveTopMosts();
+ void restoreTopMosts();
+#endif
+ void _cascadeRepaintRgn(api_region *rg);
+ void packCascadeRepaintRgn(api_region *rg);
+ int createTip();
+ void destroyTip(); // called in destructor, do not override
+ PtrList<DragSet> dragsets;
+ ifc_window *prevtarg;
+ StringW suggestedTitle;
+
+ typedef struct {
+ int msg;
+ int wparam;
+ int lparam;
+ } bufferedMsgStruct;
+
+ TList<bufferedMsgStruct> bufferedmsgs;
+ int uiwaslocked;
+
+ void onTip();
+ //FG
+ int start_hidden;
+ svc_toolTipsRenderer *tipsvc;
+
+ int tipid;
+ bool tip_done;
+ bool tipawaytimer;
+ bool tipshowtimer;
+ bool tipbeenchecked;
+ bool tipdestroytimer;
+
+ //FG
+ bool ncb;
+ uint32_t lastClick[2];
+ POINT lastClickP[2];
+
+ //FG
+ ifc_window *btexture;
+
+ //FG
+ ifc_window *notifyWindow;
+ bool destroying;
+
+ //CT:Virtual children
+ PtrList<ifc_window> virtualChildren;
+ PtrList<ifc_window> rootwndchildren; //FG
+ int virtualCanvasHandled;
+ int virtualCanvasH,virtualCanvasW;
+ int rwidth, rheight, rx, ry;
+ ifc_window *curVirtualChildCaptured;
+
+ //FG>
+ RegionI *deferedInvalidRgn;
+
+ OSWINDOWHANDLE oldCapture;
+
+ int hasfocus;
+ ifc_window *curVirtualChildFocus;
+
+ double ratio;
+ int skin_id;
+ int wndalpha;
+ int w2k_alpha;
+ int curframerate;
+
+ int notifyid;
+ int activealpha;
+ int inactivealpha;
+ int clickthrough;
+ int triedtipsvc;
+ int mustquit;
+ int returnvalue;
+ int postoninit;
+ int inited;
+ int skipnextfocus;
+ RegionI *subtractorrgn, *composedrgn;
+ void setWindowRegion(api_region *r);
+ void computeComposedRegion();
+ void assignWindowRegion(api_region *wr);
+ int wndregioninvalid;
+ int rectrgn, regionop;
+ RegionI *deferedCascadeRepaintRgn;
+ int need_flush_cascaderepaint;
+ Tooltip *tooltip;
+ PtrList<ifc_window> minmaxEnforcers;
+ int this_visible;
+ int renderbasetexture;
+ GuiObject *my_guiobject;
+ int want_autoresize_after_init;
+ int resizecount;
+ double lastratio;
+ int suggested_w, suggested_h;
+ int maximum_w, maximum_h;
+ int minimum_w, minimum_h;
+ int allow_deactivate;
+ int minimized;
+ int deleting;
+ int preventcancelcapture;
+ StringW tcname;
+ int focus_on_click;
+ PtrListQuickSorted<TabOrderEntry, TabOrderSort> childtabs;
+ ifc_window *rootfocus;
+ int ratiolinked;
+ int nodoubleclick, noleftclick, norightclick, nomousemove, nocontextmnu;
+ Cursor *customdefaultcursor;
+ Accessible *accessible;
+ StringW osname;
+ int focusEventsEnabled;
+ PtrList<ifc_window> ontoplist;
+ int alwaysontop;
+ WndWatcher rootfocuswatcher;
+
+ int cloaked;
+ int m_takenOver;
+ int this_enabled;
+ int has_alpha_flag;
+ RECT *commitfb_rect;
+ PtrList<ReparentWndEntry> reparentwnds;
+#ifndef WA3COMPATIBILITY
+ void *m_target;
+#endif
+ int lastnullregion;
+ Stack<RECT> windowrectstack;
+ TList<OSWINDOWHANDLE> ghosthwnd;
+ int ghostbust;
+
+ OSWINDOWHANDLE lastActiveWnd;
+
+};
+
+#ifdef WIN32
+__inline HINSTANCE HINSTANCEfromHWND(HWND wnd) {
+ if (wnd == NULL) return NULL;
+ return (HINSTANCE)(LONG_PTR)GetWindowLongPtrW(wnd, GWLP_HINSTANCE);
+}
+#endif
+
+#endif
diff --git a/Src/Wasabi/api/wnd/bitmap.cpp b/Src/Wasabi/api/wnd/bitmap.cpp
new file mode 100644
index 00000000..f89da5f6
--- /dev/null
+++ b/Src/Wasabi/api/wnd/bitmap.cpp
@@ -0,0 +1,1584 @@
+#include <precomp.h>
+
+//#define NO_SIMPLEFASTMODE
+#include <api/imgldr/api_imgldr.h>
+#include <api/wnd/blending.h>
+
+#include "bitmap.h"
+#ifndef _NOSTUDIO
+#include <api/api.h>
+#endif
+#include <bfc/std.h>
+#include <api/wnd/bltcanvas.h>
+
+#include <api/memmgr/memmgrapi.h>
+
+
+#if !defined(WIN32) && !defined(LINUX)
+#error port me!
+#endif
+
+#define ERRORBMP L"wasabi.bitmapnotfound"
+#define HARDERRORBMP L"xml/wasabi/window/error.png"
+// do not define NO_MMX in this file. :)
+
+#ifndef NO_MMX
+
+#ifdef WIN32
+#define MMX_CONST const
+#else
+#define MMX_CONST
+#endif
+
+static unsigned int MMX_CONST SkinBitmap_mmx_revn2[2]={0x01000100,0x01000100};
+static unsigned int MMX_CONST SkinBitmap_mmx_zero[2];
+static unsigned int MMX_CONST SkinBitmap_mmx_one[2]={1,0};
+#define HAS_MMX Blenders::MMX_AVAILABLE()
+
+#else
+
+//NO_MMX defined
+#define HAS_MMX 0
+
+#endif
+
+
+#ifndef _NOSTUDIO
+
+#ifdef WASABI_COMPILE_IMGLDR
+SkinBitmap::SkinBitmap(HINSTANCE hInstance, int id, const wchar_t *forcegroup)
+{
+ bitmapname = L"";
+ subimage_w=-1;
+ subimage_h=-1;
+ x_offset=-1;
+ y_offset=-1;
+ fullimage_w=fullimage_h=0;
+ has_alpha = 0;
+ ASSERT(hInstance != NULL);
+ ownbits=1;
+ fromskin = 0;
+ bits=WASABI_API_IMGLDR->imgldr_makeBmp(hInstance, id,&has_alpha,&fullimage_w,&fullimage_h, forcegroup);
+ last_failed = 0;
+ #ifdef WASABI_COMPILE_SKIN
+ if (bits == NULL)
+ {
+ //last_failed = 1;
+ //TODO: bits = WASABI_API_IMGLDR->imgldr_requestSkinBitmap(ERRORBMP, &has_alpha, &x_offset, &y_offset, &subimage_w, &subimage_h, &fullimage_w, &fullimage_h,_cached);
+ }
+ #endif
+ if (bits == NULL)
+ {
+ last_failed = 1;
+ bits = WASABI_API_IMGLDR->imgldr_makeBmp(HARDERRORBMP, &has_alpha, &fullimage_w, &fullimage_h);
+ }
+}
+#endif
+#endif
+
+// TODO: benski> make sure this works :)
+SkinBitmap::SkinBitmap(ARGB32 *_bits, int w, int h)
+{
+ subimage_w=-1;
+ subimage_h=-1;
+ x_offset=-1;
+ y_offset=-1;
+ bitmapname = L"";
+ fullimage_w=fullimage_h=0;
+ has_alpha = 1;
+ ownbits=0;
+ bits = _bits;
+ fromskin = 0;
+ last_failed = 0;
+}
+
+// TODO: benski> could we be using GetDIBits here?
+void SkinBitmap::bmpToBits(HBITMAP hbmp, HDC defaultDC)
+{
+#ifdef WIN32
+ if (hbmp && !bits)
+ {
+ BITMAPINFO srcbmi={0,};
+ HDC hMemDC, hMemDC2;
+ HBITMAP hprev,hprev2=0;
+ HBITMAP hsrcdib;
+ void *srcdib;
+ BITMAP bm;
+ int r = GetObject(hbmp, sizeof(BITMAP), &bm);
+ ASSERT(r != 0);
+
+ fullimage_w=bm.bmWidth;
+ fullimage_h=ABS(bm.bmHeight);
+
+ int bmw=getWidth();
+ int bmh=getHeight();
+ int xo=getX();
+ int yo=getY();
+
+ srcbmi.bmiHeader.biSize=sizeof(srcbmi.bmiHeader);
+ srcbmi.bmiHeader.biWidth=bmw;
+ srcbmi.bmiHeader.biHeight=-bmh;
+ srcbmi.bmiHeader.biPlanes=1;
+ srcbmi.bmiHeader.biBitCount=32;
+ srcbmi.bmiHeader.biCompression=BI_RGB;
+ hMemDC = CreateCompatibleDC(NULL);
+ hsrcdib=CreateDIBSection(hMemDC,&srcbmi,DIB_RGB_COLORS,&srcdib,NULL,0);
+ ASSERTPR(hsrcdib != 0, "CreateDIBSection() failed #6");
+ if (defaultDC)
+ hMemDC2 = defaultDC;
+ else {
+ hMemDC2 = CreateCompatibleDC(NULL);
+ hprev2 = (HBITMAP) SelectObject(hMemDC2, hbmp);
+ }
+ hprev = (HBITMAP) SelectObject(hMemDC, hsrcdib);
+ BitBlt(hMemDC,0,0,bmw,bmh,hMemDC2,xo,yo,SRCCOPY);
+ SelectObject(hMemDC, hprev);
+ if (!defaultDC) {
+ SelectObject(hMemDC2, hprev2);
+ DeleteDC(hMemDC2);
+ }
+ DeleteDC(hMemDC);
+ bits=(ARGB32*)MALLOC_(bmw*bmh*4);
+ if (getHeight()+getY() > bm.bmHeight || getWidth()+getX() > bm.bmWidth) {
+ ASSERTALWAYS(StringPrintf("Subbitmap coordinates outside master bitmap [%d,%d,%d,%d in 0,0,%d,%d]", getX(), getY(), getWidth(), getHeight(), bm.bmWidth, bm.bmHeight));
+ }
+ MEMCPY32(bits,srcdib,bmw*bmh/**sizeof(ARGB32)*/);
+ DeleteObject(hsrcdib);
+ x_offset=-1;
+ y_offset=-1;
+ subimage_w=-1;
+ subimage_h=-1;
+ fullimage_w=bmw;
+ fullimage_h=bmh;
+ }
+#endif
+#ifdef LINUX
+ if ( ! bits ) {
+ fullimage_w=hbmp.bmWidth;
+ fullimage_h=ABS(hbmp.bmHeight);
+
+ bits=(ARGB32*)MALLOC_( fullimage_w * fullimage_h * 4 );
+ MEMCPY32( bits, hbmp.shmseginfo->shmaddr, fullimage_w * fullimage_h );
+ x_offset=-1;
+ y_offset=-1;
+ subimage_w=-1;
+ subimage_h=-1;
+ }
+#endif
+}
+
+#ifndef _NOSTUDIO
+#ifdef WASABI_COMPILE_IMGLDR
+SkinBitmap::SkinBitmap(const wchar_t *elementname, int _cached)
+{
+ ASSERT(elementname!= NULL);
+
+ bitmapname = elementname;
+ x_offset = -1;
+ y_offset = -1;
+ subimage_w = -1;
+ subimage_h = -1;
+ fullimage_w=fullimage_h=0;
+ ownbits=1;
+ bits = NULL;
+ fromskin = 0;
+ last_failed = 0;
+#ifdef WASABI_COMPILE_SKIN
+ bits = WASABI_API_IMGLDR->imgldr_requestSkinBitmap(elementname, &has_alpha, &x_offset, &y_offset, &subimage_w, &subimage_h, &fullimage_w, &fullimage_h,_cached);
+ fromskin = (bits != NULL);
+#endif
+ if (bits == NULL)
+ bits = WASABI_API_IMGLDR->imgldr_makeBmp(elementname, &has_alpha, &fullimage_w, &fullimage_h);
+ #ifdef WASABI_COMPILE_SKIN
+ if (bits == NULL)
+ {
+ bits = WASABI_API_IMGLDR->imgldr_requestSkinBitmap(ERRORBMP, &has_alpha, &x_offset, &y_offset, &subimage_w, &subimage_h, &fullimage_w, &fullimage_h,_cached);
+ last_failed = 1;
+ }
+ #endif
+ if (bits == NULL)
+ {
+ bits = WASABI_API_IMGLDR->imgldr_makeBmp(HARDERRORBMP, &has_alpha, &fullimage_w, &fullimage_h);
+ last_failed = 1;
+ }
+
+ // check that coordinates are correct
+ if(x_offset!=-1 && x_offset>fullimage_w) x_offset=fullimage_w-1;
+ if(y_offset!=-1 && y_offset>fullimage_h) y_offset=fullimage_h-1;
+ if(subimage_w!=-1 && (x_offset+subimage_w)>fullimage_w) subimage_w=fullimage_w-x_offset;
+ if(subimage_h!=-1 && (y_offset+subimage_h)>fullimage_h) subimage_h=fullimage_h-y_offset;
+
+ // ASSERTPR(bits != NULL, elementname);
+ if (bits == NULL) {
+ DebugString("element not found ! %s\n", elementname);
+ int n = 10*10;
+ bits = (ARGB32 *)WASABI_API_MEMMGR->sysMalloc(n * 4);
+
+
+ ARGB32 *p = bits;
+ while (n--)
+ *p++ = 0xFFFF00FF;
+ }
+}
+#endif
+#endif
+
+SkinBitmap::SkinBitmap(HBITMAP bitmap)
+{
+#ifdef WIN32
+ ASSERT(bitmap != NULL);
+#endif
+ subimage_w=-1;
+ subimage_h=-1;
+ x_offset=-1;
+ y_offset=-1;
+ bitmapname = L"";
+ fullimage_w=fullimage_h=0;
+ has_alpha = 0;
+ ownbits=1;
+ bits = NULL;
+ fromskin = 0;
+ last_failed = 0;
+ bmpToBits(bitmap,NULL);
+}
+
+SkinBitmap::SkinBitmap(HBITMAP bitmap, HDC dc, int _has_alpha, void *_bits)
+{
+ subimage_w=-1;
+ subimage_h=-1;
+ x_offset=-1;
+ y_offset=-1;
+ fromskin = 0;
+ last_failed = 0;
+ bitmapname = L"";
+ fullimage_w=fullimage_h=0;
+#ifdef WIN32
+ ASSERT(bitmap != NULL);
+#endif
+ has_alpha = _has_alpha;
+ bits = (ARGB32*)_bits;
+ if (!_bits)
+ {
+ ownbits=1;
+ bmpToBits(bitmap,dc);
+ }
+ else
+ {
+#ifdef WIN32
+ BITMAP bm;
+ ownbits=0;
+ int r = GetObject(bitmap, sizeof(BITMAP), &bm);
+ ASSERT(r != 0);
+ fullimage_w=bm.bmWidth;
+ fullimage_h=ABS(bm.bmHeight);
+#endif
+#ifdef LINUX
+ ownbits=0;
+ fullimage_w=bitmap.bmWidth;
+ fullimage_h=ABS(bitmap.bmHeight);
+#endif
+//port me
+ }
+}
+
+SkinBitmap::SkinBitmap(int w, int h, DWORD bgcolor) {
+ subimage_w=-1;
+ subimage_h=-1;
+ x_offset=-1;
+ y_offset=-1;
+ fullimage_w=w;
+ bitmapname = L"";
+ fullimage_h=h;
+ fromskin = 0;
+ last_failed = 0;
+
+ int memsize = w*h*sizeof(ARGB32);
+ if (memsize == 0) memsize++; // +1 so no failure when 0x0
+ bits = (ARGB32*)MALLOC_(memsize);
+
+ DWORD *dw = (DWORD *)bits;
+ MEMFILL<DWORD>(dw, bgcolor, w*h);
+
+ has_alpha = TRUE;
+ ownbits=2; // 2 specifies should be FREE()'d
+}
+
+SkinBitmap::~SkinBitmap() {
+ if (bits) {
+ if (ownbits==2) FREE(bits);
+#ifndef _NOSTUDIO
+#ifdef WASABI_COMPILE_IMGLDR
+ else if (ownbits) {
+#ifdef WASABI_COMPILE_SKIN
+ if (fromskin)
+ WASABI_API_IMGLDR->imgldr_releaseSkinBitmap(bits);
+ else
+#endif
+#ifndef _WASABIRUNTIME
+ WASABI_API_IMGLDR->imgldr_releaseBmp(bits);
+#else
+ WASABI_API_IMGLDR->imgldr_releaseSkinBitmap(bits);
+#endif
+ }
+#endif
+#endif
+ }
+ bits=NULL;
+}
+
+void SkinBitmap::blit(ifc_canvas *canvas, int x, int y) {
+ RECT src, dst;
+ src.left=0;
+ src.top=0;
+ src.bottom=getHeight();
+ src.right=getWidth();
+ dst.left=x;
+ dst.right=x+getWidth();
+ dst.top=y;
+ dst.bottom=y+getHeight();
+ blitToRect(canvas,&src,&dst,255);
+}
+
+void SkinBitmap::blitRectToTile(ifc_canvas *canvas, RECT *dest, RECT *src, int xoffs, int yoffs, int alpha) {
+ int startx,starty;
+
+ int w,h;
+
+ w = src->right-src->left;
+ h = src->bottom-src->top;
+ if (w <= 0 || h <= 0) return; //wtfmf
+
+ RECT c;
+ if (canvas->getClipBox(&c) == NULLREGION) {
+ c = *dest;
+ } else {
+ if (dest->left > c.left) c.left = dest->left;
+ if (dest->top > c.top) c.top = dest->top;
+ if (dest->right < c.right) c.right = dest->right;
+ if (dest->bottom < c.bottom) c.bottom = dest->bottom;
+ }
+
+
+ starty = c.top-((c.top - dest->top) % h)- yoffs;
+ startx = c.left-((c.left - dest->left) % w) - xoffs;
+
+ for (int j=starty;j<c.bottom;j+=h)
+ for (int i=startx;i<c.right;i+=w) {
+ int xp=i;
+ int yp=j;
+ int xo=0;
+ int yo=0;
+ int _w=getWidth();
+ int _h=getHeight();
+ if (xp < c.left) {
+ xo=c.left-xp;
+ _w+=xo;
+ xp=c.left;
+ }
+ if (yp < c.top) {
+ yo=c.top-yp;
+ _h+=yo;
+ yp=c.top;
+ }
+ if (xp + _w >= c.right) _w=c.right-xp;
+ if (yp + _h >= c.bottom) _h=c.bottom-yp;
+ RECT _s={xo, yo, xo+_w, yo+_h};
+ RECT _d={xp, yp, xp+_w, yp+_h};
+ blitToRect(canvas, &_s, &_d, alpha);
+ }
+}
+
+
+void SkinBitmap::blitTile(ifc_canvas *canvas, RECT *dest, int xoffs, int yoffs, int alpha) {
+ RECT r={0,0,getWidth(),getHeight()};
+ blitRectToTile(canvas, dest, &r, xoffs, yoffs, alpha);
+}
+
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4799)
+#endif
+
+
+#define DEFAULT_CACHE_WIDTH 64
+#define DEFAULT_CACHE_HEIGHT 64
+int cacheWidth = DEFAULT_CACHE_WIDTH;
+int cacheHeight = DEFAULT_CACHE_HEIGHT;
+BltCanvas blitToRectCanvas(DEFAULT_CACHE_WIDTH,DEFAULT_CACHE_HEIGHT);
+
+void SkinBitmap::blitToRect(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha) { // only dst(top,left) are used
+
+ if (alpha <= 0) return;
+ if (alpha > 255) alpha = 255;
+
+ HDC hdc = canvas->getHDC();
+ if (hdc == NULL) return;
+ void *dib=canvas->getBits();
+ int cwidth,cheight, pitch;
+ BaseCloneCanvas clone(canvas);
+ bool usingBlitCanvas = false;
+ RECT destrect=*dst;
+ destrect.bottom=destrect.top+(src->bottom-src->top);
+ destrect.right=destrect.left+(src->right-src->left);
+
+ RECT c;
+ int ctype=canvas->getClipBox(&c);
+
+ if (c.top > destrect.top) destrect.top=c.top;
+ if (c.left > destrect.left) destrect.left=c.left;
+ if (c.bottom < destrect.bottom) destrect.bottom=c.bottom;
+ if (c.right < destrect.right) destrect.right=c.right;
+
+#ifdef NO_SIMPLEFASTMODE
+ dib=NULL;
+#endif
+
+ if (destrect.right <= destrect.left || destrect.bottom <= destrect.top) return;
+ int xs,yp,xe,ye;
+
+ if (!dib || canvas->getDim(NULL,&cheight,&cwidth) || !cwidth || cheight < 1 || ctype == COMPLEXREGION)
+ {
+ cwidth=destrect.right-destrect.left;
+ cheight=destrect.bottom-destrect.top;
+ if (cwidth > cacheWidth || cheight > cacheHeight)
+ {
+ cacheWidth=MAX(cacheWidth, cwidth);
+ cacheHeight=MAX(cacheHeight, cheight);
+ blitToRectCanvas.DestructiveResize(cacheWidth, cacheHeight);
+ }
+
+ dib = blitToRectCanvas.getBits();
+ if (has_alpha || alpha < 255)
+ clone.blit(destrect.left, destrect.top, &blitToRectCanvas, 0, 0, cwidth, cheight);
+
+ xs=0;
+ yp=0;
+ xe=cwidth;
+ ye=cheight;
+ pitch=cacheWidth;
+ usingBlitCanvas = true;
+ }
+ else
+ {
+
+ xs=destrect.left;
+ xe=destrect.right;
+ yp=destrect.top;
+ ye=destrect.bottom;
+
+ cwidth/=4;
+ pitch=cwidth;
+ }
+ int xpo=(dst->left-destrect.left+xs)-(getX()+src->left);
+ int ypo=(dst->top-destrect.top+yp)-(getY()+src->top);
+
+ if (yp < 0) yp=0;
+ if (xs < 0) xs=0;
+
+ if (yp<getY()+ypo) yp=ypo+getY();
+ if (xs<getX()+xpo) xs=xpo+getX();
+
+ if (xe > getWidth()+getX()+xpo) xe=getWidth()+getX()+xpo;
+ if (ye > getHeight()+getY()+ypo) ye=getHeight()+getY()+ypo;
+
+ // blend bitmap to dib
+
+ if (xs<xe) for (; yp < ye; yp ++) {
+ int xp=xe-xs;
+ unsigned int *dest=((unsigned int*)dib) + pitch*yp + xs;
+ unsigned int *src=((unsigned int*)bits) + (yp-ypo)*fullimage_w + (xs-xpo);
+
+ if (!has_alpha && alpha==255) // simple copy
+ {
+ MEMCPY32(dest,src,xp);
+ }
+ else if (!has_alpha) { // no alpha channel info, but just a simple blend
+ if (!HAS_MMX)
+ while (xp--) *dest++ = Blenders::BLEND_ADJ1(*src++, *dest, alpha);
+
+ #ifndef NO_MMX
+ else
+ {
+#ifdef WIN32
+ if (xp>1) __asm
+ {
+ movd mm3, [alpha]
+ mov ecx, xp
+
+ movq mm4, [SkinBitmap_mmx_revn2]
+ packuswb mm3, mm3 // 0000HHVV
+
+ paddusw mm3, [SkinBitmap_mmx_one]
+ mov edi, dest
+
+ punpcklwd mm3, mm3 // HHVVHHVV
+ mov esi, src
+
+ punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
+ shr ecx, 1
+
+ psubw mm4, mm3
+
+ align 16
+ _blitAlpha_Loop1:
+
+ movd mm0, [edi]
+
+ movd mm1, [esi]
+ punpcklbw mm0, [SkinBitmap_mmx_zero]
+
+ movd mm7, [edi+4]
+ punpcklbw mm1, [SkinBitmap_mmx_zero]
+
+ pmullw mm0, mm4
+ pmullw mm1, mm3
+
+ movd mm6, [esi+4]
+ punpcklbw mm7, [SkinBitmap_mmx_zero]
+
+ punpcklbw mm6, [SkinBitmap_mmx_zero]
+
+ pmullw mm7, mm4
+ pmullw mm6, mm3
+
+ paddw mm0, mm1
+
+ psrlw mm0, 8
+
+ packuswb mm0, mm0
+ add esi, 8
+
+ movd [edi], mm0
+ paddw mm7, mm6
+
+ psrlw mm7, 8
+
+ packuswb mm7, mm7
+
+ movd [edi+4], mm7
+
+ add edi, 8
+
+ dec ecx
+ jnz _blitAlpha_Loop1
+ mov src, esi
+ mov dest, edi
+#else
+ if ( xp > 1 ) {
+ __asm__ volatile (
+ "movd %6, %%mm3\n"
+ "mov %2, %%ecx\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm4\n"
+ "packuswb %%mm3, %%mm3\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm3\n"
+ "mov %0, %%edi\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "mov %1, %%esi\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "shr $1, %%ecx\n"
+ "psubw %%mm3, %%mm4\n"
+ ".align 16\n"
+ "_blitAlpha_Loop1:\n"
+ "movd (%%edi), %%mm0\n"
+ "movd (%%esi), %%mm1\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm0\n"
+ "movd 4(%%edi), %%mm7\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm1\n"
+ "pmullw %%mm3, %%mm0\n"
+ "pmullw %%mm4, %%mm1\n"
+ "movd 4(%%esi), %%mm6\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm7\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm6\n"
+ "pmullw %%mm4, %%mm6\n"
+ "pmullw %%mm3, %%mm7\n"
+ "paddw %%mm1, %%mm0\n"
+ "psrlw $8, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "add $8, %%esi\n"
+ "movd %%mm0, (%%edi)\n"
+ "paddw %%mm6, %%mm7\n"
+ "psrlw $8, %%mm7\n"
+ "packuswb %%mm7, %%mm7\n"
+ "movd %%mm7, 4(%%edi)\n"
+ "add $8, %%edi\n"
+ "dec %%ecx\n"
+ "jnz _blitAlpha_Loop1\n"
+ "mov %%esi, %1\n"
+ "mov %%edi, %0\n"
+
+ : "=m" (dest), "=m" (src), "=m" (xp)
+ : "0" (dest), "1" (src), "2" (xp), "m" (alpha)
+ : "%eax", "%ecx", "%esi", "%edi" );
+
+#endif
+ }
+ if (xp & 1) *dest++ = Blenders::BLEND_ADJ1_MMX(*src++, *dest, alpha);
+ } // mmx available
+ #endif // !NO_MMX
+ }
+ else if (alpha == 255) { // no global alpha, just alpha channel
+ if (!HAS_MMX)
+ while (xp--) *dest++ = Blenders::BLEND_ADJ2(*dest, *src++);
+
+ #ifndef NO_MMX
+ else
+ {
+#ifdef WIN32
+ if (xp > 1) __asm
+ {
+ mov ecx, xp
+ shr ecx, 1
+ mov edi, dest
+ mov esi, src
+ align 16
+ _blitAlpha_Loop2:
+
+ movd mm3, [esi]
+ movd mm5, [esi+4]
+
+ movq mm2, [SkinBitmap_mmx_revn2]
+ psrld mm3, 24
+
+ movq mm4, [SkinBitmap_mmx_revn2]
+ psrld mm5, 24
+
+ movd mm0, [edi]
+ packuswb mm3, mm3 // 0000HHVV
+
+ movd mm1, [esi]
+ packuswb mm5, mm5 // 0000HHVV
+
+ movd mm6, [esi+4]
+ paddusw mm3, [SkinBitmap_mmx_one]
+
+ punpcklwd mm3, mm3 // HHVVHHVV
+ paddusw mm5, [SkinBitmap_mmx_one]
+
+ movd mm7, [edi+4]
+ punpcklwd mm5, mm5 // HHVVHHVV
+
+ punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
+ punpckldq mm5, mm5 // HHVVHHVV HHVVHHVV
+
+ punpcklbw mm6, [SkinBitmap_mmx_zero]
+ psubw mm4, mm5
+
+ punpcklbw mm0, [SkinBitmap_mmx_zero]
+ psubw mm2, mm3
+
+ punpcklbw mm7, [SkinBitmap_mmx_zero]
+ pmullw mm0, mm2
+
+ pmullw mm7, mm4
+ punpcklbw mm1, [SkinBitmap_mmx_zero]
+
+ psubw mm2, mm3
+
+ psrlw mm0, 8
+ psrlw mm7, 8
+ paddw mm0, mm1
+
+ paddw mm7, mm6
+ packuswb mm0, mm0
+
+ movd [edi], mm0
+ packuswb mm7, mm7
+
+ movd [edi+4], mm7
+
+ add esi, 8
+ add edi, 8
+
+ dec ecx
+ jnz _blitAlpha_Loop2
+ mov src, esi
+ mov dest, edi
+#else
+ if( xp > 1 ) {
+ __asm__ volatile (
+ "mov %4, %%ecx\n"
+ "shr $1, %%ecx\n"
+ "mov %0, %%edi\n"
+ "mov %1, %%esi\n"
+ ".align 16\n"
+ "_blitAlpha_Loop2:\n"
+ "movd (%%esi), %%mm3\n"
+ "movd 4(%%esi), %%mm5\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm2\n"
+ "psrld $24, %%mm3\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm4\n"
+ "psrld $24, %%mm5\n"
+ "movd (%%edi), %%mm0\n"
+ "packuswb %%mm3, %%mm3\n"
+ "movd (%%esi), %%mm1\n"
+ "packuswb %%mm5, %%mm5\n"
+ "movd 4(%%esi), %%mm6\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm3\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm5\n"
+ "movd 4(%%edi), %%mm7\n"
+ "punpcklwd %%mm5, %%mm5\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "punpckldq %%mm5, %%mm5\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm6\n"
+ "psubw %%mm5, %%mm4\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm0\n"
+ "psubw %%mm3, %%mm2\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm7\n"
+ "pmullw %%mm2, %%mm0\n"
+ "pmullw %%mm4, %%mm7\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm1\n"
+ "psubw %%mm3, %%mm2\n"
+ "psrlw $8, %%mm0\n"
+ "psrlw $8, %%mm7\n"
+ "paddw %%mm1, %%mm0\n"
+ "paddw %%mm6, %%mm7\n"
+ "packuswb %%mm0, %%mm0\n"
+ "movd %%mm0, (%%edi)\n"
+ "packuswb %%mm7, %%mm7\n"
+ "movd %%mm7, 4(%%edi)\n"
+ "add $8, %%esi\n"
+ "add $8, %%edi\n"
+ "dec %%ecx\n"
+ "jnz _blitAlpha_Loop2\n"
+ "mov %%esi, %1\n"
+ "mov %%edi, %0\n"
+
+ : "=m" (dest), "=m" (src)
+ : "0" (dest), "1" (src), "m" (xp)
+ : "%eax", "%ecx", "%esi", "%edi" );
+#endif
+ }
+ if (xp&1) *dest++ = Blenders::BLEND_ADJ2_MMX(*dest, *src++);
+ } // HAS_MMX
+ #endif // ifndef NO_MMX
+ }
+ else { // both
+ if (!HAS_MMX)
+ while (xp--) *dest++ = Blenders::BLEND_ADJ3(*dest, *src++, alpha);
+ #ifndef NO_MMX
+ else
+ {
+#ifdef WIN32
+ if (xp > 1) __asm
+ {
+ movd mm5, [alpha]
+ mov ecx, xp
+
+ packuswb mm5, mm5
+ shr ecx, 1
+
+ paddusw mm5, [SkinBitmap_mmx_one]
+
+ punpcklwd mm5, mm5
+ mov edi, dest
+
+ punpckldq mm5, mm5
+ mov esi, src
+
+ align 16
+ _blitAlpha_Loop3:
+
+ movd mm3, [esi] // VVVVVVVV
+ movd mm4, [esi+4] // VVVVVVVV
+
+ movd mm0, [edi]
+ psrld mm3, 24
+
+ movd mm1, [esi]
+ psrld mm4, 24
+
+ paddusw mm3, [SkinBitmap_mmx_one]
+ paddusw mm4, [SkinBitmap_mmx_one]
+
+ movd mm7, [edi+4]
+ punpcklwd mm3, mm3
+
+ movd mm6, [esi+4]
+ punpcklwd mm4, mm4
+
+ punpckldq mm3, mm3
+ punpckldq mm4, mm4
+
+ pmullw mm3, mm5
+ pmullw mm4, mm5
+
+ punpcklbw mm7, [SkinBitmap_mmx_zero]
+ punpcklbw mm6, [SkinBitmap_mmx_zero]
+
+ movq mm2, [SkinBitmap_mmx_revn2]
+ psrlw mm3, 8
+
+ psrlw mm4, 8
+
+ punpcklbw mm0, [SkinBitmap_mmx_zero]
+ punpcklbw mm1, [SkinBitmap_mmx_zero]
+
+ psubw mm2, mm3
+ pmullw mm0, mm2
+
+ pmullw mm1, mm5
+ add esi, 8
+
+ movq mm2, [SkinBitmap_mmx_revn2]
+ pmullw mm6, mm5
+
+ paddusw mm0, mm1
+ psubw mm2, mm4
+
+ pmullw mm7, mm2
+ psrlw mm0, 8
+
+ packuswb mm0, mm0
+ paddusw mm7, mm6
+
+ movd [edi], mm0
+ psrlw mm7, 8
+
+ packuswb mm7, mm7
+
+ movd [edi+4], mm7
+
+ add edi, 8
+
+ dec ecx
+ jnz _blitAlpha_Loop3
+ mov src, esi
+ mov dest, edi
+#else
+ if ( xp > 1 ) {
+ __asm__ volatile (
+ "movd %5, %%mm5\n"
+ "mov %4, %%ecx\n"
+ "packuswb %%mm5, %%mm5 \n"
+ "shr $1, %%ecx\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm5\n"
+ "punpcklwd %%mm5, %%mm5\n"
+ "mov %0, %%edi\n"
+ "punpckldq %%mm5, %%mm5\n"
+ "mov %1, %%esi\n"
+ ".align 16\n"
+ "_blitAlpha_Loop3:\n"
+ "movd (%%esi), %%mm3\n"
+ "movd 4(%%esi), %%mm4\n"
+ "movd (%%edi), %%mm0\n"
+ "psrld $24, %%mm3\n"
+ "movd (%%esi), %%mm1\n"
+ "psrld $24, %%mm4\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm3\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm4\n"
+ "movd 4(%%edi), %%mm7\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "movd 4(%%esi), %%mm6\n"
+ "punpcklwd %%mm4, %%mm4\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "punpckldq %%mm4, %%mm4\n"
+ "pmullw %%mm5, %%mm3\n"
+ "pmullw %%mm5, %%mm4\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm7\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm6\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm2\n"
+ "psrlw $8, %%mm3\n"
+ "psrlw $8, %%mm4\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm0\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm1\n"
+ "psubw %%mm3, %%mm2\n"
+ "pmullw %%mm2, %%mm0\n"
+ "pmullw %%mm5, %%mm1\n"
+ "add $8, %%esi\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm2\n"
+ "pmullw %%mm5, %%mm6\n"
+ "paddusw %%mm1, %%mm0\n"
+ "psubw %%mm4, %%mm2\n"
+ "pmullw %%mm2, %%mm7\n"
+ "psrlw $8, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "paddusw %%mm6, %%mm7\n"
+ "movd %%mm0, (%%edi)\n"
+ "psrlw $8, %%mm7\n"
+ "packuswb %%mm7, %%mm7\n"
+ "movd %%mm7, 4(%%edi)\n"
+ "add $8, %%edi\n"
+ "dec %%ecx\n"
+ "jnz _blitAlpha_Loop3\n"
+ "mov %%esi, %1\n"
+ "mov %%edi, %0\n"
+
+ : "=m" (dest), "=m" (src)
+ : "0" (dest), "1" (src), "m" (xp), "m" (alpha)
+ : "%eax", "%ecx", "%esi", "%edi" );
+#endif
+ }
+ if (xp&1) *dest++ = Blenders::BLEND_ADJ3_MMX(*dest, *src++, alpha);
+ } // HAS_MMX
+ #endif // ifndef NO_MMX
+ }
+ }
+#ifndef NO_MMX
+ Blenders::BLEND_MMX_END();
+#endif
+ // write bits back to dib.
+
+ if (usingBlitCanvas) {
+ blitToRectCanvas.blit(0, 0, &clone, destrect.left, destrect.top, cwidth, cheight);
+ }
+}
+
+#ifdef WIN32
+#pragma warning(pop)
+#endif
+
+void SkinBitmap::stretch(ifc_canvas *canvas, int x, int y, int w, int h) {
+ RECT src, dst;
+ src.left=0;
+ src.top=0;
+ src.right=getWidth();
+ src.bottom=getHeight();
+ dst.left=x;
+ dst.right=x+w;
+ dst.top=y;
+ dst.bottom=y+h;
+ stretchToRectAlpha(canvas,&src,&dst,255);
+}
+
+void SkinBitmap::stretchToRect(ifc_canvas *canvas, RECT *r) {
+ stretch(canvas, r->left, r->top, r->right - r->left, r->bottom - r->top);
+}
+
+void SkinBitmap::stretchRectToRect(ifc_canvas *canvas, RECT *src, RECT *dst) {
+ stretchToRectAlpha(canvas,src,dst,255);
+}
+
+
+void SkinBitmap::stretchToRectAlpha(ifc_canvas *canvas, RECT *r, int alpha) {
+ RECT re;
+ re.left=0; re.top=0;
+ re.right=getWidth(); re.bottom=getHeight();
+ stretchToRectAlpha(canvas,&re,r,alpha);
+}
+
+void SkinBitmap::blitAlpha(ifc_canvas *canvas, int x, int y, int alpha)
+{
+ RECT dst,src;
+ dst.left=x;
+ dst.top=y;
+ src.left=0;
+ src.top=0;
+ src.bottom=getHeight();
+ src.right=getWidth();
+ blitToRect(canvas,&src,&dst,alpha);
+}
+
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4799)
+#endif
+
+template <class C>
+class Stretcher {
+public:
+ static void _stretchToRectAlpha(SkinBitmap *bitmap, int ys, int ye, int xe, int xs, int xstart, int yv, void *dib, int pitch, int dxv, int dyv, int alpha) {
+ int bitmap_x = bitmap->getX();
+ int bitmap_y = bitmap->getY();
+ int bmpheight = bitmap->getHeight();
+ int fullimage_w = bitmap->getFullWidth();
+ void *bits = bitmap->getBits();
+ int xp=xe-xs;
+ for (int yp = ys; yp < ye; yp ++) {
+ int t=yv>>16;
+ if (t < 0) t=0;
+ if (t >= bmpheight) t=bmpheight-1;
+ int *psrc=((int*)bits) + (t+bitmap_y)*fullimage_w + bitmap_x;
+ int *dest=((int*)dib) + pitch*yp + xs;
+
+ C::stretch(xp, psrc, dest, xstart, dxv, alpha);
+
+ yv+=dyv;
+ }
+ }
+};
+
+// no alpha, just stretch
+class Stretch {
+public:
+ static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha) {
+ while (xp--) { //JFtodo: assembly optimize - these first two modes aren't used that much anyway
+ *dest++ = psrc[xv>>16];
+ xv+=dxv;
+ }
+ }
+};
+
+// no alpha channel, just a global alpha val
+class StretchGlobal {
+public:
+ static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha) {
+ while (xp--) { //JFTODO: make MMX optimized version
+ *dest++ = Blenders::BLEND_ADJ1(psrc[xv>>16], *dest, alpha);
+ xv+=dxv;
+ }
+ }
+};
+
+// alpha channel, no global alpha val
+class StretchChannel {
+public:
+ static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha) {
+ while (xp--) {
+ *dest++ = Blenders::BLEND_ADJ2(*dest, psrc[xv>>16]);
+ xv+=dxv;
+ }
+ }
+};
+
+class StretchGlobalChannel {
+public:
+ static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha) {
+ while (xp--) {
+ *dest++ = Blenders::BLEND_ADJ3(*dest, psrc[xv>>16], alpha);
+ xv+=dxv;
+ }
+ }
+};
+
+
+#ifndef NO_MMX
+
+// no alpha channel, just a global alpha val
+class StretchGlobalMMX {
+public:
+ static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha) {
+ while (xp--) { //JFTODO: make MMX optimized version
+ *dest++ = Blenders::BLEND_ADJ1_MMX(psrc[xv>>16], *dest, alpha);
+ xv+=dxv;
+ }
+ }
+};
+
+
+// alpha channel, no global alpha val
+class StretchChannelMMX {
+public:
+ static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha) {
+#ifdef WIN32
+ if (xp>1) __asm
+ {
+ mov ecx, xp
+ mov edi, dest
+
+ shr ecx, 1
+ mov esi, psrc
+
+ mov edx, xv
+ mov ebx, dxv
+
+ align 16
+ _stretchAlpha_Loop2:
+
+ mov eax, edx
+ movd mm0, [edi]
+
+ movq mm4, [SkinBitmap_mmx_revn2]
+ shr eax, 16
+
+ movq mm2, [SkinBitmap_mmx_revn2]
+ punpcklbw mm0, [SkinBitmap_mmx_zero]
+
+ movd mm3, [esi+eax*4]
+ movd mm1, [esi+eax*4]
+
+ lea eax, [edx+ebx]
+ shr eax, 16
+
+ movd mm7, [edi+4]
+ psrld mm3, 24
+
+ packuswb mm3, mm3 // 0000HHVV
+ movd mm5, [esi+eax*4]
+
+ movd mm6, [esi+eax*4]
+ psrld mm5, 24
+
+ paddusw mm3, [SkinBitmap_mmx_one]
+ punpcklbw mm6, [SkinBitmap_mmx_zero]
+
+ packuswb mm5, mm5 // 0000HHVV
+ lea edx, [edx+ebx*2]
+
+ paddusw mm5, [SkinBitmap_mmx_one]
+ punpcklwd mm3, mm3 // HHVVHHVV
+
+ punpcklwd mm5, mm5 // HHVVHHVV
+ add edi, 8
+
+ punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
+
+ punpckldq mm5, mm5 // HHVVHHVV HHVVHHVV
+
+ psubw mm4, mm5
+
+ psubw mm2, mm3
+
+ punpcklbw mm7, [SkinBitmap_mmx_zero]
+ pmullw mm0, mm2
+
+ pmullw mm7, mm4
+ punpcklbw mm1, [SkinBitmap_mmx_zero]
+
+ psubw mm2, mm3
+
+ psrlw mm0, 8
+ psrlw mm7, 8
+ paddw mm0, mm1
+
+ paddw mm7, mm6
+ packuswb mm0, mm0
+
+ movd [edi-8], mm0
+ packuswb mm7, mm7
+
+ movd [edi-4], mm7
+
+ dec ecx
+ jnz _stretchAlpha_Loop2
+ mov dest, edi
+ mov xv, edx
+ }
+#else
+ if (xp>1)
+ {
+ __asm__ volatile (
+ "mov %5, %%ecx\n"
+ "mov %0, %%edi\n"
+ "shr $1, %%ecx\n"
+ "mov %1, %%esi\n"
+ "mov %2, %%edx\n"
+ "mov %7, %%ebx\n"
+ ".align 16\n"
+ "_stretchAlpha_Loop2:\n"
+ "mov %%edx, %%eax\n"
+ "movd (%%edi), %%mm0\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm4\n"
+ "shr $16, %%eax\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm2\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm0\n"
+ "movd (%%esi,%%eax,4), %%mm3\n"
+ "movd (%%esi,%%eax,4), %%mm1\n"
+ "lea (%%edx,%%ebx), %%eax\n"
+ "shr $16, %%eax\n"
+ "movd 4(%%edi), %%mm7\n"
+ "psrld $24, %%mm3\n"
+ "packuswb %%mm3, %%mm3\n"
+ "movd (%%esi,%%eax,4), %%mm5\n"
+ "movd (%%esi,%%eax,4), %%mm6\n"
+ "psrld $24, %%mm5\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm3\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm6\n"
+ "packuswb %%mm5, %%mm5\n"
+ "lea (%%edx,%%ebx,2), %%edx\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm5\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "punpcklwd %%mm5, %%mm5\n"
+ "add $8, %%edi\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "punpckldq %%mm5, %%mm5\n"
+ "psubw %%mm5, %%mm4\n"
+ "psubw %%mm3, %%mm2\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm7\n"
+ "pmullw %%mm2, %%mm0\n"
+ "pmullw %%mm4, %%mm7\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm1\n"
+ "psubw %%mm3, %%mm2\n"
+ "psrlw $8, %%mm0\n"
+ "psrlw $8, %%mm7\n"
+ "paddw %%mm1, %%mm0\n"
+ "paddw %%mm6, %%mm7\n"
+ "packuswb %%mm0, %%mm0\n"
+ "movd %%mm0, -8(%%edi)\n"
+ "packuswb %%mm7, %%mm7\n"
+ "movd %%mm7, -4(%%edi)\n"
+ "dec %%ecx\n"
+ "jnz _stretchAlpha_Loop2\n"
+ "mov %%edi, %0\n"
+ "mov %%edx, %2\n"
+
+ : "=m" (dest), "=m" (psrc), "=m" (xv)
+ : "0" (dest), "1" (psrc), "m" (xp),
+ "2" (xv), "m" (dxv), "m" (alpha)
+ : "%eax", "%ebx", "%ecx", "%edx",
+ "%esi", "%edi" );
+
+ }
+#endif
+
+ if (xp&1) *dest++ = Blenders::BLEND_ADJ2_MMX(*dest, psrc[xv>>16]);
+ }
+};
+
+
+class StretchGlobalChannelMMX {
+public:
+ static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha) {
+#ifdef WIN32
+ if (xp>1) __asm
+ {
+ movd mm5, [alpha]
+ mov ecx, xp
+
+ packuswb mm5, mm5
+ shr ecx, 1
+
+ paddusw mm5, [SkinBitmap_mmx_one]
+
+ punpcklwd mm5, mm5
+ mov edi, dest
+
+ punpckldq mm5, mm5
+ mov esi, psrc
+
+ mov edx, xv
+ mov ebx, dxv
+
+ align 16
+ _stretchAlpha_Loop3:
+ movd mm0, [edi]
+ mov eax, edx
+
+ movd mm7, [edi+4]
+ shr eax, 16
+
+ movd mm1, [esi+eax*4]
+ movd mm3, [esi+eax*4] // VVVVVVVV
+
+ lea eax, [edx+ebx]
+ psrld mm3, 24
+
+ paddusw mm3, [SkinBitmap_mmx_one]
+
+ punpcklwd mm3, mm3
+ shr eax, 16
+
+ punpckldq mm3, mm3
+
+ pmullw mm3, mm5
+
+ movd mm4, [esi+eax*4] // VVVVVVVV
+ movd mm6, [esi+eax*4]
+
+ movq mm2, [SkinBitmap_mmx_revn2]
+ psrld mm4, 24
+
+ paddusw mm4, [SkinBitmap_mmx_one]
+ punpcklbw mm7, [SkinBitmap_mmx_zero]
+
+ punpcklwd mm4, mm4
+ lea edx, [edx+ebx*2]
+
+ punpckldq mm4, mm4
+ add edi, 8
+
+ punpcklbw mm6, [SkinBitmap_mmx_zero]
+ pmullw mm4, mm5
+
+ psrlw mm3, 8
+
+ punpcklbw mm0, [SkinBitmap_mmx_zero]
+
+ punpcklbw mm1, [SkinBitmap_mmx_zero]
+ psubw mm2, mm3
+
+ pmullw mm0, mm2
+ pmullw mm1, mm5
+
+ pmullw mm6, mm5
+ psrlw mm4, 8
+
+ movq mm2, [SkinBitmap_mmx_revn2]
+ paddusw mm0, mm1
+ psubw mm2, mm4
+
+ pmullw mm7, mm2
+ psrlw mm0, 8
+
+ packuswb mm0, mm0
+ paddusw mm7, mm6
+
+ movd [edi-8], mm0
+ psrlw mm7, 8
+
+ packuswb mm7, mm7
+
+ movd [edi-4], mm7
+
+ dec ecx
+ jnz _stretchAlpha_Loop3
+ mov xv, edx
+ mov dest, edi
+ }
+#else
+ if (xp>1)
+ {
+ __asm__ volatile (
+ "movd %8, %%mm5\n"
+ "mov %5, %%ecx\n"
+ "packuswb %%mm5, %%mm5 \n"
+ "shr $1, %%ecx\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm5\n"
+ "punpcklwd %%mm5, %%mm5\n"
+ "mov %0, %%edi\n"
+ "punpckldq %%mm5, %%mm5\n"
+ "mov %1, %%esi\n"
+ "mov %6, %%edx\n"
+ "mov %7, %%ebx\n"
+ ".align 16\n"
+ "_stretchAlpha_Loop3:\n"
+ "movd (%%edi), %%mm0\n"
+ "mov %%edx, %%eax\n"
+ "movd 4(%%edi), %%mm7\n"
+ "shr $16, %%eax\n"
+ "movd (%%esi,%%eax,4), %%mm1\n"
+ "movd (%%esi,%%eax,4), %%mm3\n"
+ "lea (%%edx,%%ebx), %%eax\n"
+ "psrld $24, %%mm3\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm3\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "shr $16, %%eax\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "pmullw %%mm5, %%mm3\n"
+ "movd (%%esi,%%eax,4), %%mm4\n"
+ "movd (%%esi,%%eax,4), %%mm6\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm2\n"
+ "psrld $24, %%mm4\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm4\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm7\n"
+ "punpcklwd %%mm4, %%mm4\n"
+ "lea (%%edx,%%ebx,2), %%edx\n"
+ "punpckldq %%mm4, %%mm4\n"
+ "add $8, %%edi\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm6\n"
+ "pmullw %%mm5, %%mm4\n"
+ "psrlw $8, %%mm3\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm0\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm1\n"
+ "psubw %%mm3, %%mm2\n"
+ "pmullw %%mm2, %%mm0\n"
+ "pmullw %%mm5, %%mm1\n"
+ "pmullw %%mm5, %%mm6\n"
+ "psrlw $8, %%mm4\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm2\n"
+ "paddusw %%mm1, %%mm0\n"
+ "psubw %%mm4, %%mm2\n"
+ "pmullw %%mm2, %%mm7\n"
+ "psrlw $8, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "paddusw %%mm6, %%mm7\n"
+ "movd %%mm0, -8(%%edi)\n"
+ "psrlw $8, %%mm7\n"
+ "packuswb %%mm7, %%mm7\n"
+ "movd %%mm7, -4(%%edi)\n"
+ "dec %%ecx\n"
+ "jnz _stretchAlpha_Loop3\n"
+ "mov %%edi, %0\n"
+ "mov %%edx, %2\n"
+
+ : "=m" (dest), "=m" (psrc), "=m" (xv)
+ : "0" (dest), "1" (psrc), "m" (xp),
+ "m" (xv), "m" (dxv), "m" (alpha)
+ : "%eax", "%ebx", "%ecx", "%edx",
+ "%esi", "%edi" );
+
+ }
+#endif
+
+ if (xp&1) *dest++ = Blenders::BLEND_ADJ3_MMX(*dest, psrc[xv>>16], alpha);
+ }
+};
+#endif
+
+
+class __Stretch : public Stretcher<Stretch> {};
+class __StretchGlobal : public Stretcher<StretchGlobal> {};
+class __StretchChannel : public Stretcher<StretchChannel> {};
+class __StretchGlobalChannel : public Stretcher<StretchGlobalChannel> {};
+
+#ifndef NO_MMX
+class __StretchGlobalMMX : public Stretcher<StretchGlobalMMX> {};
+class __StretchChannelMMX : public Stretcher<StretchChannelMMX> {};
+class __StretchGlobalChannelMMX : public Stretcher<StretchGlobalChannelMMX> {};
+#endif
+
+#ifdef WIN32
+#pragma warning(pop)
+#endif
+
+
+void SkinBitmap::stretchToRectAlpha(ifc_canvas *canvas, RECT *_src, RECT *_dst, int alpha)
+{
+ if (alpha <= 0) return;
+ if (alpha > 255) alpha = 255;
+
+ RECT src=*_src;
+ RECT dst=*_dst;
+
+ if ((src.right-src.left) == (dst.right-dst.left) &&
+ (src.bottom-src.top) == (dst.bottom-dst.top))
+ {
+ blitToRect(canvas,_src,_dst,alpha);
+ return;
+ }
+ //FG> this is a hack, we should support subpixels instead
+ if (src.left == src.right) {
+ if (src.right < getWidth())
+ src.right++;
+ else
+ src.left--;
+ }
+ if (src.top== src.bottom) {
+ if (src.bottom < getHeight())
+ src.bottom++;
+ else
+ src.top--;
+ }
+
+ if (src.left >= src.right || src.top >= src.bottom) return;
+ if (dst.left >= dst.right || dst.top >= dst.bottom) return;
+
+ void *dib=canvas->getBits();
+ HDC hdc=canvas->getHDC();
+ bool usingBlitCanvas = false;
+ BaseCloneCanvas clone(canvas);
+ int cwidth, cheight, pitch;
+
+ int dyv=((src.bottom-src.top)<<16)/(dst.bottom-dst.top);
+ int dxv=((src.right-src.left)<<16)/(dst.right-dst.left);
+ int yv=(src.top<<16);
+ int xstart=(src.left<<16);
+
+ RECT c;
+ int ctype=canvas->getClipBox(&c);
+ if (c.top > dst.top)
+ {
+ yv+=(c.top-dst.top)*dyv;
+ dst.top=c.top;
+ }
+ if (c.left > dst.left)
+ {
+ xstart+=(c.left-dst.left)*dxv;
+ dst.left=c.left;
+ }
+ if (c.bottom < dst.bottom) dst.bottom=c.bottom;
+ if (c.right < dst.right) dst.right=c.right;
+
+ if (dst.right <= dst.left || dst.bottom <= dst.top) return;
+
+ int xs,xe,ys,ye;
+
+#ifdef NO_SIMPLEFASTMODE
+ dib=NULL;
+#endif
+ if (!dib || canvas->getDim(NULL,&cheight,&cwidth) || !cwidth || cheight < 1 || ctype == COMPLEXREGION)
+ {
+ cwidth=dst.right-dst.left;
+ cheight=dst.bottom-dst.top;
+ if (cwidth > cacheWidth || cheight > cacheHeight)
+ {
+ cacheWidth=MAX(cacheWidth, cwidth);
+ cacheHeight=MAX(cacheHeight, cheight);
+ blitToRectCanvas.DestructiveResize(cacheWidth, cacheHeight);
+ }
+
+ dib = blitToRectCanvas.getBits();
+ if ( has_alpha || alpha < 255 )
+ clone.blit( dst.left, dst.top, &blitToRectCanvas, 0, 0, cwidth, cheight );
+
+ xs=0;
+ ys=0;
+ xe=cwidth;
+ ye=cheight;
+ pitch=cacheWidth;
+ usingBlitCanvas=true;
+ }
+ else
+ {
+ xs=dst.left;
+ xe=dst.right;
+ ys=dst.top;
+ ye=dst.bottom;
+ cwidth/=4;
+ pitch=cwidth;
+ }
+
+ // stretch and blend bitmap to dib
+
+ if (xstart < 0) xstart=0;
+
+ if (xs<xe) {
+ if (!has_alpha) { // doesn't have alpha channel
+ if (alpha == 255) { // no global alpha
+ __Stretch::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, pitch, dxv, dyv, alpha);
+ } else { // has global alpha
+#ifndef NO_MMX
+ if (HAS_MMX) {
+ __StretchGlobalMMX::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, pitch, dxv, dyv, alpha);
+ } else
+#endif
+ {
+ __StretchGlobal::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, pitch, dxv, dyv, alpha);
+ }
+ }
+ } else { // has alpha channel
+ // FUCKO: JF> BRENNAN FIX THESE BITCHES :)
+ if (alpha == 255) { // no global alpha
+#ifndef NO_MMX
+ if (HAS_MMX) {
+ __StretchChannelMMX::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, pitch, dxv, dyv, alpha);
+ } else
+#endif
+ {
+ __StretchChannel::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, pitch, dxv, dyv, alpha);
+ }
+ } else { // has global alpha
+#ifndef NO_MMX
+ if (HAS_MMX) {
+ __StretchGlobalChannelMMX::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, pitch, dxv, dyv, alpha);
+ } else
+#endif
+ {
+ __StretchGlobalChannel::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, pitch, dxv, dyv, alpha);
+ }
+ }
+ }
+ }
+
+#ifndef NO_MMX
+ Blenders::BLEND_MMX_END();
+#endif
+ // write bits back to dib.
+
+ if (usingBlitCanvas) {
+ blitToRectCanvas.blit(0, 0, &clone, dst.left, dst.top, cwidth, cheight);
+ }
+}
+
+COLORREF SkinBitmap::getPixel(int x, int y) {
+ ASSERT(bits != NULL);
+ if (x < 0 || y < 0 || x >= getFullWidth()-getX() || y>= getFullHeight()-getY()) return (COLORREF)0;
+ return (COLORREF)(((int*)bits)[x+getX()+(y+getY())*getFullWidth()]);
+}
+
+void *SkinBitmap::getBits() {
+ return bits;
+}
+
+int SkinBitmap::isInvalid() {
+ return last_failed;
+}
+
+void SkinBitmap::setHasAlpha(int ha) {
+ has_alpha=ha;
+}
+
+const wchar_t *SkinBitmap::getBitmapName() {
+ return bitmapname;
+}
+
diff --git a/Src/Wasabi/api/wnd/bitmap.h b/Src/Wasabi/api/wnd/bitmap.h
new file mode 100644
index 00000000..742e8e37
--- /dev/null
+++ b/Src/Wasabi/api/wnd/bitmap.h
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+#include "platform/win32/bitmap.h"
+#elif defined(__APPLE__)
+#include "platform/osx/osx_bitmap_cgimage.h"
+#else
+#error port me
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/blending.cpp b/Src/Wasabi/api/wnd/blending.cpp
new file mode 100644
index 00000000..6bd19397
--- /dev/null
+++ b/Src/Wasabi/api/wnd/blending.cpp
@@ -0,0 +1,56 @@
+#include <precomp.h>
+#include "blending.h"
+#include <bfc/std.h>
+
+#if !defined(WIN32) && !defined(LINUX)
+#error port me!
+#endif
+
+class BlenderInit
+{
+public:
+ BlenderInit() { Blenders::init(); }
+};
+static BlenderInit blender_init;
+
+void Blenders::init()
+{
+ if (!alphatable[127][127])
+ {
+ int i, j;
+ for (j = 0;j < 256;j++)
+ for (i = 0;i < 256;i++)
+ alphatable[i][j] = (i * (j + 1)) >> 8;
+#ifndef NO_MMX
+ DWORD retval1, retval2;
+#ifdef WIN32
+ __try {
+ _asm {
+ mov eax, 1 // set up CPUID to return processor version and features
+ // 0 = vendor string, 1 = version info, 2 = cache info
+ _emit 0x0f // code bytes = 0fh, 0a2h
+ _emit 0xa2
+ mov retval1, eax
+ mov retval2, edx
+ }
+ } __except(EXCEPTION_EXECUTE_HANDLER) { retval1 = retval2 = 0;}
+#else
+ __asm__ volatile ( "movl $1, %%eax\n"
+ ".byte 15, 162\n"
+ "movl %%eax, %0\n"
+ "movl %%edx, %1\n"
+ : "=m" (retval1), "=m" (retval2)
+ : // No inputs...
+ : "%eax", "%edx" );
+#endif
+ mmx_available = retval1 && (retval2 & 0x800000);
+#endif //ndef NO_MMX
+
+ }
+}
+
+#ifndef NO_MMX
+int Blenders::mmx_available = 0;
+#endif
+
+unsigned char Blenders::alphatable[256][256];
diff --git a/Src/Wasabi/api/wnd/blending.h b/Src/Wasabi/api/wnd/blending.h
new file mode 100644
index 00000000..c7148c5b
--- /dev/null
+++ b/Src/Wasabi/api/wnd/blending.h
@@ -0,0 +1,536 @@
+#ifndef _BLENDING_H_
+#define _BLENDING_H_
+
+//#include <bfc/common.h>
+#include <bfc/platform/types.h>
+class Blenders
+{
+public:
+ static void init();
+ static unsigned int inline BLEND_ADJ1(unsigned int a, unsigned int b, int alpha);
+ static unsigned int inline BLEND_ADJ2(unsigned int a, unsigned int b);
+ static unsigned int inline BLEND_ADJ3(unsigned int a, unsigned int b, int alpha);
+ static unsigned int inline BLEND_MUL(unsigned int a, int v);
+ static unsigned int inline BLEND_AVG(unsigned int a, unsigned int b);
+ static unsigned int inline BLEND4(unsigned int *p1, unsigned int w, int xp, int yp);
+
+#ifndef NO_MMX
+ static int inline MMX_AVAILABLE() { return mmx_available; }
+ static unsigned int inline BLEND_ADJ1_MMX(unsigned int a, unsigned int b, int alpha);
+ static unsigned int inline BLEND_ADJ2_MMX(unsigned int a, unsigned int b);
+ static unsigned int inline BLEND_ADJ3_MMX(unsigned int a, unsigned int b, int alpha);
+ static unsigned int inline BLEND_MUL_MMX(unsigned int a, int v);
+ static unsigned int inline BLEND_AVG_MMX(unsigned int a, unsigned int b);
+ static unsigned int inline BLEND4_MMX(unsigned int *p1, unsigned int w, int xp, int yp);
+ static void inline BLEND_MMX_END()
+ {
+#ifdef WIN32
+ if (mmx_available) __asm emms;
+#endif
+#ifdef LINUX
+if (mmx_available) __asm__ volatile ( "emms" : : );
+#endif
+
+ }
+#endif
+
+//private:
+ static uint8_t alphatable[256][256];
+#ifndef NO_MMX
+ static int mmx_available;
+#endif
+};
+
+
+// NON MMX
+
+// average blend of a and b.
+unsigned int inline Blenders::BLEND_AVG(unsigned int a, unsigned int b)
+{
+ return ((a >> 1)&~((1 << 7) | (1 << 15) | (1 << 23))) + ((b >> 1)&~((1 << 7) | (1 << 15) | (1 << 23)));
+}
+
+
+// multiplies 32 bit color A by scalar V (0-255)
+unsigned int inline Blenders::BLEND_MUL(unsigned int a, int v)
+{
+ register int t;
+ t = Blenders::alphatable[a & 0xFF][v];
+ t |= Blenders::alphatable[(a & 0xFF00) >> 8][v] << 8;
+ t |= Blenders::alphatable[(a & 0xFF0000) >> 16][v] << 16;
+ t |= Blenders::alphatable[(a & 0xFF000000) >> 24][v] << 24;
+ return t;
+}
+
+
+// V is scalar (0-255), (1.0-V)*b + V*a
+unsigned int inline Blenders::BLEND_ADJ1(unsigned int a, unsigned int b, int v)
+{
+ register int t;
+ t = Blenders::alphatable[b & 0xFF][0xFF - v] + Blenders::alphatable[a & 0xFF][v];
+ t |= (Blenders::alphatable[(b & 0xFF00) >> 8][0xFF - v] + Blenders::alphatable[(a & 0xFF00) >> 8][v]) << 8;
+ t |= (Blenders::alphatable[(b & 0xFF0000) >> 16][0xFF - v] + Blenders::alphatable[(a & 0xFF0000) >> 16][v]) << 16;
+ t |= (Blenders::alphatable[(b & 0xFF000000) >> 24][0xFF - v] + Blenders::alphatable[(a & 0xFF000000) >> 24][v]) << 24;
+ return t;
+}
+
+// returns a*(1.0-Alpha(b)) + b
+unsigned int inline Blenders::BLEND_ADJ2(unsigned int a, unsigned int b)
+{
+ register int t, z;
+ int v = 0xff - ((b >> 24) & 0xff);
+ t = Blenders::alphatable[a & 0xFF][v] + (b & 0xFF);
+ if (t > 0xFF) t = 0xff;
+ z = (Blenders::alphatable[(a & 0xFF00) >> 8][v] << 8) + (b & 0xFF00);
+ if (z > 0xFF00) z = 0xff00;
+ t |= z;
+ z = (Blenders::alphatable[(a & 0xFF0000) >> 16][v] << 16) + ((b & 0xFF0000));
+ if (z > 0xFF0000) z = 0xff0000;
+ t |= z;
+ z = (Blenders::alphatable[(a & 0xFF000000) >> 24][v]) + ((b & 0xFF000000) >> 24);
+ if (z > 0xFF) z = 0xff;
+ return t | (z << 24);
+}
+
+// returns a*(1-Alpha(b)*W) + b*W, clamped (W is scalar 0-0xff).
+unsigned int inline Blenders::BLEND_ADJ3(unsigned int a, unsigned int b, int w)
+{
+ register int t, z;
+ int v = 0xff - Blenders::alphatable[(b >> 24) & 0xff][w];
+
+ t = Blenders::alphatable[a & 0xFF][v] + Blenders::alphatable[b & 0xFF][w];
+ if (t > 0xFF) t = 0xFF;
+ z = Blenders::alphatable[(a & 0xFF00) >> 8][v] + Blenders::alphatable[(b & 0xFF00) >> 8][w];
+ if (z > 0xFF) z = 0xFF;
+ t |= z << 8;
+ z = Blenders::alphatable[(a & 0xFF0000) >> 16][v] + Blenders::alphatable[(b & 0xFF0000) >> 16][w];
+ if (z > 0xFF) z = 0xFF;
+ t |= z << 16;
+ z = Blenders::alphatable[(a & 0xFF000000) >> 24][v] + Blenders::alphatable[(b & 0xFF000000) >> 24][w];
+ if (z > 0xFF) z = 0xFF;
+ return t | (z << 24);
+}
+
+unsigned int __inline Blenders::BLEND4(unsigned int *p1, unsigned int w, int xp, int yp)
+{
+ register int t;
+ uint8_t a1, a2, a3, a4;
+ xp = (xp >> 8) & 0xff;
+ yp = (yp >> 8) & 0xff;
+ a1 = alphatable[255 - xp][255 - yp];
+ a2 = alphatable[xp][255 - yp];
+ a3 = alphatable[255 - xp][yp];
+ a4 = alphatable[xp][yp];
+ t = alphatable[p1[0] & 0xff][a1] + alphatable[p1[1] & 0xff][a2] + alphatable[p1[w] & 0xff][a3] + alphatable[p1[w + 1] & 0xff][a4];
+ t |= (alphatable[(p1[0] >> 8) & 0xff][a1] + alphatable[(p1[1] >> 8) & 0xff][a2] + alphatable[(p1[w] >> 8) & 0xff][a3] + alphatable[(p1[w + 1] >> 8) & 0xff][a4]) << 8;
+ t |= (alphatable[(p1[0] >> 16) & 0xff][a1] + alphatable[(p1[1] >> 16) & 0xff][a2] + alphatable[(p1[w] >> 16) & 0xff][a3] + alphatable[(p1[w + 1] >> 16) & 0xff][a4]) << 16;
+ t |= (alphatable[(p1[0] >> 24) & 0xff][a1] + alphatable[(p1[1] >> 24) & 0xff][a2] + alphatable[(p1[w] >> 24) & 0xff][a3] + alphatable[(p1[w + 1] >> 24) & 0xff][a4]) << 24;
+ return t;
+}
+
+
+
+
+#ifndef NO_MMX
+
+
+#ifdef WIN32
+#pragma warning( push, 1 )
+#pragma warning(disable: 4799)
+#endif
+
+#ifdef WIN32
+#define MMX_CONST const
+#else
+#define MMX_CONST
+#endif
+
+static unsigned int MMX_CONST Blenders__mmx_revn2[2] = {0x01000100, 0x01000100};
+static unsigned int MMX_CONST Blenders__mmx_zero[2];
+static unsigned int MMX_CONST Blenders__mmx_one[2] = {1, 0};
+
+#undef MMX_CONST
+
+/// MMX
+
+// average blend of a and b.
+unsigned int inline Blenders::BLEND_AVG_MMX(unsigned int a, unsigned int b)
+{
+ return ((a >> 1)&~((1 << 7) | (1 << 15) | (1 << 23))) + ((b >> 1)&~((1 << 7) | (1 << 15) | (1 << 23)));
+}
+
+// multiplies 32 bit color A by scalar V (0-255)
+unsigned int inline Blenders::BLEND_MUL_MMX(unsigned int a, int v)
+{
+#ifdef WIN32
+ __asm
+ {
+ movd mm3, [v] // VVVVVVVV
+
+ movd mm0, [a]
+ packuswb mm3, mm3 // 0000HHVV
+
+ punpcklbw mm0, [Blenders__mmx_zero]
+ punpcklwd mm3, mm3 // HHVVHHVV
+
+ punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
+
+ pmullw mm0, mm3
+
+ psrlw mm0, 8
+
+ packuswb mm0, mm0
+
+ movd eax, mm0
+ }
+#else
+ __asm__ volatile (
+ "movd %0, %%mm3\n"
+ "movd %1, %%mm0\n"
+ "packuswb %%mm3, %%mm3\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm0\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "pmullw %%mm3, %%mm0\n"
+ "psrlw $8, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "movd %%mm0, %%eax\n"
+ :
+ : "m" (v), "m" (a)
+ : "%mm0", "%mm3" );
+#endif
+}
+
+
+// V is scalar (0-255), (1.0-V)*b + V*a
+unsigned int inline Blenders::BLEND_ADJ1_MMX(unsigned int a, unsigned int b, int v)
+{
+#ifdef WIN32
+ __asm
+ {
+ movd mm3, [v] // VVVVVVVV
+
+ movd mm0, [a]
+ packuswb mm3, mm3 // 0000HHVV
+
+ movd mm1, [b]
+ paddusw mm3, [Blenders__mmx_one]
+
+ movq mm4, [Blenders__mmx_revn2]
+ punpcklwd mm3, mm3 // HHVVHHVV
+
+ punpcklbw mm0, [Blenders__mmx_zero]
+ punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
+
+ punpcklbw mm1, [Blenders__mmx_zero]
+ psubw mm4, mm3
+
+ pmullw mm0, mm3
+ pmullw mm1, mm4
+
+ paddw mm0, mm1
+
+ psrlw mm0, 8
+
+ packuswb mm0, mm0
+
+ movd eax, mm0
+ }
+#else
+ __asm__ volatile (
+ "movd %0, %%mm3\n"
+ "movd %1, %%mm0\n"
+ "packuswb %%mm3, %%mm3\n"
+ "movd %2, %%mm1\n"
+ "paddusw (Blenders__mmx_one), %%mm3\n"
+ "movq (Blenders__mmx_revn2), %%mm4\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm0\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm1\n"
+ "psubw %%mm3, %%mm4\n"
+ "pmullw %%mm3, %%mm0\n"
+ "pmullw %%mm4, %%mm1\n"
+ "paddw %%mm1, %%mm0\n"
+ "psrlw $8, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "movd %%mm0, %%eax\n"
+ :
+ : "m" (v), "m" (a), "m" (b)
+ : "%mm0", "%mm1", "%mm3", "%mm4" );
+#endif
+}
+
+// returns a*(1.0-Alpha(b)) + b
+unsigned int inline Blenders::BLEND_ADJ2_MMX(unsigned int a, unsigned int b)
+{
+#ifdef WIN32
+ __asm
+ {
+ movd mm3, [b] // VVVVVVVV
+ movq mm4, [Blenders__mmx_revn2]
+
+ movd mm0, [a]
+ psrld mm3, 24
+
+ movd mm1, [b]
+ paddusw mm3, [Blenders__mmx_one]
+
+ punpcklwd mm3, mm3 // HHVVHHVV
+ punpcklbw mm0, [Blenders__mmx_zero]
+
+ punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
+ punpcklbw mm1, [Blenders__mmx_zero]
+
+ psubw mm4, mm3
+
+ pmullw mm0, mm4
+ // stall
+
+ // stall
+
+ // stall
+
+ psrlw mm0, 8
+ // stall
+
+ paddw mm0, mm1
+ // stall
+
+ packuswb mm0, mm0
+ // stall
+
+ movd eax, mm0
+ }
+#else
+ __asm__ volatile (
+ "movd %1, %%mm3\n"
+ "movq (Blenders__mmx_revn2), %%mm4\n"
+ "movd %0, %%mm0\n"
+ "psrld $24, %%mm3\n"
+ "movd %1, %%mm1\n"
+ "paddusw (Blenders__mmx_one), %%mm3\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm0\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm1\n"
+ "psubw %%mm3, %%mm4\n"
+ "pmullw %%mm4, %%mm0\n"
+ "psrlw $8, %%mm0\n"
+ "paddw %%mm1, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "movd %%mm0, %%eax\n"
+ :
+ : "m" (a), "m" (b)
+ : "%esi", "%mm0", "%mm1", "%mm3", "%mm4" );
+#endif
+}
+
+// returns a*(1-Alpha(b)*W) + b*W, clamped (W is scalar 0-0xff).
+unsigned int inline Blenders::BLEND_ADJ3_MMX(unsigned int a, unsigned int b, int w)
+{
+#ifdef WIN32
+ __asm
+ {
+ movd mm3, [b] // VVVVVVVV
+ movd mm5, [w]
+
+ movd mm0, [a]
+ psrld mm3, 24
+
+ movd mm1, [b]
+ paddusw mm3, [Blenders__mmx_one]
+
+ movq mm4, [Blenders__mmx_revn2]
+ pmullw mm3, mm5
+
+ packuswb mm5, mm5
+ punpcklbw mm0, [Blenders__mmx_zero]
+
+ punpcklwd mm5, mm5
+ punpcklbw mm1, [Blenders__mmx_zero]
+
+ psrlw mm3, 8
+ punpckldq mm5, mm5
+
+ paddusw mm3, [Blenders__mmx_one]
+
+ punpcklwd mm3, mm3 // HHVVHHVV
+
+ punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
+
+
+ psubw mm4, mm3
+
+ pmullw mm0, mm4
+ pmullw mm1, mm5
+
+ paddusw mm0, mm1
+
+ psrlw mm0, 8
+
+ packuswb mm0, mm0
+
+ movd eax, mm0
+ }
+#else
+ __asm__ volatile (
+ "movd %2, %%mm3\n"
+ "movd %0, %%mm5\n"
+ "movd %1, %%mm0\n"
+ "psrld $24, %%mm3\n"
+ "movd %2, %%mm1\n"
+ "paddusw (Blenders__mmx_one), %%mm3\n"
+ "movq (Blenders__mmx_revn2), %%mm4\n"
+ "pmullw %%mm5, %%mm3\n"
+ "packuswb %%mm5, %%mm5 \n"
+ "punpcklbw (Blenders__mmx_zero), %%mm0\n"
+ "punpcklwd %%mm5, %%mm5\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm1\n"
+ "psrlw $8, %%mm3\n"
+ "punpckldq %%mm5, %%mm5\n"
+ "paddusw (Blenders__mmx_one), %%mm3\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "psubw %%mm3, %%mm4\n"
+ "pmullw %%mm4, %%mm0\n"
+ "pmullw %%mm5, %%mm1\n"
+ "paddusw %%mm1, %%mm0\n"
+ "psrlw $8, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "movd %%mm0, %%eax\n"
+
+ :
+ : "m" (w), "m" (a), "m" (b)
+ : "%mm0", "%mm1", "%mm4", "%mm3", "%mm5" );
+#endif
+}
+
+// does bilinear filtering. p1 is upper left pixel, w is width of framebuffer
+// xp and yp's low 16 bits are used for the subpixel positioning.
+unsigned int inline Blenders::BLEND4_MMX(unsigned int *p1, unsigned int w, int xp, int yp)
+{
+#ifdef WIN32
+ __asm
+ {
+ movd mm6, xp
+ mov eax, p1
+
+ movd mm7, yp
+ mov esi, w
+
+ movq mm4, Blenders__mmx_revn2
+ psrlw mm6, 8
+
+ movq mm5, Blenders__mmx_revn2
+ psrlw mm7, 8
+
+ movd mm0, [eax]
+ punpcklwd mm6, mm6
+
+ movd mm1, [eax + 4]
+ punpcklwd mm7, mm7
+
+ movd mm2, [eax + esi*4]
+ punpckldq mm6, mm6
+
+ movd mm3, [eax + esi*4 + 4]
+ punpckldq mm7, mm7
+
+ punpcklbw mm0, [Blenders__mmx_zero]
+ psubw mm4, mm6
+
+ punpcklbw mm1, [Blenders__mmx_zero]
+ pmullw mm0, mm4
+
+ punpcklbw mm2, [Blenders__mmx_zero]
+ pmullw mm1, mm6
+
+ punpcklbw mm3, [Blenders__mmx_zero]
+ psubw mm5, mm7
+
+ pmullw mm2, mm4
+ pmullw mm3, mm6
+
+ paddw mm0, mm1
+ // stall (mm0)
+
+ psrlw mm0, 8
+ // stall (waiting for mm3/mm2)
+
+ paddw mm2, mm3
+ pmullw mm0, mm5
+
+ psrlw mm2, 8
+ // stall (mm2)
+
+ pmullw mm2, mm7
+ // stall
+
+ // stall (mm2)
+
+ paddw mm0, mm2
+ // stall
+
+ psrlw mm0, 8
+ // stall
+
+ packuswb mm0, mm0
+ // stall
+
+ movd eax, mm0
+ }
+#else
+ __asm__ volatile (
+ "movd %2, %%mm6\n"
+ "mov %0, %%eax\n"
+ "movd %3, %%mm7\n"
+ "mov %1, %%esi\n"
+ "movq (Blenders__mmx_revn2), %%mm4\n"
+ "psrlw $8, %%mm6\n"
+ "movq (Blenders__mmx_revn2), %%mm5\n"
+ "psrlw $8, %%mm7\n"
+ "movd (%%eax), %%mm0\n"
+ "punpcklwd %%mm6,%%mm6\n"
+ "movd 4(%%eax), %%mm1\n"
+ "punpcklwd %%mm7,%%mm7\n"
+ "movd (%%eax,%%esi,4), %%mm2\n"
+ "punpckldq %%mm6,%%mm6\n"
+ "movd 4(%%eax,%%esi,4), %%mm3\n"
+ "punpckldq %%mm7,%%mm7\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm0\n"
+ "psubw %%mm6, %%mm4\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm1\n"
+ "pmullw %%mm4, %%mm0\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm2\n"
+ "pmullw %%mm6, %%mm1\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm3\n"
+ "psubw %%mm7, %%mm5\n"
+ "pmullw %%mm4, %%mm2\n"
+ "pmullw %%mm6, %%mm3\n"
+ "paddw %%mm1, %%mm0\n"
+ "psrlw $8, %%mm0\n"
+ "paddw %%mm3, %%mm2\n"
+ "pmullw %%mm5, %%mm0\n"
+ "psrlw $8, %%mm2\n"
+ "pmullw %%mm7, %%mm2\n"
+ "paddw %%mm2, %%mm0\n"
+ "psrlw $8, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "movd %%mm0, %%eax\n"
+
+ :
+ : "m" (p1), "m" (w), "m" (xp), "m" (yp)
+ : "%mm0", "%mm1", "%mm4", "%mm3", "%mm5" );
+
+#endif
+}
+
+#ifdef WIN32
+#pragma warning( pop )
+#endif
+
+#endif // ndef NO_MMX
+
+
+#endif
diff --git a/Src/Wasabi/api/wnd/bltcanvas.h b/Src/Wasabi/api/wnd/bltcanvas.h
new file mode 100644
index 00000000..ee1343ac
--- /dev/null
+++ b/Src/Wasabi/api/wnd/bltcanvas.h
@@ -0,0 +1,5 @@
+#ifdef _WIN32
+#include <api/wnd/platform/win32/bltcanvas.h>
+#elif defined(__APPLE__)
+#include <api/wnd/platform/osx/bltcanvas.h>
+#endif
diff --git a/Src/Wasabi/api/wnd/bucketitem.h b/Src/Wasabi/api/wnd/bucketitem.h
new file mode 100644
index 00000000..4f0455d1
--- /dev/null
+++ b/Src/Wasabi/api/wnd/bucketitem.h
@@ -0,0 +1,76 @@
+#ifndef __BUCKETITEM_H
+#define __BUCKETITEM_H
+
+#include <bfc/common.h>
+#include <api/syscb/callbacks/wndcb.h>
+#include <api/wnd/wndclass/buttwnd.h>
+#include <bfc/depend.h>
+#include <api/wnd/notifmsg.h>
+
+template <class T> class BucketItemT : public T {
+ public:
+ BucketItemT(GUID g=INVALID_GUID, const wchar_t *text=NULL) : guid_target(g), target_txt(text) {
+ setBorders(0);
+ setHInstanceColorGroup(L"Thinger icons");
+ }
+
+ virtual ~BucketItemT() {
+ }
+
+ virtual void setBucketText(const wchar_t *txt) {
+ notifyParent(ChildNotify::COMPONENTBUCKET_SETTEXT, reinterpret_cast<intptr_t>(txt), 0);
+ }
+ virtual void onLeftPush(int x, int y) {
+ T::onLeftPush(x, y);
+ if (guid_target != INVALID_GUID) {
+ RECT r;
+ getClientRect(&r);
+ clientToScreen(&r);
+ int newstatus = WASABI_API_WNDMGR->skinwnd_toggleByGuid(guid_target);
+ setActivatedButton(newstatus);
+ }
+ }
+
+ virtual int onShowWindow(GUID g, const wchar_t *groupid) {
+ if (g == guid_target) setActivatedButton(1);
+ return 1;
+ }
+
+ virtual int onHideWindow(GUID g, const wchar_t *groupid) {
+ if (g == guid_target) setActivatedButton(0);
+ return 1;
+ }
+
+ virtual void onEnterArea() {
+ T::onEnterArea();
+ if (!target_txt.isempty()) setBucketText(target_txt);
+ }
+
+ virtual void onLeaveArea() {
+ T::onLeaveArea();
+ if (!target_txt.isempty()) setBucketText(NULL);
+ }
+
+ void setAutoOpen(GUID g) {
+ guid_target = g;
+ }
+
+ void setAutoText(const wchar_t *txt) {
+ target_txt = txt;
+ }
+
+ private:
+ GUID guid_target;
+ StringW target_txt;
+};
+
+#define BUCKETITEM_PARENT ButtonWnd
+class BucketItem : public BucketItemT<BUCKETITEM_PARENT> {
+ public:
+ BucketItem(GUID g=INVALID_GUID, const wchar_t *text=NULL) : BucketItemT<ButtonWnd> (g, text) {}
+ virtual ~BucketItem() {}
+};
+
+
+#endif // __BUCKETITEM_H
+
diff --git a/Src/Wasabi/api/wnd/canvas.cpp b/Src/Wasabi/api/wnd/canvas.cpp
new file mode 100644
index 00000000..d7123dfa
--- /dev/null
+++ b/Src/Wasabi/api/wnd/canvas.cpp
@@ -0,0 +1,3 @@
+#include "precomp.h"
+
+#error moved to platform/win32!
diff --git a/Src/Wasabi/api/wnd/canvas.h b/Src/Wasabi/api/wnd/canvas.h
new file mode 100644
index 00000000..50e7d8c6
--- /dev/null
+++ b/Src/Wasabi/api/wnd/canvas.h
@@ -0,0 +1,5 @@
+#ifdef _WIN32
+#include <api/wnd/platform/win32/canvas.h>
+#elif defined(__APPLE__)
+#include <api/wnd/platform/osx/canvas.h>
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/contextmenu.cpp b/Src/Wasabi/api/wnd/contextmenu.cpp
new file mode 100644
index 00000000..25a17aeb
--- /dev/null
+++ b/Src/Wasabi/api/wnd/contextmenu.cpp
@@ -0,0 +1,170 @@
+#include <precomp.h>
+
+#include "contextmenu.h"
+#include <api/service/svcs/svc_contextcmd.h>
+#include <bfc/string/StringW.h>
+
+#define DD_CONTEXTMENUENTRY "ContextMenuEntry v1"
+
+class ContextMenuEntry
+{
+public:
+ ContextMenuEntry(DragItem *_item, svc_contextCmd *_svc, int _pos, const wchar_t *txt, int _sortval, int _addorder) :
+ svc(_svc), item(_item), pos(_pos), text(txt), sortval(_sortval), addorder(_addorder) { }
+
+ svc_contextCmd *svc;
+ DragItem *item;
+ int pos;
+ StringW text, submenu_text;
+ int sortval;
+ int addorder;
+};
+
+class ContextMenuEntryCompare
+{
+public:
+ static int compareItem(void *p1, void* p2)
+ {
+ ContextMenuEntry *e1 = static_cast<ContextMenuEntry*>(p1);
+ ContextMenuEntry *e2 = static_cast<ContextMenuEntry*>(p2);
+ int ret = CMP3(e1->sortval, e2->sortval);
+ if (ret == 0) ret = CMP3(e1->addorder, e2->addorder);
+ return ret;
+ }
+};
+
+ContextMenu::ContextMenu(ifc_window *sourceWnd, DragItem *_item, bool autopop, const wchar_t *_menu_path)
+ : PopupMenu(sourceWnd), item(_item), menu_path(_menu_path)
+{
+ populate();
+ if (autopop) popAtMouse();
+}
+
+ContextMenu::ContextMenu(ifc_window *sourceWnd, int x, int y, DragItem *_item, bool autopop, const wchar_t *_menu_path)
+ : PopupMenu(sourceWnd), item(_item), menu_path(_menu_path)
+{
+ populate();
+ if (autopop) popAtXY(x, y);
+}
+
+ContextMenu::ContextMenu(DragItem *_item, const wchar_t *_menu_path)
+ : item(_item), menu_path(_menu_path)
+{
+ populate();
+}
+
+ContextMenu::~ContextMenu()
+{
+ entries.deleteAll();
+
+ // release all services
+ for (int i = 0; i < svclist.getNumItems(); i++)
+ SvcEnum::release(svclist.enumItem(i));
+}
+
+void ContextMenu::addDragItem(DragItem *_item, const wchar_t *_menu_path)
+{
+ menu_path = _menu_path;
+ item = _item;
+ populate();
+}
+
+void ContextMenu::populate()
+{
+ if (item == NULL) return ;
+
+ ContextCmdEnum cce(item, menu_path);
+ svc_contextCmd *svc;
+ int i, j, addorder = 0;
+
+ // make a list of all context cmd services that match the menu path
+ for (i = 0; (svc = cce.getNext()) != NULL; i++)
+ {
+ for (j = 0; ; j++)
+ {
+ const wchar_t *text = svc->getCommand(item, j);
+ if (text == NULL) break;
+ if (!wcscmp(text, L"~~~SEP~~~")) text = NULL; // sorry, magic value
+ ContextMenuEntry *entry = new ContextMenuEntry(item, svc, j, text, svc->getSortVal(item, j), addorder++);
+ entries.addItem(entry);
+ }
+ // save the service * to release later
+ svclist.addItem(svc);
+ }
+
+ // sorting is implicit but just making sure
+ entries.sort();
+
+ PtrList<StringW> submenu_list;
+
+#ifdef WASABI_COMPILE_COMPONENTS
+ GUID prev = INVALID_GUID;
+#endif
+ // populate the menu from the list
+ int n = entries.getNumItems();
+ for (i = 0; i < n; i++)
+ {
+ ContextMenuEntry *entry = entries.enumItem(i);
+ if (entry->text.isempty())
+ {
+ addSeparator();
+ }
+ else
+ {
+ svc_contextCmd *svc = entry->svc;
+#ifdef WASABI_COMPILE_COMPONENTS
+ GUID g = WASABI_API_SVC->service_getOwningComponent(svc);
+ if (g != prev && prev != INVALID_GUID && i < n - 1)
+ addSeparator();
+ prev = g;
+#endif
+ if (!svc->getSubMenu(item, menu_path))
+ {
+ int checked = entry->svc->getChecked(item, entry->pos);
+ int enabled = entry->svc->getEnabled(item, entry->pos);
+ addCommand(entry->text, reinterpret_cast<intptr_t>(entry), checked, !enabled);
+ }
+ else
+ {
+ entry->submenu_text = svc->getSubMenuText(menu_path);
+ if (!entry->submenu_text.isempty())
+ {
+ for (j = 0; j < submenu_list.getNumItems(); j++)
+ if (!WCSICMP(*submenu_list[j], entry->submenu_text)) break;
+ if (j >= submenu_list.getNumItems())
+ {
+ submenu_list.addItem(new StringW(entry->submenu_text));
+ addSubMenuCallback(entry->submenu_text, this, reinterpret_cast<intptr_t>(entry));
+ }
+ }
+ }
+ }
+ }
+ submenu_list.deleteAll();
+}
+
+void ContextMenu::onPostPop(intptr_t result)
+{
+ //if (result == -1 || result == -2 || result == -3) return; //FUCKO need real enums
+ if (result < 0) return ;
+ ASSERT(result != 0xcccccccc);
+ ContextMenuEntry *entry = reinterpret_cast<ContextMenuEntry*>(result);
+ if (entry == NULL) return ;
+ entry->svc->onCommand(entry->item, entry->pos);
+}
+
+PopupMenu *ContextMenu::popupMenuCallback(PopupMenu *parent, intptr_t param)
+{
+ ContextMenuEntry *entry = reinterpret_cast<ContextMenuEntry*>(param);
+ StringW path = menu_path;
+ if (!path.isempty())
+ path.cat(L"/");
+ path.cat(entry->submenu_text);
+ ContextMenu *ret = new ContextMenu(entry->item, path);
+ if (ret->getNumCommands() <= 0)
+ {
+ delete ret;
+ ret = NULL;
+ }
+ return ret;
+}
diff --git a/Src/Wasabi/api/wnd/contextmenu.h b/Src/Wasabi/api/wnd/contextmenu.h
new file mode 100644
index 00000000..61d32b91
--- /dev/null
+++ b/Src/Wasabi/api/wnd/contextmenu.h
@@ -0,0 +1,42 @@
+#ifndef _CONTEXTMENU_H
+#define _CONTEXTMENU_H
+
+#include <api/wnd/popup.h>
+#include <bfc/common.h>
+
+class DragItem;
+class ContextMenuEntry;
+class ContextMenuEntryCompare;
+class svc_contextCmd;
+
+class ContextMenu : private PopupMenu, private PopupMenuCallback
+{
+public:
+ ContextMenu(ifc_window *sourceWnd, DragItem *item, bool autopop=TRUE, const wchar_t *menu_path=NULL);
+ ContextMenu(ifc_window *sourceWnd, int x, int y, DragItem *item, bool autopop=TRUE, const wchar_t *menu_path=NULL);
+ virtual ~ContextMenu();
+
+ void addDragItem(DragItem *item, const wchar_t *menu_path=NULL);
+
+ using PopupMenu::popAtXY;
+ using PopupMenu::popAtMouse;
+ using PopupMenu::addCommand;
+ using PopupMenu::addSeparator;
+ using PopupMenu::getNumCommands;
+
+protected:
+ ContextMenu(DragItem *item, const wchar_t *menu_path);
+
+private:
+ virtual void onPostPop(intptr_t result);
+
+ void populate();
+ virtual PopupMenu *popupMenuCallback(PopupMenu *parent, intptr_t param);
+
+ DragItem *item;
+ StringW menu_path;
+ PtrList<svc_contextCmd> svclist;
+ PtrListQuickSorted<ContextMenuEntry, ContextMenuEntryCompare> entries;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/cursor.cpp b/Src/Wasabi/api/wnd/cursor.cpp
new file mode 100644
index 00000000..6e9618fc
--- /dev/null
+++ b/Src/Wasabi/api/wnd/cursor.cpp
@@ -0,0 +1,48 @@
+#include <precomp.h>
+
+#include "cursor.h"
+
+#define CBCLASS CursorI
+START_DISPATCH;
+ CB(CURSOR_GETOSHANDLE, getOSHandle);
+END_DISPATCH;
+
+#ifdef WASABI_COMPILE_SKIN
+
+SkinCursor::SkinCursor(const wchar_t *elementid) {
+ name = elementid;
+ cursor = NULL;
+ WASABI_API_SYSCB->syscb_registerCallback(static_cast<SkinCallbackI *>(this));
+}
+
+SkinCursor::SkinCursor() {
+ WASABI_API_SYSCB->syscb_registerCallback(static_cast<SkinCallbackI *>(this));
+ cursor = NULL;
+}
+
+SkinCursor::~SkinCursor() {
+ WASABI_API_SYSCB->syscb_deregisterCallback(static_cast<SkinCallbackI *>(this));
+}
+
+OSCURSORHANDLE SkinCursor::getOSHandle() {
+ if (cursor == NULL && !name.isempty()) {
+ cursor = WASABI_API_SKIN->cursor_request(name);
+ }
+ return cursor;
+}
+
+int SkinCursor::skincb_onReset() {
+ reset();
+ return 1;
+}
+
+void SkinCursor::reset() {
+ cursor = NULL;
+}
+
+void SkinCursor::setCursorElementId(const wchar_t *id) {
+ name = id;
+ reset();
+}
+
+#endif
diff --git a/Src/Wasabi/api/wnd/cursor.h b/Src/Wasabi/api/wnd/cursor.h
new file mode 100644
index 00000000..cd5d5ef2
--- /dev/null
+++ b/Src/Wasabi/api/wnd/cursor.h
@@ -0,0 +1,62 @@
+#ifndef __CURSOR_H
+#define __CURSOR_H
+#ifdef _WIN32 // PORT ME
+#include <bfc/dispatch.h>
+#include <api/syscb/callbacks/skincb.h>
+#include <bfc/string/bfcstring.h>
+#include <bfc/string/StringW.h>
+
+class Cursor : public Dispatchable
+{
+ public:
+ OSCURSORHANDLE getOSHandle();
+
+ enum {
+ CURSOR_GETOSHANDLE = 0,
+ };
+
+};
+
+inline OSCURSORHANDLE Cursor::getOSHandle() {
+ return _call(CURSOR_GETOSHANDLE, (OSCURSORHANDLE)NULL);
+}
+
+class CursorI : public Cursor {
+
+ public:
+
+ CursorI() {}
+ virtual ~CursorI() {}
+
+ virtual OSCURSORHANDLE getOSHandle()=0;
+
+ protected:
+
+ RECVS_DISPATCH;
+
+};
+
+#ifdef WASABI_COMPILE_SKIN
+
+class SkinCursor : public CursorI, public SkinCallbackI {
+
+ public:
+
+ SkinCursor();
+ SkinCursor(const wchar_t *elementid);
+ virtual ~SkinCursor();
+
+ virtual void setCursorElementId(const wchar_t *id);
+ virtual int skincb_onReset();
+ virtual OSCURSORHANDLE getOSHandle();
+ virtual void reset();
+
+ private:
+
+ StringW name;
+ OSCURSORHANDLE cursor;
+};
+
+#endif
+#endif
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/cwndtrack.h b/Src/Wasabi/api/wnd/cwndtrack.h
new file mode 100644
index 00000000..fa50f32f
--- /dev/null
+++ b/Src/Wasabi/api/wnd/cwndtrack.h
@@ -0,0 +1,11 @@
+#ifndef _CWNDTRACK_H
+#define _CWNDTRACK_H
+
+#define TOP 1
+#define LEFT 2
+#define RIGHT 4
+#define BOTTOM 8
+#define NOINTERSECT 16
+#define KEEPSIZE 32
+
+#endif
diff --git a/Src/Wasabi/api/wnd/deactivatemgr.cpp b/Src/Wasabi/api/wnd/deactivatemgr.cpp
new file mode 100644
index 00000000..f011db52
--- /dev/null
+++ b/Src/Wasabi/api/wnd/deactivatemgr.cpp
@@ -0,0 +1,55 @@
+#include <precomp.h>
+#include "deactivatemgr.h"
+
+#define FAKE_PTR (ifc_window *)-1
+#define BYPASS_DEACTIVATE_ATOM "BYPASS_DEACTIVATE_MGR"
+
+int AppDeactivationMgr::is_deactivation_allowed(ifc_window *w) {
+#ifdef WIN32
+ if (FindAtomA(BYPASS_DEACTIVATE_ATOM) != NULL) return 1; // so people don't _need_ an api pointer to bypass us, however, if you can please call api->appdeactivation_setbypass
+#else
+ DebugString( "portme -- AppDeactivationMgr::is_deactivation_allowed\n");
+#endif
+ return list.getNumItems() == 0;
+}
+
+void AppDeactivationMgr::push_disallow(ifc_window *w) {
+ if (w == NULL)
+ w = FAKE_PTR;
+ list.addItem(w);
+}
+
+void AppDeactivationMgr::pop_disallow(ifc_window *w) {
+ if (w == NULL)
+ w = FAKE_PTR;
+ if (list.getNumItems() == 0) {
+ return;
+ }
+ while (list.getNumItems()>0) {
+ int p = list.searchItem(w);
+ if (p >= 0)
+ list.removeByPos(p);
+ else break;
+ }
+}
+
+void AppDeactivationMgr::setbypass(int i) {
+#ifdef WIN32
+ if (i) {
+ ATOM a = FindAtomA(BYPASS_DEACTIVATE_ATOM);
+ if (a != NULL) return;
+ AddAtomA(BYPASS_DEACTIVATE_ATOM);
+ } else {
+ ATOM a = FindAtomA(BYPASS_DEACTIVATE_ATOM);
+ if (a != NULL) {
+ DeleteAtom(a);
+ return;
+ }
+ }
+#else
+ DebugString( "portme -- AppDeactivationMgr::setbypass\n" );
+#endif
+}
+
+PtrList<ifc_window> AppDeactivationMgr::list;
+
diff --git a/Src/Wasabi/api/wnd/deactivatemgr.h b/Src/Wasabi/api/wnd/deactivatemgr.h
new file mode 100644
index 00000000..6e1e8c59
--- /dev/null
+++ b/Src/Wasabi/api/wnd/deactivatemgr.h
@@ -0,0 +1,22 @@
+#ifndef __APPDEACTIVATIONMGR_H
+#define __APPDEACTIVATIONMGR_H
+
+#include <bfc/ptrlist.h>
+
+class ifc_window;
+
+class AppDeactivationMgr {
+
+ public:
+
+ static int is_deactivation_allowed(ifc_window *w);
+ static void push_disallow(ifc_window *w);
+ static void pop_disallow(ifc_window *w);
+ static void setbypass(int i);
+
+ private:
+ static PtrList<ifc_window> list;
+
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/di.cpp b/Src/Wasabi/api/wnd/di.cpp
new file mode 100644
index 00000000..d7ff3631
--- /dev/null
+++ b/Src/Wasabi/api/wnd/di.cpp
@@ -0,0 +1,46 @@
+#include "precomp.h"
+#include "drag.h"
+#include <api/wnd/api_window.h>
+
+DI::DI(ifc_window *rw)
+ {
+ if (rw == NULL) di = NULL;
+ else di = rw->getDragInterface();
+ }
+ int DI::dragEnter(ifc_window *sourceWnd)
+ {
+ return di ? di->dragEnter(sourceWnd) : 0;
+ }
+ int DI::dragOver(int x, int y, ifc_window *sourceWnd)
+ {
+ return di ? di->dragOver(x, y, sourceWnd) : 0;
+ }
+ int DI::dragSetSticky(ifc_window *wnd, int left, int right, int up, int down)
+ {
+ return di ? di->dragSetSticky(wnd, left, right, up, down) : 0;
+ }
+ int DI::dragLeave(ifc_window *sourceWnd)
+ {
+ return di ? di->dragLeave(sourceWnd) : 0;
+ }
+ int DI::dragDrop(ifc_window *sourceWnd, int x, int y)
+ {
+ return di ? di->dragDrop(sourceWnd, x, y) : 0;
+ }
+
+ const wchar_t *DI::dragGetSuggestedDropTitle(void)
+ {
+ return di ? di->dragGetSuggestedDropTitle() : NULL;
+ }
+ int DI::dragCheckData(const wchar_t *type, int *nitems )
+ {
+ return di ? di->dragCheckData(type, nitems) : 0;
+ }
+ void *DI::dragGetData(int slot, int itemnum)
+ {
+ return di ? di->dragGetData(slot, itemnum) : NULL;
+ }
+ int DI::dragCheckOption(int option)
+ {
+ return di ? di->dragCheckOption(option) : NULL;
+ }
diff --git a/Src/Wasabi/api/wnd/drag.h b/Src/Wasabi/api/wnd/drag.h
new file mode 100644
index 00000000..7680b55d
--- /dev/null
+++ b/Src/Wasabi/api/wnd/drag.h
@@ -0,0 +1,75 @@
+#ifndef __WASABI_DRAG_H
+#define __WASABI_DRAG_H
+
+class ifc_window;
+
+#include <bfc/wasabi_std.h>
+
+class NOVTABLE DragInterface
+{
+public:
+ // (called on dest) when dragged item enters the winder
+ virtual int dragEnter(ifc_window *sourceWnd) = 0;
+ // (called on dest) during the winder
+ virtual int dragOver(int x, int y, ifc_window *sourceWnd) = 0;
+ // (called on src)
+ virtual int dragSetSticky(ifc_window *wnd, int left, int right, int up, int down) = 0;
+ // (called on dest) when dragged item leaves the winder
+ virtual int dragLeave(ifc_window *sourceWnd) = 0;
+ // (called on dest) here is where we actually drop it
+ virtual int dragDrop(ifc_window *sourceWnd, int x, int y) = 0;
+
+ // must be called from within dragDrop(); (receiver)
+ virtual const wchar_t *dragGetSuggestedDropTitle(void) = 0;
+ // must be called from within your dragEnter, Over, Leave, or Drop
+ // return the slot # if you support this form of the data, -1 otherwise
+ // nitems can be NULL if you're just checking validity
+ virtual int dragCheckData(const wchar_t *type, int *nitems = NULL) = 0;
+ // fetches a specific pointer that was stored
+ virtual void *dragGetData(int slot, int itemnum) = 0;
+ virtual int dragCheckOption(int option) = 0;
+};
+
+class DragInterfaceI : public DragInterface
+{
+public:
+ // (called on dest) when dragged item enters the winder
+ virtual int dragEnter(ifc_window *sourceWnd) { return 0; }
+ // (called on dest) during the winder
+ virtual int dragOver(int x, int y, ifc_window *sourceWnd) { return 0; }
+ // (called on src)
+ virtual int dragSetSticky(ifc_window *wnd, int left, int right, int up, int down) { return 0; }
+ // (called on dest) when dragged item leaves the winder
+ virtual int dragLeave(ifc_window *sourceWnd) { return 0; }
+ // (called on dest) here is where we actually drop it
+ virtual int dragDrop(ifc_window *sourceWnd, int x, int y) { return 0; }
+
+ // must be called from within dragDrop(); (receiver)
+ virtual const wchar_t *dragGetSuggestedDropTitle(void) { return NULL; }
+ // must be called from within your dragEnter, Over, Leave, or Drop
+ // return the slot # if you support this form of the data, -1 otherwise
+ // nitems can be NULL if you're just checking validity
+ virtual int dragCheckData(const wchar_t *type, int *nitems = NULL) { return 0; }
+ // fetches a specific pointer that was stored
+ virtual void *dragGetData(int slot, int itemnum) { return 0; }
+ virtual int dragCheckOption(int option) { return 0; }
+};
+
+class DI
+{
+public:
+ DI(ifc_window *rw);
+ int dragEnter(ifc_window *sourceWnd);
+ int dragOver(int x, int y, ifc_window *sourceWnd);
+ int dragSetSticky(ifc_window *wnd, int left, int right, int up, int down);
+ int dragLeave(ifc_window *sourceWnd);
+ int dragDrop(ifc_window *sourceWnd, int x, int y);
+ const wchar_t *dragGetSuggestedDropTitle(void);
+ int dragCheckData(const wchar_t *type, int *nitems = NULL);
+ void *dragGetData(int slot, int itemnum);
+ int dragCheckOption(int option);
+private:
+ DragInterface *di;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/dragitem.h b/Src/Wasabi/api/wnd/dragitem.h
new file mode 100644
index 00000000..c0236e24
--- /dev/null
+++ b/Src/Wasabi/api/wnd/dragitem.h
@@ -0,0 +1,23 @@
+#ifndef _DRAGITEM_H
+#define _DRAGITEM_H
+
+#include <bfc/dispatch.h>
+
+// has 1 or more pointers to a named data type
+class NOVTABLE DragItem : public Dispatchable
+{
+public:
+ const wchar_t *getDatatype() { return _call(GETDATATYPE, L""); }
+ int getNumData() { return _call(GETNUMDATA, 0); }
+ void *getDatum(int pos = 0) { return _call(GETDATUM, (void*)NULL, pos); }
+
+protected:
+ DISPATCH_CODES
+ {
+ GETDATATYPE = 100,
+ GETNUMDATA = 200,
+ GETDATUM = 300
+ };
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/dragitemi.cpp b/Src/Wasabi/api/wnd/dragitemi.cpp
new file mode 100644
index 00000000..75abde26
--- /dev/null
+++ b/Src/Wasabi/api/wnd/dragitemi.cpp
@@ -0,0 +1,36 @@
+#include <precomp.h>
+#include "dragitemi.h"
+
+DragItemI::DragItemI(const wchar_t *_datatype, void *_data) :
+ datatype(_datatype)
+{
+ if (_data != NULL) addVoidDatum(_data);
+}
+
+void DragItemI::addVoidDatum(void *newdatum)
+{
+ datalist.addItem(reinterpret_cast<char *>(newdatum));
+}
+
+const wchar_t *DragItemI::getDatatype()
+{
+ return datatype;
+};
+
+int DragItemI::getNumData()
+{
+ return datalist.getNumItems();
+}
+
+void *DragItemI::getDatum(int pos)
+{
+ return reinterpret_cast<void *>(datalist[pos]);
+}
+
+#define CBCLASS DragItemI
+START_DISPATCH;
+CB(GETDATATYPE, getDatatype);
+CB(GETNUMDATA, getNumData);
+CB(GETDATUM, getDatum);
+END_DISPATCH;
+#undef CBCLASS
diff --git a/Src/Wasabi/api/wnd/dragitemi.h b/Src/Wasabi/api/wnd/dragitemi.h
new file mode 100644
index 00000000..41198533
--- /dev/null
+++ b/Src/Wasabi/api/wnd/dragitemi.h
@@ -0,0 +1,58 @@
+#ifndef _DRAGITEMI_H
+#define _DRAGITEMI_H
+
+#include "dragitem.h"
+#include <bfc/common.h>
+#include <bfc/string/stringW.h>
+#include <bfc/ptrlist.h>
+
+class DragItemI : public DragItem
+{
+public:
+ DragItemI(const wchar_t *datatype, void *datum = NULL);
+ virtual ~DragItemI() {}
+
+ void addVoidDatum(void *newdatum); // up to you to cast it right
+
+ const wchar_t *getDatatype();
+ int getNumData();
+ void *getDatum(int pos = 0);
+
+private:
+ RECVS_DISPATCH;
+
+ StringW datatype;
+ PtrList<char> datalist;
+};
+
+template <class T>
+class DragItemT : public DragItemI
+{
+public:
+ DragItemT(T *item = NULL) : DragItemI(T::dragitem_getDatatype(), item) {}
+ static inline DragItemI *create(T *item) { return new DragItemT<T>(item); }
+
+ void addDatum(T *newdatum)
+ {
+ addVoidDatum(static_cast<void *>(newdatum));
+ }
+};
+
+template <class T>
+class DragItemCast
+{
+public:
+ DragItemCast(DragItem *_item, int _pos = 0) : item(_item), pos(_pos) {}
+ operator T *()
+ {
+ if (item == NULL || !STREQL(T::dragitem_getDatatype(), item->getDatatype()))
+ return NULL;
+ else
+ return static_cast<T*>(item->getDatum(pos));
+ }
+private:
+ DragItem *item;
+ int pos;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/fakedrag.h b/Src/Wasabi/api/wnd/fakedrag.h
new file mode 100644
index 00000000..4262f8b8
--- /dev/null
+++ b/Src/Wasabi/api/wnd/fakedrag.h
@@ -0,0 +1,12 @@
+#ifndef _FAKEDRAG_H
+#define _FAKEDRAG_H
+
+#include <api/wnd/basewnd.h>
+
+class FakeDragWnd : public BaseWnd {
+public:
+ FakeDragWnd() { dragging = 1; }
+ ~FakeDragWnd() { dragging = 0; }
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/findobjectcb.cpp b/Src/Wasabi/api/wnd/findobjectcb.cpp
new file mode 100644
index 00000000..b7b46ef6
--- /dev/null
+++ b/Src/Wasabi/api/wnd/findobjectcb.cpp
@@ -0,0 +1,8 @@
+#include "precomp.h"
+#include "findobjectcb.h"
+
+#define CBCLASS _FindObjectCallback
+START_DISPATCH;
+ CB(FINDOBJECTCB_MATCHOBJECT, findobjectcb_matchObject);
+END_DISPATCH;
+
diff --git a/Src/Wasabi/api/wnd/findobjectcb.h b/Src/Wasabi/api/wnd/findobjectcb.h
new file mode 100644
index 00000000..b0ce7f90
--- /dev/null
+++ b/Src/Wasabi/api/wnd/findobjectcb.h
@@ -0,0 +1,44 @@
+#ifndef __FINDOBJECTCALLBACK_H
+#define __FINDOBJECTCALLBACK_H
+
+#include <bfc/dispatch.h>
+#include <bfc/common.h>
+
+class ifc_window;
+
+class FindObjectCallback : public Dispatchable {
+
+ public:
+
+ int findobjectcb_matchObject(ifc_window *object);
+
+ enum {
+ FINDOBJECTCB_MATCHOBJECT = 0,
+ };
+
+};
+
+inline int FindObjectCallback::findobjectcb_matchObject(ifc_window *object) {
+ return _call(FINDOBJECTCB_MATCHOBJECT, 0, object);
+}
+
+
+class _FindObjectCallback : public FindObjectCallback {
+ public:
+ virtual int findobjectcb_matchObject(ifc_window *object)=0;
+
+ protected:
+ RECVS_DISPATCH;
+};
+
+
+class FindObjectCallbackI : public _FindObjectCallback {
+ public:
+
+ FindObjectCallbackI() {}
+ virtual ~FindObjectCallbackI() {}
+
+ virtual int findobjectcb_matchObject(ifc_window *object)=0;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/fontdef.h b/Src/Wasabi/api/wnd/fontdef.h
new file mode 100644
index 00000000..add5ca5e
--- /dev/null
+++ b/Src/Wasabi/api/wnd/fontdef.h
@@ -0,0 +1,15 @@
+#ifndef __FONTDEF_H
+#define __FONTDEF_H
+
+#define WA_FONT_TEXTOUT_NORMAL 0
+#define WA_FONT_TEXTOUT_RECT 1
+#define WA_FONT_TEXTOUT_ELLIPSED 2
+#define WA_FONT_TEXTOUT_WRAPPED 3
+#define WA_FONT_TEXTOUT_WRAPPEDPATHED 4
+#define WA_FONT_TEXTOUT_CENTERED 5
+
+#define WA_FONT_GETINFO_WIDTH 0
+#define WA_FONT_GETINFO_HEIGHT 1
+#define WA_FONT_GETINFO_WIDTHHEIGHT 2
+
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/ifc_bitmap.h b/Src/Wasabi/api/wnd/ifc_bitmap.h
new file mode 100644
index 00000000..560d13a4
--- /dev/null
+++ b/Src/Wasabi/api/wnd/ifc_bitmap.h
@@ -0,0 +1,51 @@
+#ifndef NULLSOFT_WASABI_IFC_BITMAP_H
+#define NULLSOFT_WASABI_IFC_BITMAP_H
+
+#include <bfc/dispatch.h>
+#include <bfc/platform/types.h>
+#include <bfc/platform/platform.h>
+
+#warning move this typedef to bfc/platform/platform.h
+#ifdef _WIN32
+typedef HBITMAP OSBITMAPHANDLE;
+#elif defined(__APPLE__)
+typedef CGImageRef OSBITMAPHANDLE;
+#else
+#error port me
+#endif
+
+class ifc_bitmap : public Dispatchable
+{
+protected:
+ ifc_bitmap() {}
+ ~ifc_bitmap() {}
+public:
+ OSBITMAPHANDLE GetBitmap();
+ uint8_t *GetBits();
+ void UpdateBits(uint8_t *bits); // call to signify that you've modified the underlying bits.
+
+ DISPATCH_CODES
+ {
+ IFC_BITMAP_GETBITMAP = 10,
+ IFC_BITMAP_GETBITS = 20,
+ IFC_BITMAP_UPDATEBITS = 30,
+ };
+};
+
+
+inline OSBITMAPHANDLE ifc_bitmap::GetBitmap()
+{
+ return _call(IFC_BITMAP_GETBITMAP, (OSBITMAPHANDLE)0);
+}
+
+inline uint8_t *ifc_bitmap::GetBits()
+{
+ return _call(IFC_BITMAP_GETBITS, (uint8_t *)0);
+}
+
+inline void ifc_bitmap::UpdateBits(uint8_t *bits)
+{
+ _voidcall(IFC_BITMAP_UPDATEBITS, bits);
+}
+
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/keyboard.cpp b/Src/Wasabi/api/wnd/keyboard.cpp
new file mode 100644
index 00000000..8c06d861
--- /dev/null
+++ b/Src/Wasabi/api/wnd/keyboard.cpp
@@ -0,0 +1,570 @@
+#include <precomp.h>
+#include "keyboard.h"
+#include <api/locales/localesmgr.h>
+//#include <api/wac/main.h> // CUT !!!
+#include <api/script/objects/systemobj.h>
+#include <api/wnd/wndtrack.h>
+
+#ifdef WASABI_COMPILE_SCRIPT
+#include <api/script/vcpu.h>
+#endif
+
+#if !defined(WIN32) && !defined(LINUX)
+#error port me
+#endif
+
+Keyboard::vkEntry Keyboard::vkEntries[]={
+#ifdef WIN32
+ //1, "lbutton", // fg> we don't want mouse messages in keyboard events, no.
+ //2, "rbutton",
+ 3, L"cancel",
+ //4, L"mbutton",
+ 8, L"backspace",
+ 9, L"tab",
+ 0xc, L"clear",
+ 0xd, L"return",
+ 0x10, L"shift",
+ 0x11, L"ctrl",
+ 0x12, L"alt",
+ 0x13, L"pause",
+ 0x14, L"capslock",
+ 0x1b, L"esc",
+ 0x20, L"space",
+ 0x21, L"pgup",
+ 0x22, L"pgdn",
+ 0x23, L"end",
+ 0x24, L"home",
+ 0x25, L"left",
+ 0x26, L"up",
+ 0x27, L"right",
+ 0x28, L"down",
+ 0x29, L"select",
+ 0x2b, L"execute",
+ 0x2c, L"prtscr",
+ 0x2d, L"insert",
+ 0x2e, L"del",
+ 0x2f, L"help",
+ 0x5b, L"lwin",
+ 0x5c, L"rwin",
+ 0x5d, L"mwin",
+ 0x60, L"n0",
+ 0x61, L"n1",
+ 0x62, L"n2",
+ 0x63, L"n3",
+ 0x64, L"n4",
+ 0x65, L"n5",
+ 0x66, L"n6",
+ 0x67, L"n7",
+ 0x68, L"n8",
+ 0x69, L"n9",
+ 0x6a, L"numpad_multiply",
+ 0x6b, L"numpad_add",
+ 0x6c, L"separator",
+ 0x6d, L"numpad_substract",
+ 0x6e, L"numpad_point",
+ 0x6f, L"numpad_divide",
+ 0x70, L"f1",
+ 0x71, L"f2",
+ 0x72, L"f3",
+ 0x73, L"f4",
+ 0x74, L"f5",
+ 0x75, L"f6",
+ 0x76, L"f7",
+ 0x77, L"f8",
+ 0x78, L"f9",
+ 0x79, L"f10",
+ 0x7a, L"f11",
+ 0x7b, L"f12",
+ 0x90, L"numlock",
+ 0x91, L"scroll",
+ 0xbb, L"equal",
+ 0xbd, L"minus",
+ 0xbf, L"slash",
+// 0xdb, L"minus", // seems to be the french code? --BU
+ 0xf6, L"attn",
+ 0xfe, L"clear",
+#endif
+#ifdef LINUX
+ {XK_space, L"space"},
+ {XK_Cancel, L"cancel"},
+ {XK_BackSpace, L"backspace"},
+ {XK_Tab, L"tab"},
+ {XK_Clear, L"clear"},
+ {XK_Return, L"return"},
+ {XK_Shift_L, L"shift"},
+ {XK_Shift_R, L"shift"},
+ {XK_Control_L, L"ctrl"},
+ {XK_Control_R, L"ctrl"},
+ {XK_Alt_L, L"alt"},
+ {XK_Alt_R, L"alt"},
+ {XK_Pause, L"pause"},
+ {XK_Caps_Lock, L"capslock"},
+ {XK_Escape, L"esc"},
+ {XK_Page_Up, L"pgup"},
+ {XK_KP_Page_Up, L"pgup"},
+ {XK_Page_Down, L"pgdn"},
+ {XK_KP_Page_Down, L"pgdn"},
+ {XK_End, L"end"},
+ {XK_KP_End, L"end"},
+ {XK_Home, L"home"},
+ {XK_KP_Home, L"home"},
+ {XK_Left, L"left"},
+ {XK_KP_Left, L"left"},
+ {XK_Up, L"up"},
+ {XK_KP_Up, L"up"},
+ {XK_Right, L"right"},
+ {XK_KP_Right, L"right"},
+ {XK_Down, L"down"},
+ {XK_KP_Down, L"down"},
+ {XK_Select, L"select"},
+ {XK_Execute, L"execute"},
+ {XK_Print, L"prtscr"},
+ {XK_Insert, L"insert"},
+ {XK_KP_Insert, L"insert"},
+ {XK_Delete, L"del"},
+ {XK_KP_Delete, L"del"},
+ {XK_Help, L"help"},
+ {XK_KP_0, L"n0"},
+ {XK_KP_1, L"n1"},
+ {XK_KP_2, L"n2"},
+ {XK_KP_3, L"n3"},
+ {XK_KP_4, L"n4"},
+ {XK_KP_5, L"n5"},
+ {XK_KP_6, L"n6"},
+ {XK_KP_7, L"n7"},
+ {XK_KP_8, L"n8"},
+ {XK_KP_9, L"n9"},
+ {XK_KP_Multiply, L"numpad_multiply"},
+ {XK_KP_Add, L"numpad_add"},
+ {XK_KP_Separator, L"separator"},
+ {XK_KP_Subtract, L"numpad_substract"},
+ {XK_KP_Decimal, L"numpad_point"},
+ {XK_KP_Divide, L"numpad_divide"},
+ {XK_F1, L"f1"},
+ {XK_F2, L"f2"},
+ {XK_F3, L"f3"},
+ {XK_F4, L"f4"},
+ {XK_F5, L"f5"},
+ {XK_F6, L"f6"},
+ {XK_F7, L"f7"},
+ {XK_F8, L"f8"},
+ {XK_F9, L"f9"},
+ {XK_F10, L"f10"},
+ {XK_F11, L"f11"},
+ {XK_F12, L"f12"},
+ {XK_Scroll_Lock, L"scroll"},
+#ifdef XK_3270
+ {XK_3270_Attn, L"attn"}, // I don't know what this is...
+#endif
+ {XK_Clear, L"clear"},
+#endif
+};
+//PORTME
+
+wchar_t *Keyboard::getVkName(int vkey)
+{
+ if(vkey>=0x41 && vkey<=0x5A) { // letters
+ static wchar_t key[2];
+ key[0]=vkey+0x20;
+ key[1]=0;
+ return key;
+ }
+ if(vkey>=0x30 && vkey<=0x39) { // numbers
+ static wchar_t key[2];
+ key[0]=vkey;
+ key[1]=0;
+ return key;
+ }
+ for(int i=0;i<(sizeof(vkEntries)/sizeof(vkEntry));i++) {
+ if(vkEntries[i].vk==vkey) return vkEntries[i].trans;
+ }
+#ifdef _DEBUG
+ //DebugString("undefined vk key pressed! (0x%x) :(\n",vkey);
+#endif
+ return NULL;
+}
+
+
+int Keyboard::forwardKbdMessage(ifc_window *from, int msg, int wp, int lp)
+{
+ OSWINDOWHANDLE wnd_to = WASABI_API_WND->main_getRootWnd()->gethWnd();
+ // note to self:
+ // this is necessary for winamp2's TranslateAccelerator call to work, it seems that this function will
+ // use the mouse capture wnd to determine the keyboard focus, oh thank you microsoft, because of you
+ // a script has to use "complete;" to be able to detect shift+ctrl+alt + click on a toggle button,
+ // otherwise pressing a key will throw the capture away, and the button will think the mouse is gone.
+ // this means that we can't be stealth doing that, we have to prevent anybody else getting shift+ctrl+alt
+ // isn't that nice ?
+ // we still avoid doing that if a mouse button is down, this will allow key+drags with capture
+ #ifdef WIN32
+ if (!(GetAsyncKeyState(VK_LBUTTON)&(1 << 31)) && !(GetAsyncKeyState(VK_RBUTTON)&(1 << 31)) && !(GetAsyncKeyState(VK_MBUTTON)&(1 << 31))) {
+ SetCapture(NULL);
+ }
+
+
+ #endif
+
+ #ifdef GET_KBDFORWARD_WND
+ ifc_window *dp = from->getDesktopParent();
+ if (dp) {
+ Layout *l = static_cast<Layout *>(dp->getInterface(layoutGuid));
+ if (l) {
+ Container *c = l->getParentContainer();
+ if (c) {
+ GUID g = c->getDefaultContent();
+ GET_KBDFORWARD_WND(g, wnd_to);
+ }
+ }
+ }
+ #endif
+
+ if (infw) return 0;
+ // if (from && from->gethWnd() == wnd_to) return 1;
+ infw = 1;
+
+ /* MSG winmsg;
+ winmsg.message = msg;
+ winmsg.hwnd = from->gethWnd();
+ winmsg.wParam = wp;
+ winmsg.lParam = lp;*/
+
+ int r = 0;
+ // int r = WASABI_API_APP->app_translateAccelerators(&winmsg);
+ infw = 0;
+
+ return r;
+}
+
+int Keyboard::onForwardOnChar(ifc_window *from, unsigned int c, int kd)
+{
+ if (WASABI_API_WND->isKeyboardLocked()) return 1;
+ return forwardKbdMessage(from, WM_CHAR, (WPARAM)c, (LPARAM)kd);
+}
+
+int MEMCMPC(void *m, char c, int size) {
+ char *p = (char*)m;
+ for (int i=0;i<size;i++) {
+ if (*p != c) return 1;
+ }
+ return 0;
+}
+
+int Keyboard::onForwardOnKeyDown(ifc_window *from, int k, int kd, int nomsg)
+{
+ if (WASABI_API_WND->isKeyboardLocked()) return 1;
+ if (infw) return 0;
+ if (k >= MAX_KEY) return 0;
+ lastwasreset = 0;
+ pressedKeys[k]=1;
+ syncKeyTable();
+ wchar_t s[64]={0,};
+ int first=1;
+#ifdef LINUX
+ for (int i=MAX_KEY-1; i >= 0; i--) {
+#else
+ for (int i=0;i<MAX_KEY;i++) {
+#endif
+ if (pressedKeys[i]) {
+ wchar_t *n = getVkName(i);
+ if (n) {
+ if (!first) wcscat(s, L"+");
+ else first=0;
+ wcscat(s,n);
+ }
+ }
+ }
+ ifc_window *wnd = from;
+ if(s[0]) {
+#ifdef _DEBUG
+ DebugString("keyboard: key pressed: %s\n",s);
+#endif
+#ifdef WASABI_COMPILE_LOCALES
+ const wchar_t *action;
+#endif
+ int found=0;
+ while(wnd!=NULL) {
+ for(int i=0;i<accSecEntries.getNumItems();i++) {
+ AccSec *ase = accSecEntries[i];
+ if(ase->global || ase->wnd==wnd) {
+#ifdef WASABI_COMPILE_LOCALES
+ if (action=LocalesManager::translateAccelerator(ase->name, s))
+ {
+ if(ase->wnd==wnd) found = 1;
+ wnd->onAcceleratorEvent(action);
+#ifdef _DEBUG
+ DebugString("keyboard: accelerator found\n");
+#endif
+ continue;
+ }
+#else
+ wnd->onAcceleratorEvent(s);
+#endif
+ }
+ }
+ wnd=wnd->getParent();
+ }
+ if (found) return 1;
+
+ if (NULL != from)
+ {
+ const wchar_t *accelSec = from->getId();
+ if (accelSec && *accelSec)
+ {
+ #ifdef WASABI_COMPILE_LOCALES
+ if(action=LocalesManager::translateAccelerator(accelSec, s))
+ {
+ int r = 0;
+ #ifdef WASABI_COMPILE_SCRIPT
+ r = SystemObject::onAccelerator(action, accelSec, s);
+ #endif
+ #ifdef WASABI_COMPILE_ACTIONS
+ if (r == 0)
+ {
+ int act=SkinParser::getAction(action);
+ if(act) Main::doAction(act);
+ }
+ #endif
+ #ifdef _DEBUG
+ DebugString("keyboard: accelerator found\n");
+ #endif
+ return 1;
+ }
+ #endif
+ }
+
+ }
+#ifdef WASABI_COMPILE_LOCALES
+ if(action=LocalesManager::translateAccelerator(L"general", s))
+ {
+ int r = 0;
+#ifdef WASABI_COMPILE_SCRIPT
+ r = SystemObject::onAccelerator(action, L"general", s);
+#endif
+#ifdef WASABI_COMPILE_ACTIONS
+ if (r == 0) {
+ int act=SkinParser::getAction(action);
+ if(act) Main::doAction(act);
+ }
+#endif
+#ifdef _DEBUG
+ DebugString("keyboard: accelerator found\n");
+#endif
+ return 1;
+ }
+#endif
+#ifdef _DEBUG
+ DebugString("keyboard: accelerator not found\n");
+#endif
+#ifdef WASABI_COMPILE_SCRIPT
+ DebugStringW(L"keyboard: sending \"%s\" to script\n", s);
+ SystemObject::onKeyDown(s);
+ if (VCPU::getComplete()) {
+ DebugStringW(L"keyboard: %s trapped by script\n", s);
+ return 1;
+ }
+#endif
+ if (pressedKeys[VK_CONTROL] && pressedKeys[VK_TAB])
+ {
+ int next = pressedKeys[VK_SHIFT] ? -1 : 1;
+ HWND w = GetForegroundWindow();
+ if (w == NULL) {
+ WASABI_API_WND->main_getRootWnd()->setFocus();
+ return 1;
+ }
+ ifc_window *cur = windowTracker->rootWndFromHwnd(w); // TODO: API_WNDMGR->
+ if (cur != NULL) {
+ ifc_window *nextwnd = windowTracker->getNextDesktopWindow(cur, next);
+ if (nextwnd) nextwnd->setFocus();
+ return 1;
+ }
+ WASABI_API_WND->main_getRootWnd()->setFocus();
+ return 1;
+ }
+ if (from && pressedKeys[VK_CONTROL] && pressedKeys[VK_F4]) {
+ ifc_window *dp = from->getDesktopParent();
+ if (dp) {
+ Layout *l = static_cast<Layout *>(dp->getInterface(layoutGuid));
+ if (l) {
+ Container *c = l->getParentContainer();
+ if (c) {
+ if (c->isMainContainer())
+ c->setVisible(!c->isVisible());
+ else
+ c->close();
+ return 1;
+ }
+ }
+ }
+ }
+ if (pressedKeys[0x5D]) {
+#if defined(WA3COMPATIBILITY)
+ Main::appContextMenu(from, TRUE, 0);
+#elif defined(WASABI_CUSTOM_CONTEXTMENUS)
+ extern void appContextMenu(ifc_window *wnd);
+ appContextMenu(windowTracker->rootWndFromHwnd(GetForegroundWindow()));
+#endif
+ }
+ if (s[0] && from) return forwardKbdMessage(from, WM_KEYDOWN, (WPARAM)k, (LPARAM)kd);
+ }
+ return 0;
+}
+
+void Keyboard::syncKeyTable() {
+ for (int i=0;i<MAX_KEY;i++) {
+ //if (pressedKeys[i] && !(GetAsyncKeyState(i) & (1 << 31))) pressedKeys[i] = 0;
+ if (pressedKeys[i] && !Std::keyDown(i)) pressedKeys[i] = 0;
+ }
+}
+
+int Keyboard::onForwardOnKeyUp(ifc_window *from, int k, int kd) {
+ if (WASABI_API_WND->isKeyboardLocked()) return 1;
+ if (infw) return 0;
+ if (k >= MAX_KEY) return 0;
+ /*int hadkey = */MEMCMPC(pressedKeys, 0, sizeof(pressedKeys));
+ pressedKeys[k]=0;
+ syncKeyTable();
+ wchar_t s[64]={0,};
+ int first=1;
+#ifdef LINUX
+ for (int i=MAX_KEY-1; i >= 0; i--) {
+#else
+ for (int i=0;i<MAX_KEY;i++) {
+#endif
+ if (pressedKeys[i]) {
+ wchar_t *n = getVkName(i);
+ if (n) {
+ if (!first) wcscat(s, L"+");
+ else first=0;
+ wcscat(s,n);
+ }
+ }
+ }
+ if (!*s) {
+ if (!lastwasreset)
+ {
+ lastwasreset = 1;
+#ifdef WASABI_COMPILE_SCRIPT
+ DebugStringW(L"keyboard: sending \"%s\" to script\n", s);
+ SystemObject::onKeyDown(s);
+ if (VCPU::getComplete()) {
+ DebugStringW(L"keyboard: %s trapped by script\n", s);
+ return 1;
+ }
+#endif
+ }
+ }
+ return forwardKbdMessage(from, WM_KEYUP, (WPARAM)k, (LPARAM)kd);
+}
+
+int Keyboard::onForwardOnSysKeyDown(ifc_window *from, int k, int kd) {
+ if (WASABI_API_WND->isKeyboardLocked()) return 1;
+ if (infw) return 0;
+ if(kd&(1<<29)) pressedKeys[0x12]=1;
+ int r = onForwardOnKeyDown(from, k, 1);
+ if (r == 0) {
+ if (from && forwardKbdMessage(from, WM_SYSKEYDOWN, (WPARAM)k, (LPARAM)kd)) return 1;
+ }
+ return r;
+}
+
+int Keyboard::onForwardOnSysKeyUp(ifc_window *from, int k, int kd)
+{
+ if (WASABI_API_WND->isKeyboardLocked()) return 1;
+ if (infw) return 0;
+ if(kd&(1<<29)) pressedKeys[0x12]=0;
+ pressedKeys[k]=0;
+ int r = onForwardOnKeyUp(from, k, 1);
+ if (r == 0) {
+ if (forwardKbdMessage(from, WM_SYSKEYUP, (WPARAM)k, (WPARAM)kd)) return 1;
+ }
+ return r;
+}
+
+
+int Keyboard::onForwardOnKillFocus() {
+ // FG> I don't think this is necessary anymore because onkeydown always resyncs the pressedKeys table
+ // and supressing this allows scripts to trap ctrl/alt/shit + clicks (otherwise the click would reset
+ // the modifiers by way of an automatic focus)
+ //MEMSET(pressedKeys,0,sizeof(pressedKeys));
+ return 0;
+}
+
+void Keyboard::registerAcceleratorSection(const wchar_t *name, ifc_window *wnd, int global)
+{
+ accSecEntries.addItem(new AccSec(name,wnd,global));
+ viewer.viewItem(wnd);
+}
+
+int Keyboard::interceptOnChar(unsigned int c) {
+ if (hookers.getNumItems() > 0) {
+ return hookers.getLast()->onChar(c);
+ }
+ return 0;
+}
+
+int Keyboard::interceptOnKeyDown(int k){
+ if (hookers.getNumItems() > 0) {
+ return hookers.getLast()->onKeyDown(k);
+ }
+ return 0;
+}
+
+int Keyboard::interceptOnKeyUp(int k){
+ if (hookers.getNumItems() > 0) {
+ return hookers.getLast()->onKeyUp(k);
+ }
+ return 0;
+}
+
+int Keyboard::interceptOnSysKeyDown(int k, int kd){
+ if (hookers.getNumItems() > 0) {
+ return hookers.getLast()->onSysKeyDown(k, kd);
+ }
+ return 0;
+}
+
+int Keyboard::interceptOnSysKeyUp(int k, int kd){
+ if (hookers.getNumItems() > 0) {
+ return hookers.getLast()->onSysKeyUp(k, kd);
+ }
+ return 0;
+}
+
+void Keyboard::hookKeyboard(ifc_window *hooker) {
+ hookers.addItem(hooker);
+ DebugString("hookKeyboard = %d\n", hookers.getNumItems());
+}
+
+void Keyboard::unhookKeyboard(ifc_window *hooker) {
+ hookers.removeItem(hooker);
+ DebugString("unhookKeyboard = %d\n", hookers.getNumItems());
+}
+
+void Keyboard::reset() {
+ if (lastwasreset) return;
+ DebugString("keyboard reset\n");
+ MEMZERO(pressedKeys, sizeof(pressedKeys));
+ if (!lastwasreset) {
+ lastwasreset = 1;
+#ifdef WASABI_COMPILE_SCRIPT
+ DebugString("keyboard: sending \"\" to script\n");
+ SystemObject::onKeyDown(L"");
+#endif
+ }
+}
+
+int AccSecViewer::viewer_onItemDeleted(ifc_window *item) {
+ for(int i=0;i<Keyboard::accSecEntries.getNumItems();i++)
+ if(Keyboard::accSecEntries[i]->wnd==item) {
+ Keyboard::accSecEntries.removeByPos(i);
+ i--;
+ }
+ return 1;
+}
+
+wchar_t Keyboard::pressedKeys[MAX_KEY]={0,};
+PtrList<AccSec> Keyboard::accSecEntries;
+AccSecViewer Keyboard::viewer;
+PtrList<ifc_window> Keyboard::hookers;
+int Keyboard::infw = 0;
+int Keyboard::lastwasreset = 0;
diff --git a/Src/Wasabi/api/wnd/keyboard.h b/Src/Wasabi/api/wnd/keyboard.h
new file mode 100644
index 00000000..1aa4034c
--- /dev/null
+++ b/Src/Wasabi/api/wnd/keyboard.h
@@ -0,0 +1,77 @@
+#ifndef __KEYBOARD_H
+#define __KEYBOARD_H
+
+#include <bfc/string/StringW.h>
+#include <bfc/ptrlist.h>
+#include <bfc/depview.h>
+
+#ifdef WIN32
+#define MAX_KEY 256
+#else
+#define MAX_KEY 65536
+#endif
+
+class ifc_window;
+
+class AccSec {
+public:
+ AccSec(const wchar_t *pname, ifc_window *pwnd, int pglobal=0) : name(pname), wnd(pwnd), global(pglobal) { }
+ StringW name;
+ ifc_window *wnd;
+ int global;
+};
+
+#include <api/wnd/api_window.h>
+class AccSecViewer : public DependentViewerTPtr<ifc_window> {
+public:
+ void viewItem(ifc_window *i) { viewer_addViewItem(i); }
+ virtual int viewer_onItemDeleted(ifc_window *item);
+};
+
+class Keyboard {
+
+public:
+
+ static int onForwardOnChar(ifc_window *from, unsigned int c, int kd);
+ static int onForwardOnKeyDown(ifc_window *from, int k, int kd, int nomsg=0);
+ static int onForwardOnKeyUp(ifc_window *from, int k, int kd);
+ static int onForwardOnSysKeyDown(ifc_window *from, int k, int kd);
+ static int onForwardOnSysKeyUp(ifc_window *from, int k, int kd);
+ static int onForwardOnKillFocus();
+
+ static int interceptOnChar(unsigned int c);
+ static int interceptOnKeyDown(int k);
+ static int interceptOnKeyUp(int k);
+ static int interceptOnSysKeyDown(int k, int kd);
+ static int interceptOnSysKeyUp(int k, int kd);
+
+ static void hookKeyboard(ifc_window *hooker);
+ static void unhookKeyboard(ifc_window *hooker);
+
+ static void reset();
+
+ static void registerAcceleratorSection(const wchar_t *name, ifc_window *wnd, int pglobal);
+
+ static PtrList<AccSec> accSecEntries;
+
+private:
+ static int forwardKbdMessage(ifc_window *from, int msg, int wp, int lp);
+ static wchar_t *getVkName(int vkey);
+ static void syncKeyTable();
+
+ // special keys
+ typedef struct {
+ int vk;
+ wchar_t *trans;
+ } vkEntry;
+ static vkEntry vkEntries[];
+
+ static wchar_t pressedKeys[MAX_KEY];
+
+ static AccSecViewer viewer;
+ static PtrList<ifc_window> hookers;
+ static int infw;
+ static int lastwasreset;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/minibrowser.cpp b/Src/Wasabi/api/wnd/minibrowser.cpp
new file mode 100644
index 00000000..fdcd7f85
--- /dev/null
+++ b/Src/Wasabi/api/wnd/minibrowser.cpp
@@ -0,0 +1,28 @@
+#include "precomp.h"
+#include "minibrowser.h"
+
+#define CBCLASS MiniBrowserCallbackI
+START_DISPATCH;
+ CB(MINIBROWSER_ONBEFORENAVIGATE, minibrowsercb_onBeforeNavigate);
+ VCB(MINIBROWSER_ONDOCUMENTCOMPLETE, minibrowsercb_onDocumentComplete);
+END_DISPATCH;
+#undef CBCLASS
+
+#define CBCLASS MiniBrowserI
+START_DISPATCH;
+ CB(MINIBROWSER_GETROOTWND, minibrowser_getRootWnd);
+ CB(MINIBROWSER_NAVIGATEURL, minibrowser_navigateUrl);
+ CB(MINIBROWSER_BACK, minibrowser_back);
+ CB(MINIBROWSER_FORWARD, minibrowser_forward);
+ CB(MINIBROWSER_HOME, minibrowser_home);
+ CB(MINIBROWSER_REFRESH, minibrowser_refresh);
+ CB(MINIBROWSER_STOP, minibrowser_stop);
+ VCB(MINIBROWSER_SETTARGETNAME, minibrowser_setTargetName);
+ CB(MINIBROWSER_GETTARGETNAME, minibrowser_getTargetName);
+ CB(MINIBROWSER_GETCURRENTURL, minibrowser_getCurrentUrl);
+ VCB(MINIBROWSER_ADDCB, minibrowser_addCB);
+ VCB(MINIBROWSER_SETHOME, minibrowser_setHome);
+ VCB(MINIBROWSER_SETSCROLLFLAG, minibrowser_setScrollbarsFlag);
+END_DISPATCH;
+#undef CBCLASS
+
diff --git a/Src/Wasabi/api/wnd/minibrowser.h b/Src/Wasabi/api/wnd/minibrowser.h
new file mode 100644
index 00000000..b96b1577
--- /dev/null
+++ b/Src/Wasabi/api/wnd/minibrowser.h
@@ -0,0 +1 @@
+#include <api/skin/widgets/mb/minibrowser.h>
diff --git a/Src/Wasabi/api/wnd/notifmsg.h b/Src/Wasabi/api/wnd/notifmsg.h
new file mode 100644
index 00000000..be1cb05b
--- /dev/null
+++ b/Src/Wasabi/api/wnd/notifmsg.h
@@ -0,0 +1,109 @@
+#ifndef _NOTIFMSG_H
+#define _NOTIFMSG_H
+
+//!## Messages for BaseWnd::childNotify
+
+// these are in their own header file to keep from having to muck with
+// basewnd.h all the time to add a new global message
+
+namespace ChildNotify {
+enum {
+//
+// Common messages any control may need to send
+ NOP = 0, // not used. do not use.
+
+ // When child window is in its destructor
+ DELETED = 100, // no params
+
+ // Focus stuff
+ GOTFOCUS = 200, // no params
+ KILLFOCUS = 210, // no params
+ NAMECHANGED = 220, // no params
+
+ // for transient child windows
+ RETURN_CODE = 300, // param1 = the code
+ // NOTE: Currently only used by editwnd.cpp, but open for custom use by developers
+
+ // child wants parent to hide/show it
+ HIDEYHIDEY = 400, // no params
+ UNHIDEYHIDEY = 410, // no params
+
+// class-specific stuff
+
+ // ButtonWnd, buttwnd.h
+ BUTTON_LEFTPUSH = 10000, // no params
+ BUTTON_RIGHTPUSH = 10010, // no params
+ BUTTON_LEFTDOUBLECLICK = 10020, // no params
+ BUTTON_RIGHTDOUBLECLICK = 10030, // no params
+
+ CLICKWND_LEFTDOWN = 10100, // x/y
+ CLICKWND_LEFTUP = 10101, // x/y
+ CLICKWND_RIGHTDOWN = 10102, // x/y
+ CLICKWND_RIGHTUP = 10103, // x/y
+
+ // EditWnd, editwnd.h
+ EDITWND_DATA_MODIFIED = 11000, // user edit - no params
+ EDITWND_DATA_MODIFIED_ONIDLE = 11005, // user edit - no params (on idle)
+ EDITWND_CANCEL_PRESSED = 11010, // esc pressed - no params
+ EDITWND_ENTER_PRESSED = 11020, // enter pressed - no params
+ EDITWND_KEY_PRESSED = 11030, // any key pressed - param1 = the key
+
+ // DropList, droplist.h
+ DROPLIST_SEL_CHANGED = 12000, // param1 = new pos
+
+ // ListWnd, listwnd.h
+ LISTWND_SELCHANGED = 13000, // sent on any change - no params
+ LISTWND_ITEMSELCHANGED = 13010, // sent for each item - param1 = the item index, param2 = its selected state
+ LISTWND_DBLCLK = 13100, // param1 = the item index
+ LISTWND_POPUPMENU = 13200, // param1 = the x coord, param2 = the y coord
+
+ // FrameWnd, framewnd.h
+ FRAMEWND_QUERY_SLIDE_MODE = 14000, // no params - return slide mode
+ FRAMEWND_SET_SLIDE_MODE = 14010, // param1 = the new slide mode
+ FRAMEWND_WINDOWSHADE_CAPABLE = 14020, // no params - return width of shade
+ FRAMEWND_WINDOWSHADE_ENABLE = 14030, // param1 = new enabled state
+// Cut? this is unused.
+// FRAMEWND_WINDOWSHADE_DISABLE = 14040,
+ FRAMEWND_SETTITLEWIDTH = 14050, // param1 = the pullbar position
+
+ // ServiceWnd, servicewnd.h
+ SVCWND_LBUTTONDOWN = 15000, // param1 = the x coord, param2 = the y coord
+ SVCWND_RBUTTONDOWN = 15010, // param1 = the x coord, param2 = the y coord
+ SVCWND_LBUTTONUP = 15020, // param1 = the x coord, param2 = the y coord
+ SVCWND_RBUTTONUP = 15030, // param1 = the x coord, param2 = the y coord
+ SVCWND_LBUTTONDBLCLK = 15040, // param1 = the x coord, param2 = the y coord
+ SVCWND_RBUTTONDBLCLK = 15050, // param1 = the x coord, param2 = the y coord
+ SVCWND_MOUSEMOVE = 15060, // param1 = the x coord, param2 = the y coord
+
+ // Slider, slider.h
+ SLIDER_INTERIM_POSITION = 16000, // param1 = the slider position
+ SLIDER_FINAL_POSITION = 16010, // param1 = the slider position
+
+ // BucketItem, bucketitem.h
+ COMPONENTBUCKET_SETTEXT = 17000, // param1 = pointer to the text
+
+ // CheckWnd, checkwnd.h
+ CHECKWND_CLICK = 18000, // param1 = the new checkstate
+
+ // ScrollBar, scrollbar.h
+ SCROLLBAR_SETPOSITION = 19000, // param1 = the new position
+ SCROLLBAR_SETFINALPOSITION = 19010, // called when scrolling is completed - no params
+
+ // RadioGroup, radiogroup.h
+ RADIOGROUP_STATECHANGE = 20000, // param1 = the object selected, param2 = the object deselected
+
+ // grouptogglebutton
+ GROUPCLICKTGBUTTON_TOGGLE = 20100, // when the button is toggled, param1 = status
+ GROUPCLICKTGBUTTON_CLICKED = 20101, // when the button is clicked regardless of toggling
+
+ // misc
+ AUTOWHCHANGED = 20200, // sent by an object whose resource's auto w/h has changed (ie Text changed text, Layer changed image, etc)
+ GROUPRELOAD = 20300, // sent by abstractwndholder when its content is reloaded
+
+ // popup
+ POPUP_SUBMENUCLOSE = 21000, // sent by a submenu to its parent popup menu when it should close (esc/left key pressed)
+};
+
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/paintcb.cpp b/Src/Wasabi/api/wnd/paintcb.cpp
new file mode 100644
index 00000000..974ba998
--- /dev/null
+++ b/Src/Wasabi/api/wnd/paintcb.cpp
@@ -0,0 +1,52 @@
+#include "precomp.h"
+#include "paintcb.h"
+#include "api_window.h"
+
+#define CBCLASS PaintCallbackInfoI
+START_DISPATCH;
+ CB(PAINTCBINFO_GETCANVAS, getCanvas);
+ CB(PAINTCBINFO_GETREGION, getRegion);
+END_DISPATCH;
+
+PaintCallback::PaintCallback(ifc_window *w) {
+ monitorWindow(w);
+}
+
+PaintCallback::~PaintCallback() {
+ if (wnd != NULL) viewer_delViewItem(wnd);
+}
+
+void PaintCallback::monitorWindow(ifc_window *w) {
+ if (wnd != NULL) {
+ viewer_delViewItem(wnd);
+ wnd = NULL;
+ }
+ if (w != NULL) {
+ viewer_addViewItem(w);
+ wnd = w;
+ }
+}
+
+int PaintCallback::viewer_onItemDeleted(ifc_window *item) {
+ ASSERT(item == wnd);//jic
+ onWindowDeleted(wnd);
+ wnd = NULL;
+ return 1;
+}
+
+int PaintCallback::viewer_onEvent(ifc_window *item, int event, intptr_t param, void *ptr, size_t ptrlen) {
+ PaintCallbackInfo *info = reinterpret_cast<PaintCallbackInfo *>(ptr);
+ switch (event) {
+ case ifc_window::Event_ONPAINT:
+ if (param == BEFOREPAINT)
+ onBeforePaint(info);
+ else
+ onAfterPaint(info);
+ break;
+ case ifc_window::Event_ONINVALIDATE:
+ onInvalidation(info);
+ break;
+ }
+ return 1;
+}
+
diff --git a/Src/Wasabi/api/wnd/paintcb.h b/Src/Wasabi/api/wnd/paintcb.h
new file mode 100644
index 00000000..acb6fc6e
--- /dev/null
+++ b/Src/Wasabi/api/wnd/paintcb.h
@@ -0,0 +1,73 @@
+#ifndef _PAINTCB_H
+#define _PAINTCB_H
+
+#include <bfc/depview.h>
+#include <bfc/dispatch.h>
+#include <api/wnd/api_window.h>
+
+class Canvas;
+class api_region;
+
+class PaintCallbackInfo : public Dispatchable {
+ public:
+ Canvas *getCanvas();
+ api_region *getRegion();
+
+ enum {
+ PAINTCBINFO_GETCANVAS = 10,
+ PAINTCBINFO_GETREGION = 20,
+ };
+
+};
+
+inline Canvas *PaintCallbackInfo::getCanvas() {
+ return _call(PAINTCBINFO_GETCANVAS, (Canvas *)NULL);
+}
+
+inline api_region *PaintCallbackInfo::getRegion() {
+ return _call(PAINTCBINFO_GETREGION, (api_region *)NULL);
+}
+
+class PaintCallbackInfoI : public PaintCallbackInfo {
+ public:
+ PaintCallbackInfoI(Canvas *_canvas, api_region *_region) : canvas(_canvas), region(_region) {}
+ virtual ~PaintCallbackInfoI() {}
+
+ virtual Canvas *getCanvas() { return canvas; }
+ virtual api_region *getRegion() { return region; }
+
+ private:
+
+ Canvas *canvas;
+ api_region *region;
+
+ protected:
+ RECVS_DISPATCH;
+};
+
+class PaintCallback : DependentViewerTPtr<ifc_window> {
+public:
+ PaintCallback() { wnd = NULL; };
+ PaintCallback(ifc_window *w);
+ virtual ~PaintCallback();
+
+ virtual void monitorWindow(ifc_window *w);
+ virtual int viewer_onEvent(ifc_window *item, int event, intptr_t param, void *ptr, size_t ptrlen);
+ virtual int viewer_onItemDeleted(ifc_window *item);
+
+ // override those
+ virtual void onBeforePaint(PaintCallbackInfo *info) { }
+ virtual void onAfterPaint(PaintCallbackInfo *info) { }
+ virtual void onWindowDeleted(ifc_window *w)=0; // warning, pointer invalid
+ virtual void onInvalidation(PaintCallbackInfo *info) { }
+
+ enum {
+ BEFOREPAINT = 10,
+ AFTERPAINT = 20,
+ };
+
+private:
+ ifc_window *wnd;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/paintset.cpp b/Src/Wasabi/api/wnd/paintset.cpp
new file mode 100644
index 00000000..b6ea8343
--- /dev/null
+++ b/Src/Wasabi/api/wnd/paintset.cpp
@@ -0,0 +1,603 @@
+#include <precomp.h>
+#include <wasabicfg.h>
+#include "paintset.h"
+
+using namespace Paintset;
+#include <tataki/canvas/bltcanvas.h>
+
+#include <tataki/bitmap/autobitmap.h>
+#include <tataki/color/skinclr.h>
+#include <api/font/font.h>
+#include <api/service/svcs/svc_font.h>
+
+#ifndef WASABI_COMPILE_IMGLDR
+#error This module requires image loading capabilities (WASABI_COMPILE_IMGLDR)
+#endif
+
+#define TITLE_PADDING 4 // SKINME
+
+#ifdef WASABI_COMPILE_SKIN
+static SkinColor title_fg(L"wasabi.component.title.foreground");
+static SkinColor title_border(L"wasabi.component.title.border");
+#endif
+
+class NOVTABLE PaintSet
+{
+protected:
+ PaintSet()
+ {}
+public:
+ virtual ~PaintSet()
+ {}
+
+ virtual void render(ifc_canvas *canvas, const RECT *r, int alpha) = 0;
+};
+
+static PaintSet *sets[NUM_PAINTSETS];
+
+class PaintSetButtonDisabled : public PaintSet
+{
+public:
+ PaintSetButtonDisabled();
+
+ virtual void render(ifc_canvas *canvas, const RECT *r, int alpha);
+
+private:
+ AutoSkinBitmap mid;
+};
+
+PaintSetButtonDisabled::PaintSetButtonDisabled()
+{
+ mid = L"wasabi.label.middle";
+}
+
+void PaintSetButtonDisabled::render(ifc_canvas *canvasbase, const RECT *_r, int alpha)
+{
+ BaseCloneCanvas canvas;
+ int ret = canvas.clone(canvasbase);
+ ASSERT(ret);
+
+ RECT r = *_r;
+
+ mid.stretchToRectAlpha(&canvas, &r, alpha);
+}
+
+//----
+
+class PaintSetButtonUp : public PaintSet
+{
+public:
+ PaintSetButtonUp();
+
+ virtual void render(ifc_canvas *canvas, const RECT *r, int alpha);
+
+protected:
+ AutoSkinBitmap ul, u, ur;
+ AutoSkinBitmap l, mid, right;
+ AutoSkinBitmap ll, bot, lr;
+};
+
+PaintSetButtonUp::PaintSetButtonUp()
+{
+ ul = L"wasabi.button.top.left";
+ u = L"wasabi.button.top";
+ ur = L"wasabi.button.top.right";
+
+ l = L"wasabi.button.left";
+ mid = L"wasabi.button.middle";
+ right = L"wasabi.button.right";
+
+ ll = L"wasabi.button.bottom.left";
+ bot = L"wasabi.button.bottom";
+ lr = L"wasabi.button.bottom.right";
+}
+
+void PaintSetButtonUp::render(ifc_canvas *canvasbase, const RECT *_r, int alpha)
+{
+ BaseCloneCanvas canvas;
+ int ret = canvas.clone(canvasbase);
+ if (!ret) return;
+
+ RECT r = *_r, br;
+
+ // upper left
+ br.left = r.left;
+ br.top = r.top;
+ br.right = r.left + ul.getWidth();
+ br.bottom = r.top + ul.getHeight();
+ ul.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // top
+ br.left = br.right;
+ br.right = r.right - ur.getWidth();
+ u.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // upper right
+ br.left = br.right;
+ br.right = r.right;
+ ur.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // left
+ br.left = r.left;
+ br.right = r.left + l.getWidth();
+ br.top = r.top + ul.getHeight();
+ br.bottom = r.bottom - ll.getHeight();
+ l.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // middle
+ br.top = r.top + ul.getHeight();
+ br.bottom = r.bottom - ll.getHeight();
+ br.left = r.left + ul.getWidth();
+ br.right = r.right - ur.getWidth();
+ mid.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // right
+ br.left = r.right - right.getWidth();
+ br.right = r.right;
+ br.top = r.top + ur.getHeight();
+ br.bottom = r.bottom - lr.getHeight();
+ right.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // lower left
+ br.left = r.left;
+ br.right = r.left + ll.getWidth();
+ br.top = r.bottom - ll.getHeight();
+ br.bottom = r.bottom;
+ ll.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // bot
+ br.left = r.left + ll.getWidth();
+ br.right = r.right - lr.getWidth();
+ br.top = r.bottom - bot.getHeight();
+ br.bottom = r.bottom;
+ bot.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // lower right
+ br.left = r.right - lr.getWidth();
+ br.right = r.right;
+ br.top = r.bottom - lr.getHeight();
+ br.bottom = r.bottom;
+ lr.stretchToRectAlpha(&canvas, &br, alpha);
+}
+
+class PaintSetLabel : public PaintSetButtonUp
+{
+public:
+ PaintSetLabel()
+ {
+ ul = L"wasabi.label.top.left";
+ u = L"wasabi.label.top";
+ ur = L"wasabi.label.top.right";
+
+ l = L"wasabi.label.left";
+ mid = L"wasabi.label.middle";
+ right = L"wasabi.label.right";
+
+ ll = L"wasabi.label.bottom.left";
+ bot = L"wasabi.label.bottom";
+ lr = L"wasabi.label.bottom.right";
+ }
+};
+
+//----
+
+class PaintSetButtonDown : public PaintSet
+{
+public:
+ PaintSetButtonDown();
+
+ virtual void render(ifc_canvas *canvas, const RECT *r, int alpha);
+
+private:
+ AutoSkinBitmap ul, u, ur;
+ AutoSkinBitmap l, mid, right;
+ AutoSkinBitmap ll, bot, lr;
+};
+
+PaintSetButtonDown::PaintSetButtonDown()
+{
+ ul = L"wasabi.button.pressed.top.left";
+ u = L"wasabi.button.pressed.top";
+ ur = L"wasabi.button.pressed.top.right";
+
+ l = L"wasabi.button.pressed.left";
+ mid = L"wasabi.button.pressed.middle";
+ right = L"wasabi.button.pressed.right";
+
+ ll = L"wasabi.button.pressed.bottom.left";
+ bot = L"wasabi.button.pressed.bottom";
+ lr = L"wasabi.button.pressed.bottom.right";
+}
+
+void PaintSetButtonDown::render(ifc_canvas *canvasbase, const RECT *_r, int alpha)
+{
+ BaseCloneCanvas canvas;
+ int ret = canvas.clone(canvasbase);
+ ASSERT(ret);
+
+ RECT r = *_r, br;
+
+ // upper left
+ br.left = r.left;
+ br.top = r.top;
+ br.right = r.left + ul.getWidth();
+ br.bottom = r.top + ul.getHeight();
+ ul.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // top
+ br.left = br.right;
+ br.right = r.right - ur.getWidth();
+ u.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // upper right
+ br.left = br.right;
+ br.right = r.right;
+ ur.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // left
+ br.left = r.left;
+ br.right = r.left + l.getWidth();
+ br.top = r.top + ul.getHeight();
+ br.bottom = r.bottom - ll.getHeight();
+ l.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // middle
+ br.top = r.top + ul.getHeight();
+ br.bottom = r.bottom - ll.getHeight();
+ br.left = r.left + ul.getWidth();
+ br.right = r.right - ur.getWidth();
+ mid.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // right
+ br.left = r.right - right.getWidth();
+ br.right = r.right;
+ br.top = r.top + ur.getHeight();
+ br.bottom = r.bottom - lr.getHeight();
+ right.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // lower left
+ br.left = r.left;
+ br.right = r.left + ll.getWidth();
+ br.top = r.bottom - ll.getHeight();
+ br.bottom = r.bottom;
+ ll.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // bot
+ br.left = r.left + ll.getWidth();
+ br.right = r.right - lr.getWidth();
+ br.top = r.bottom - bot.getHeight();
+ br.bottom = r.bottom;
+ bot.stretchToRectAlpha(&canvas, &br, alpha);
+
+ // lower right
+ br.left = r.right - lr.getWidth();
+ br.right = r.right;
+ br.top = r.bottom - lr.getHeight();
+ br.bottom = r.bottom;
+ lr.stretchToRectAlpha(&canvas, &br, alpha);
+}
+//--
+
+class PaintSetAppFrame : public PaintSet
+{
+public:
+ PaintSetAppFrame();
+ virtual ~PaintSetAppFrame();
+
+ virtual void render(ifc_canvas *canvas, const RECT *r, int alpha);
+
+private:
+ SkinBitmap *ul, *up, *ur;
+ SkinBitmap *left, *right;
+ SkinBitmap *ll, *bot, *lr;
+};
+
+PaintSetAppFrame::PaintSetAppFrame()
+{
+ ul = new SkinBitmap(L"studio.border.upperLeft");
+ up = new SkinBitmap(L"studio.border.top");
+ ur = new SkinBitmap(L"studio.border.upperRight");
+
+ left = new SkinBitmap(L"studio.border.left");
+ right = new SkinBitmap(L"studio.border.right");
+
+ ll = new SkinBitmap(L"studio.border.lowerLeft");
+ bot = new SkinBitmap(L"studio.border.bottom");
+ lr = new SkinBitmap(L"studio.border.lowerRight");
+}
+
+PaintSetAppFrame::~PaintSetAppFrame()
+{
+ delete ul; delete up; delete ur;
+ delete left; delete right;
+ delete ll; delete bot; delete lr;
+}
+
+void PaintSetAppFrame::render(ifc_canvas *canvasbase, const RECT *_r, int alpha)
+{
+ BaseCloneCanvas canvas;
+ int ret = canvas.clone(canvasbase);
+ ASSERT(ret);
+
+ RECT r = *_r;
+ RECT br;
+
+ // upper left
+ br = r;
+ br.right = br.left + 2;
+ br.bottom = br.top + 2;
+ ul->stretchToRectAlpha(&canvas, &br, alpha);
+
+ // top
+ br = r;
+ br.left += 2;
+ br.right -= 2;
+ br.bottom = br.top + 2;
+ up->stretchToRectAlpha(&canvas, &br, alpha);
+
+ // upper right
+ br = r;
+ br.left = br.right - 2;
+ br.bottom = br.top + 2;
+ ur->stretchToRectAlpha(&canvas, &br, alpha);
+
+ // left
+ br = r;
+ br.right = br.left + 2;
+ br.top += 2;
+ br.bottom -= 2;
+ left->stretchToRectAlpha(&canvas, &br, alpha);
+
+ // right
+ br = r;
+ br.left = br.right - 2;
+ br.top += 2;
+ br.bottom -= 2;
+ right->stretchToRectAlpha(&canvas, &br, alpha);
+
+ // lower left
+ br = r;
+ br.right = br.left + 2;
+ br.top = br.bottom - 2;
+ ll->stretchToRectAlpha(&canvas, &br, alpha);
+
+ // bottom
+ br = r;
+ br.left += 2;
+ br.right -= 2;
+ br.top = br.bottom - 2;
+ bot->stretchToRectAlpha(&canvas, &br, alpha);
+
+ // lower right
+ br = r;
+ br.left = br.right - 2;
+ br.top = br.bottom - 2;
+ lr->stretchToRectAlpha(&canvas, &br, alpha);
+}
+
+// -----
+
+class PaintSetTitleStreak : public PaintSet
+{
+public:
+ PaintSetTitleStreak();
+
+ virtual void render(ifc_canvas *canvas, const RECT *r, int alpha);
+
+private:
+ AutoSkinBitmap title_left, title_middle, title_right;
+};
+
+PaintSetTitleStreak::PaintSetTitleStreak()
+{
+ title_left = L"wasabi.titlebar.left.active";
+ title_middle = L"wasabi.titlebar.center.active";
+ title_right = L"wasabi.titlebar.right.active";
+}
+
+void PaintSetTitleStreak::render(ifc_canvas *canvasbase, const RECT *_r, int alpha)
+{
+ BaseCloneCanvas canvas;
+ int ret = canvas.clone(canvasbase);
+ if (!ret) return;
+
+ RECT r = *_r;
+
+ RECT lr = r;
+ lr.right = lr.left + title_left.getWidth();
+ lr.top += ((lr.bottom - lr.top) - title_left.getHeight()) / 2;
+ lr.bottom = lr.top + title_left.getHeight();
+ if (lr.right <= lr.left) return;
+ title_left.stretchToRectAlpha(&canvas, &lr, alpha);
+
+ RECT rr = r;
+ rr.left = rr.right - title_right.getWidth();
+ rr.top += ((rr.bottom - rr.top) - title_left.getHeight()) / 2;
+ rr.bottom = rr.top + title_left.getHeight();
+ if (rr.right <= rr.left) return;
+ title_right.stretchToRectAlpha(&canvas, &rr, alpha);
+
+ RECT cr = r;
+ cr.left = lr.right;
+ cr.right = rr.left;
+ cr.top += ((cr.bottom - cr.top) - title_left.getHeight()) / 2;
+ cr.bottom = cr.top + title_left.getHeight();
+ if (cr.right <= cr.left) return;
+ title_middle.stretchToRectAlpha(&canvas, &cr, alpha);
+}
+
+class PaintSetFocusRect : public PaintSet
+{
+public:
+ virtual void render(ifc_canvas *canvas, const RECT *r, int alpha)
+ {
+ BaseCloneCanvas c;
+ c.clone(canvas);
+ c.drawRect(r, 0, 0xFFFFFF, alpha);
+ }
+};
+
+// -----
+
+int paintset_present(int set)
+{
+ return paintset_renderPaintSet(set, NULL, NULL, 255, TRUE);
+}
+
+int paintset_renderPaintSet(int type, ifc_canvas *c, const RECT *r, int alpha, int checkonly)
+{
+ PaintSet *ret = NULL;
+ switch (type)
+ {
+ case BUTTONUP:
+ ret = sets[BUTTONUP];
+ if (ret == NULL) ret = new PaintSetButtonUp();
+ sets[BUTTONUP] = ret;
+ break;
+ case BUTTONDOWN:
+ ret = sets[BUTTONDOWN];
+ if (ret == NULL) ret = new PaintSetButtonDown();
+ sets[BUTTONDOWN] = ret;
+ break;
+ case TRAY:
+ ret = sets[BUTTONDOWN];
+ if (ret == NULL) ret = new PaintSetButtonDown();
+ sets[BUTTONDOWN] = ret;
+ break;
+ case APPFRAME:
+ ret = sets[APPFRAME];
+ if (ret == NULL) ret = new PaintSetAppFrame();
+ sets[APPFRAME] = ret;
+ break;
+ case BUTTONDISABLED:
+ ret = sets[BUTTONDISABLED];
+ if (ret == NULL) ret = new PaintSetButtonDisabled();
+ sets[BUTTONDISABLED] = ret;
+ break;
+ case TITLESTREAK:
+ ret = sets[TITLESTREAK];
+ if (ret == NULL) ret = new PaintSetTitleStreak();
+ sets[TITLESTREAK] = ret;
+ break;
+ case LABEL:
+ ret = sets[LABEL];
+ if (ret == NULL) ret = new PaintSetLabel();
+ sets[LABEL] = ret;
+ break;
+ case FOCUSRECT:
+ ret = sets[FOCUSRECT];
+ if (ret == NULL) ret = new PaintSetFocusRect();
+ sets[FOCUSRECT] = ret;
+ break;
+ }
+
+ if (ret != NULL)
+ {
+ if (!checkonly) ret->render(c, r, alpha);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#ifdef WASABI_COMPILE_FONTS
+
+#define VERTPAD 2
+#define AAFACTOR 2
+#define FONTNAME "studio.component.title"
+#define FONTNAMEW L"studio.component.title"
+
+void paintset_renderTitle(const wchar_t *title, ifc_canvas *canvasbase, const RECT *_r, int alpha, int dostreaks, int doborder)
+{
+ BaseCloneCanvas canvas;
+ int ret = canvas.clone(canvasbase);
+ if (!ret) return;
+
+ RECT r = *_r;
+ int w = r.right - r.left;
+ int h = (r.bottom - r.top) - VERTPAD;
+
+ svc_font *f = Font::requestSkinFont(FONTNAMEW);
+ if (f->isBitmap() || !doborder)
+ {
+ Wasabi::FontInfo fontInfo;
+ int tw, th;
+ fontInfo.pointSize = h;
+ fontInfo.face = FONTNAMEW;
+ fontInfo.color = title_fg;
+ canvas.getTextExtent(title, &tw, &th, &fontInfo);
+ w -= (tw + TITLE_PADDING * 2);
+ w /= 2;
+ int x = r.left + w + TITLE_PADDING;
+ int y = r.top + VERTPAD / 2;
+ canvas.textOut(x, y, title, &fontInfo);
+ }
+ else
+ {
+ Wasabi::FontInfo fontInfo;
+ int tw, th;
+ fontInfo.pointSize = h*AAFACTOR;
+ fontInfo.face = FONTNAMEW;
+ canvas.getTextExtent(title, &tw, &th, &fontInfo);
+ tw /= AAFACTOR;
+ th /= AAFACTOR;
+ tw += 2;
+ th += 2;
+
+ BltCanvas bc(tw*AAFACTOR, th*AAFACTOR + 1);
+ bc.fillBits(RGB(0, 0, 0)); // not skinned
+ fontInfo.opaque=false;
+ fontInfo.color = title_border;
+ bc.textOut(-AAFACTOR, AAFACTOR / 2, title, &fontInfo);
+ bc.textOut(AAFACTOR, AAFACTOR / 2, title, &fontInfo);
+ bc.textOut(AAFACTOR / 2, -AAFACTOR, title, &fontInfo);
+ bc.textOut(AAFACTOR / 2, AAFACTOR, title, &fontInfo);
+
+ fontInfo.color = title_fg;
+ bc.textOut(AAFACTOR / 2, AAFACTOR / 2, title, &fontInfo);
+
+ // mask it
+ bc.maskColor(RGB(0, 0, 0), RGB(0, 0, 0));
+ BltCanvas tc(tw, th);
+ bc.antiAliasTo(&tc, tw, th, AAFACTOR);
+
+
+ //int cw = tw + TITLE_PADDING * 2;
+ // if (cw > w || th > h) return;
+ w -= (tw + TITLE_PADDING * 2);
+ w /= 2;
+
+ int x = r.left + w + TITLE_PADDING;
+ int y = r.top + VERTPAD / 2;
+//FG>?? tc.vflip();
+ tc.blitAlpha(&canvas, x, y, alpha);
+
+ //SkinBitmap splef0(tc.getBitmap(), tc.getHDC(), TRUE, tc.getBits());
+// splef0.blitAlpha(&canvas, x, y, alpha);
+
+
+
+ }
+
+ if (dostreaks)
+ {
+ RECT pr = r;
+ pr.right = pr.left + w;
+ paintset_renderPaintSet(TITLESTREAK, &canvas, &pr, alpha);
+
+ pr.right = r.right;
+ pr.left = r.right - w;
+ paintset_renderPaintSet(TITLESTREAK, &canvas, &pr, alpha);
+ }
+}
+
+#endif
+
+void paintset_reset()
+{
+ for (int i = 0; i < NUM_PAINTSETS; i++)
+ {
+ delete sets[i];
+ sets[i] = NULL;
+ }
+}
+
diff --git a/Src/Wasabi/api/wnd/paintset.h b/Src/Wasabi/api/wnd/paintset.h
new file mode 100644
index 00000000..317a383b
--- /dev/null
+++ b/Src/Wasabi/api/wnd/paintset.h
@@ -0,0 +1,18 @@
+#ifndef _PAINTSET_H
+#define _PAINTSET_H
+
+#include <wasabicfg.h>
+
+#include <api/wnd/paintsets.h>
+#include <tataki/canvas/ifc_canvas.h>
+
+int paintset_present(int set);
+#ifdef WASABI_COMPILE_IMGLDR
+int paintset_renderPaintSet(int type, ifc_canvas *c, const RECT *r, int alpha=255, int checkonly=FALSE);
+#ifdef WASABI_COMPILE_FONTS
+void paintset_renderTitle(const wchar_t *title, ifc_canvas *canvas, const RECT *r, int alpha=255, int dostreaks=TRUE, int doborder=TRUE);
+#endif
+#endif
+void paintset_reset();
+
+#endif
diff --git a/Src/Wasabi/api/wnd/paintsets.h b/Src/Wasabi/api/wnd/paintsets.h
new file mode 100644
index 00000000..c1ed21d8
--- /dev/null
+++ b/Src/Wasabi/api/wnd/paintsets.h
@@ -0,0 +1,18 @@
+#ifndef _PAINTSETS_H
+#define _PAINTSETS_H
+
+namespace Paintset {
+ enum {
+ BUTTONUP,
+ BUTTONDOWN,
+ TRAY,
+ BUTTONDISABLED,
+ TITLESTREAK,
+ APPFRAME,
+ LABEL,
+ FOCUSRECT,
+ };
+ const int NUM_PAINTSETS = 8;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/platform/osx/PaintCanvas.cpp b/Src/Wasabi/api/wnd/platform/osx/PaintCanvas.cpp
new file mode 100644
index 00000000..6cfeb126
--- /dev/null
+++ b/Src/Wasabi/api/wnd/platform/osx/PaintCanvas.cpp
@@ -0,0 +1,51 @@
+#include "PaintCanvas.h"
+
+PaintCanvas::PaintCanvas()
+{
+ qdcontext=0;
+}
+
+bool PaintCanvas::beginPaint(BaseWnd *wnd)
+{
+ HIWindowRef macWnd = wnd->getOsWindowHandle();
+
+ qdcontext = GetWindowPort(macWnd);
+ QDBeginCGContext(qdcontext, &context);
+
+ return true;
+}
+
+PaintCanvas::~PaintCanvas()
+{
+ if (qdcontext)
+ QDEndCGContext(qdcontext, &context);
+}
+
+WndCanvas::WndCanvas()
+{
+ qdcontext=0;
+}
+
+WndCanvas::~WndCanvas()
+{
+ if (qdcontext)
+ QDEndCGContext(qdcontext, &context);
+}
+
+int WndCanvas::attachToClient(BaseWnd *basewnd)
+{
+ HIWindowRef macWnd = basewnd->getOsWindowHandle();
+
+ qdcontext = GetWindowPort(macWnd);
+ QDBeginCGContext(qdcontext, &context);
+ return 1;
+}
+
+
+TextInfoCanvas::TextInfoCanvas(BaseWnd */*unused*/)
+{
+}
+
+TextInfoCanvas::~TextInfoCanvas()
+{
+}
diff --git a/Src/Wasabi/api/wnd/platform/osx/PaintCanvas.h b/Src/Wasabi/api/wnd/platform/osx/PaintCanvas.h
new file mode 100644
index 00000000..f9091404
--- /dev/null
+++ b/Src/Wasabi/api/wnd/platform/osx/PaintCanvas.h
@@ -0,0 +1,45 @@
+#ifndef NULLSOFT_WASABI_OSX_PAINTCANVAS_H
+#define NULLSOFT_WASABI_OSX_PAINTCANVAS_H
+
+#include <tataki/canvas/canvas.h>
+#include <api/wnd/basewnd.h>
+
+class PaintCanvas : public Canvas
+{
+public:
+ PaintCanvas();
+ ~PaintCanvas();
+ bool beginPaint(BaseWnd *wnd);
+protected:
+ CGrafPtr qdcontext;
+};
+
+class PaintBltCanvas : public PaintCanvas
+{
+public:
+ bool beginPaintNC(BaseWnd *wnd)
+ {
+ return beginPaint(wnd);
+ }
+};
+#warning port PaintBltCanvas
+class WndCanvas : public Canvas
+{
+public:
+ WndCanvas();
+ virtual ~WndCanvas();
+
+ // address client area
+ int attachToClient(BaseWnd *basewnd);
+
+private:
+ CGrafPtr qdcontext;
+};
+
+class TextInfoCanvas : public Canvas
+{
+public:
+ TextInfoCanvas(BaseWnd *baseWnd);
+ virtual ~TextInfoCanvas();
+};
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/platform/osx/bltcanvas.h b/Src/Wasabi/api/wnd/platform/osx/bltcanvas.h
new file mode 100644
index 00000000..399deb71
--- /dev/null
+++ b/Src/Wasabi/api/wnd/platform/osx/bltcanvas.h
@@ -0,0 +1,26 @@
+#ifndef _BLTCANVAS_H
+#define _BLTCANVAS_H
+
+#include "canvas.h"
+
+class BltCanvas : public Canvas
+{
+public:
+ BltCanvas();
+ BltCanvas(int width, int height, OSWINDOWHANDLE wnd);
+
+ // override blit and stretchblit so we can use CGContextDrawLayerAtPoint/CGContextDrawLayerInRect
+ virtual void blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth);
+ void blitToRect(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha = 255);
+
+ virtual void stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth);
+ void stretchToRectAlpha(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha = 255);
+
+ void DestructiveResize(int w, int h, int nb_bpp = 32); // resizes the bitmap, destroying the contents
+ void fillBits(ARGB32 color);
+
+protected:
+ CGLayerRef layer;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/platform/osx/canvas.h b/Src/Wasabi/api/wnd/platform/osx/canvas.h
new file mode 100644
index 00000000..9a434026
--- /dev/null
+++ b/Src/Wasabi/api/wnd/platform/osx/canvas.h
@@ -0,0 +1,69 @@
+#ifndef NULLSOFT_WASABI_CANVAS_H
+#define NULLSOFT_WASABI_CANVAS_H
+
+#include <Carbon/Carbon.h>
+#include <tataki/canvas/ifc_canvas.h>
+#include <bfc/platform/platform.h>
+#include <api/service/svcs/svc_font.h> // for STDFONT_* stuff. should make a std_font thingy later
+#include <bfc/std.h> // for WASABI_DEFAULT_FONTNAMEW
+class BaseWnd;
+class api_region;
+
+class Canvas : public ifc_canvas
+{
+public:
+ Canvas() :context(0), wnd(0) {}
+ Canvas(CGContextRef _context) : context(_context), wnd(0) {}
+ Canvas(CGrafPtr _context);
+ HDC getHDC();
+ void fillRect(const RECT *r, RGB32 color);
+ void fillRgn(api_region *r, RGB32 color);
+ void setBaseWnd(BaseWnd *_wnd) { wnd=_wnd; }
+ void selectClipRgn(api_region *r);
+
+ virtual void blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth);
+ virtual void stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth);
+
+ void textOut(int x, int y, const wchar_t *txt, const Wasabi::FontInfo *fontInfo);
+
+ static float getSystemFontScale() { return 1.0f; }
+
+ int getTextWidth(const wchar_t *text, const Wasabi::FontInfo *fontInfo);
+ int getTextHeight(const wchar_t *text, const Wasabi::FontInfo *fontInfo);
+ int getTextHeight(const Wasabi::FontInfo *fontInfo)
+ {
+ return getTextHeight(L"M", fontInfo);
+ }
+ void getTextExtent(const wchar_t *text, int *w, int *h, const Wasabi::FontInfo *fontInfo);
+ void textOutCentered(RECT *r, const wchar_t *txt, const Wasabi::FontInfo *fontInfo);
+ void textOut(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo);
+ void textOutEllipsed(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo);
+
+ void drawSysObject(const RECT *r, int sysobj, int alpha=255);
+protected:
+ RECVS_DISPATCH;
+
+ CGContextRef context;
+ BaseWnd *wnd; // TODO: not 100% sure we'll need this. win32 version has it so we'll keep it for now
+};
+
+class BaseCloneCanvas : public Canvas
+{
+public:
+ BaseCloneCanvas(ifc_canvas *cloner=NULL);
+ virtual ~BaseCloneCanvas();
+
+ int clone(ifc_canvas *cloner);
+};
+
+namespace DrawSysObj {
+ enum {
+ BUTTON, BUTTON_PUSHED, BUTTON_DISABLED,
+ OSBUTTON, OSBUTTON_PUSHED, OSBUTTON_DISABLED,
+ OSBUTTON_CLOSE, OSBUTTON_CLOSE_PUSHED, OSBUTTON_CLOSE_DISABLED,
+ OSBUTTON_MINIMIZE, OSBUTTON_MINIMIZE_PUSHED, OSBUTTON_MINIMIZE_DISABLED,
+ OSBUTTON_MAXIMIZE, OSBUTTON_MAXIMIZE_PUSHED, OSBUTTON_MAXIMIZE_DISABLED,
+ };
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/platform/osx/osx_bitmap_cgimage.cpp b/Src/Wasabi/api/wnd/platform/osx/osx_bitmap_cgimage.cpp
new file mode 100644
index 00000000..fe9f3363
--- /dev/null
+++ b/Src/Wasabi/api/wnd/platform/osx/osx_bitmap_cgimage.cpp
@@ -0,0 +1,220 @@
+#include "osx_bitmap_cgimage.h"
+
+SkinBitmap::SkinBitmap(ARGB32 *_bits, int w, int h) : image(0)
+{
+ // TODO: allow a mechanism for SkinBitmap to take ownership of the data
+ bits = malloc(w*h*4);
+ if (bits)
+ {
+ memcpy(bits, _bits, w*h*4);
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+ imageContext = CGBitmapContextCreate(bits, w, h, 8, w*4, colorSpace, kCGBitmapByteOrder32Little|kCGImageAlphaPremultipliedFirst);
+ image = CGBitmapContextCreateImage(imageContext);
+ CGColorSpaceRelease(colorSpace);
+ }
+}
+
+SkinBitmap::~SkinBitmap()
+{
+ CGImageRelease(image);
+#ifndef SKINBITMAP_USE_CGIMAGE
+ free(bits);
+ CGContextRelease(imageContext);
+#endif
+}
+
+#ifdef WASABI_COMPILE_IMGLDR
+SkinBitmap::SkinBitmap(const wchar_t *elementname, int _cached)
+{
+ ASSERT(elementname!= NULL);
+
+ bitmapname = elementname;
+ x_offset = -1;
+ y_offset = -1;
+ subimage_w = -1;
+ subimage_h = -1;
+ fullimage_w=fullimage_h=0;
+ ownbits=1;
+ fromskin = 0;
+ last_failed = 0;
+#ifdef WASABI_COMPILE_SKIN
+ bits = WASABI_API_IMGLDR->imgldr_requestSkinBitmap(elementname, &has_alpha, &x_offset, &y_offset, &subimage_w, &subimage_h, &fullimage_w, &fullimage_h,_cached);
+ fromskin = (bits != NULL);
+#else
+ bits = NULL;
+#endif
+ if (bits == NULL)
+ bits = WASABI_API_IMGLDR->imgldr_makeBmp(elementname, &has_alpha, &fullimage_w, &fullimage_h);
+#ifdef WASABI_COMPILE_SKIN
+ if (bits == NULL)
+ {
+ bits = WASABI_API_IMGLDR->imgldr_requestSkinBitmap(ERRORBMP, &has_alpha, &x_offset, &y_offset, &subimage_w, &subimage_h, &fullimage_w, &fullimage_h,_cached);
+ last_failed = 1;
+ }
+#endif
+ if (bits == NULL)
+ {
+ bits = WASABI_API_IMGLDR->imgldr_makeBmp(HARDERRORBMP, &has_alpha, &fullimage_w, &fullimage_h);
+ last_failed = 1;
+ }
+
+ // check that coordinates are correct
+ if(x_offset!=-1 && x_offset>fullimage_w) x_offset=fullimage_w-1;
+ if(y_offset!=-1 && y_offset>fullimage_h) y_offset=fullimage_h-1;
+ if(subimage_w!=-1 && (x_offset+subimage_w)>fullimage_w) subimage_w=fullimage_w-x_offset;
+ if(subimage_h!=-1 && (y_offset+subimage_h)>fullimage_h) subimage_h=fullimage_h-y_offset;
+
+ // ASSERTPR(bits != NULL, elementname);
+ if (bits == NULL) {
+ DebugString("element not found ! %s\n", elementname);
+ int n = 10*10;
+ bits = (ARGB32 *)WASABI_API_MEMMGR->sysMalloc(n * 4);
+
+
+ ARGB32 *p = bits;
+ while (n--)
+ *p++ = 0xFFFF00FF;
+ }
+}
+#endif
+
+
+int SkinBitmap::getWidth()
+{
+ if (!image)
+ return 0;
+
+ return CGImageGetWidth(image);
+}
+
+int SkinBitmap::getFullWidth()
+{
+ if (!image)
+ return 0;
+
+ return CGImageGetBytesPerRow(image)/4; // assumes 32bit pixel data
+}
+
+int SkinBitmap::getHeight()
+{
+ if (!image)
+ return 0;
+ return CGImageGetHeight(image);
+}
+
+void SkinBitmap::blit(ifc_canvas *canvas, int x, int y)
+{
+ if (!image)
+ return;
+
+ CGContextRef context = canvas->getHDC();
+ CGRect rect = CGRectMake(x, y, getWidth(), getHeight());
+ CGContextDrawImage(context, rect, image);
+}
+
+void SkinBitmap::blitAlpha(ifc_canvas *canvas, int x, int y, int alpha)
+{
+ if (!image)
+ return;
+
+ float floatAlpha = alpha / 255.f;
+
+ CGContextRef context = canvas->getHDC();
+ CGContextSaveGState(context);
+
+// CGContextTranslateCTM(context, 0, r->bottom);
+// CGContextScaleCTM(context, 1.0, -1.0);
+
+ CGContextSetAlpha(context, floatAlpha);
+ CGRect rect = CGRectMake(x, y, getWidth(), getHeight());
+ CGContextDrawImage(context, rect, image);
+ CGContextRestoreGState(context);
+}
+
+void SkinBitmap::stretchToRect(ifc_canvas *canvas, RECT *r)
+{
+ if (!image)
+ return;
+
+ CGContextRef context = canvas->getHDC();
+ CGContextSaveGState(context);
+
+ CGContextTranslateCTM (context, 0, r->bottom);
+ CGContextScaleCTM(context, 1.0, -1.0);
+
+ CGRect rect = CGRectMake(r->left, r->top, r->right-r->left, r->bottom-r->top);
+ CGContextDrawImage(context, rect, image);
+
+ CGContextRestoreGState(context);
+}
+
+void SkinBitmap::stretchToRectAlpha(ifc_canvas *canvas, RECT *r, int alpha)
+{
+ if (!image)
+ return;
+
+ float floatAlpha = alpha / 255.f;
+
+ CGContextRef context = canvas->getHDC();
+ CGContextSaveGState(context);
+
+ CGContextTranslateCTM (context, 0, r->bottom);
+ CGContextScaleCTM(context, 1.0, -1.0);
+
+ CGContextSetAlpha(context, floatAlpha);
+ CGRect rect = CGRectMake(r->left, r->top, r->right-r->left, r->bottom-r->top);
+ CGContextDrawImage(context, rect, image);
+ CGContextRestoreGState(context);
+}
+
+void SkinBitmap::stretchToRectAlpha(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha)
+{
+ if (!image)
+ return;
+
+ float floatAlpha = alpha / 255.f;
+
+ // make a new image ref clipped to the source rect
+ CGRect srcRect = CGRectMake(src->left, src->top, src->right-src->left, src->bottom-src->top);
+ CGImageRef clippedImage = CGImageCreateWithImageInRect(image, srcRect);
+
+ // blit onto canvas
+ CGContextRef context = canvas->getHDC();
+ CGContextSaveGState(context);
+
+ CGContextTranslateCTM(context, 0, dst->bottom);
+ CGContextScaleCTM(context, 1.0, -1.0);
+
+ CGContextSetAlpha(context, floatAlpha);
+ CGRect rect = CGRectMake(dst->left, dst->top, dst->right-dst->left, dst->bottom-dst->top);
+ CGContextDrawImage(context, rect, clippedImage);
+ CGContextRestoreGState(context);
+
+ // release the reference to our clipped image
+ CGImageRelease(clippedImage);
+}
+
+uint8_t *SkinBitmap::getBits()
+{
+ return static_cast<uint8_t *>(CGBitmapContextGetData(imageContext));
+}
+
+void SkinBitmap::UpdateBits(uint8_t *bits)
+{
+ CGImageRelease(image);
+ image = CGBitmapContextCreateImage(imageContext);
+}
+
+ARGB32 SkinBitmap::getPixel(int x, int y)
+{
+ ARGB32 *array = (ARGB32 *)getBits();
+ return array[x + y*getFullWidth()];
+}
+
+#define CBCLASS SkinBitmap
+START_DISPATCH;
+CB(IFC_BITMAP_GETBITMAP, GetBitmap);
+CB(IFC_BITMAP_GETBITS, getBits);
+VCB(IFC_BITMAP_UPDATEBITS, UpdateBits);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/platform/osx/osx_bitmap_cgimage.h b/Src/Wasabi/api/wnd/platform/osx/osx_bitmap_cgimage.h
new file mode 100644
index 00000000..5a30637e
--- /dev/null
+++ b/Src/Wasabi/api/wnd/platform/osx/osx_bitmap_cgimage.h
@@ -0,0 +1,47 @@
+#ifndef NULLSOFT_WASABI_OSX_BITMAP_CGIMAGE_H
+#define NULLSOFT_WASABI_OSX_BITMAP_CGIMAGE_H
+
+#include <bfc/platform/platform.h>
+#include <tataki/canvas/ifc_canvas.h>
+#include <api/wnd/ifc_bitmap.h>
+
+/*
+ TODO:
+ need some kind of updateBits() so that the underlying image can be updated to reflect changes
+ */
+class SkinBitmap : public ifc_bitmap
+{
+public:
+ SkinBitmap(ARGB32 *bits, int w, int h); // added by benski, use if you have raw image bits
+ SkinBitmap(const wchar_t *elementname, int cached = 1);
+ ~SkinBitmap();
+ int getWidth();
+ int getHeight();
+ int getFullWidth(); // aka pitch
+
+ // blits
+ void blit(ifc_canvas *canvas, int x, int y);
+ void blitAlpha(ifc_canvas *canvas, int x, int y, int alpha = 255);
+ // stretch blits
+ void stretchToRect(ifc_canvas *canvas, RECT *r);
+ void stretchToRectAlpha(ifc_canvas *canvas, RECT *r, int alpha = 255);
+ void stretchToRectAlpha(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha = 255);
+// tiled blits
+ void blitTile(ifc_canvas *canvas, RECT *dest, int xoffs = 0, int yoffs = 0, int alpha = 255);
+
+ ARGB32 getPixel(int x, int y);
+public: // ifc_bitmap implementations
+ OSBITMAPHANDLE GetBitmap() { return image; }
+ uint8_t *getBits();
+ void UpdateBits(uint8_t *bits);
+
+private:
+ CGImageRef image;
+ CGContextRef imageContext;
+ void *bits;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/platform/osx/osx_canvas_layer.cpp b/Src/Wasabi/api/wnd/platform/osx/osx_canvas_layer.cpp
new file mode 100644
index 00000000..43c2984b
--- /dev/null
+++ b/Src/Wasabi/api/wnd/platform/osx/osx_canvas_layer.cpp
@@ -0,0 +1,95 @@
+#include <tataki/canvas/bltcanvas.h>
+
+inline float QuartzBlue(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[0] / 255.f;
+}
+
+inline float QuartzGreen(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[1] / 255.f;
+}
+
+inline float QuartzRed(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[2] / 255.f;
+}
+
+inline float QuartzAlpha(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[3] / 255.f;
+}
+
+BltCanvas::BltCanvas(int width, int height, OSWINDOWHANDLE wnd)
+{
+ CGrafPtr qdcontext = GetWindowPort(wnd);
+ CGContextRef temp;
+ QDBeginCGContext(qdcontext, &temp);
+ CGSize size = CGSizeMake(width, height);
+ layer = CGLayerCreateWithContext(temp, size, NULL);
+ context = CGLayerGetContext(layer);
+ QDEndCGContext(qdcontext, &temp);
+}
+
+void BltCanvas::blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth)
+{
+ CGPoint point = CGPointMake(dstx-srcx, dsty-srcy);
+ CGContextDrawLayerAtPoint(dest->getHDC(), point, layer);
+}
+
+void BltCanvas::blitToRect(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha)
+{
+ CGContextRef dest = canvas->getHDC();
+ CGContextSaveGState(dest);
+ CGContextSetAlpha(dest, (float)alpha/255.f);
+ // TODO: deal with width properly
+ CGRect rect = CGRectMake(dst->left - src->left, dst->top - src->top, dst->right - dst->left, dst->bottom - dst->top);
+ CGContextDrawLayerInRect(dest, rect, layer);
+ CGContextRestoreGState(dest);
+}
+
+void BltCanvas::stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth)
+{
+ CGContextSaveGState(context);
+ CGContextTranslateCTM(context, srcx, srcy);
+ CGRect rect = CGRectMake(dstx, dsty, dstw, dsth);
+ CGContextDrawLayerInRect(dest->getHDC(), rect, layer);
+ CGContextRestoreGState(context);
+}
+
+void BltCanvas::stretchToRectAlpha(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha)
+{
+ CGContextRef dest = canvas->getHDC();
+ CGContextSaveGState(dest);
+ CGContextSetAlpha(dest, (float)alpha/255.f);
+// TODO: deal with width properly
+ CGRect rect = CGRectMake(dst->left - src->left, dst->top - src->top, dst->right - dst->left, dst->bottom - dst->top);
+ CGContextDrawLayerInRect(dest, rect, layer);
+ CGContextRestoreGState(dest);
+}
+
+void BltCanvas::DestructiveResize(int w, int h, int nb_bpp)
+{
+ CGSize size = CGSizeMake(w, h);
+ CGLayerRef newlayer = CGLayerCreateWithContext(context, size, NULL);
+ CGContextRelease(context);
+ CGLayerRelease(layer);
+ layer = newlayer;
+ context = CGLayerGetContext(layer);
+}
+
+void BltCanvas::fillBits(ARGB32 color)
+{
+ CGContextSetRGBFillColor(context,
+ QuartzRed(color), // red
+ QuartzGreen(color), // green
+ QuartzBlue(color), // blue
+ QuartzAlpha(color) // alpha
+ );
+
+ CGContextFillRect(context, CGRectInfinite);
+} \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/platform/osx/osx_canvas_quartz.cpp b/Src/Wasabi/api/wnd/platform/osx/osx_canvas_quartz.cpp
new file mode 100644
index 00000000..093ab5e5
--- /dev/null
+++ b/Src/Wasabi/api/wnd/platform/osx/osx_canvas_quartz.cpp
@@ -0,0 +1,275 @@
+#include <bfc/platform/types.h>
+#include <Carbon/Carbon.h>
+#include <tataki/canvas/canvas.h>
+#include <api/wnd/basewnd.h>
+#include <tataki/region/api_region.h>
+
+
+
+/* various functions that might help out
+
+for drawSysObject:
+HIThemeDrawButton
+HIThemeDrawTitleBarWidget for minimize, maximize, exit
+*/
+
+inline float QuartzBlue(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[0] / 255.f;
+}
+
+inline float QuartzGreen(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[1] / 255.f;
+
+}
+
+inline float QuartzRed(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[2] / 255.f;
+
+}
+
+inline float QuartzAlpha(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[3] / 255.f;
+
+}
+
+Canvas::Canvas(CGrafPtr _context)
+{
+
+}
+
+void Canvas::fillRect(const RECT *r, ARGB32 color)
+{
+ CGContextSetRGBFillColor(context,
+ QuartzRed(color), // red
+ QuartzGreen(color), // green
+ QuartzBlue(color), // blue
+ QuartzAlpha(color) // alpha
+ );
+
+ HIRect rect = HIRectFromRECT(r);
+ CGContextFillRect(context, rect);
+}
+
+void Canvas::fillRgn(api_region *r, ARGB32 color)
+{
+ CGContextSetRGBFillColor(context,
+ QuartzRed(color), // red
+ QuartzGreen(color), // green
+ QuartzBlue(color), // blue
+ QuartzAlpha(color) // alpha
+ );
+
+ HIShapeRef shape = r->getOSHandle();
+ HIShapeReplacePathInCGContext(shape, context);
+ CGContextFillPath(context);
+}
+
+void Canvas::blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth)
+{
+ // clip dest
+ // Create CGImage from context
+ // CGContextDrawImage
+}
+
+HDC Canvas::getHDC()
+{
+ return context;
+}
+
+void Canvas::selectClipRgn(api_region *r)
+{
+ if (r)
+ {
+ HIShapeRef shape = r->getOSHandle();
+ HIShapeReplacePathInCGContext(shape, context);
+ CGContextClip(context);
+ }
+ else
+ {
+ CGContextClipToRect(context, CGRectInfinite);
+ }
+}
+
+void Canvas::stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth)
+{
+ // Create CGImage from context
+ // CGContextDrawImage
+}
+
+void Canvas::textOut(int x, int y, const wchar_t *txt, const Wasabi::FontInfo *fontInfo)
+{
+ // TODO: turn this code into a svc_fontI, and use api_font here instead
+ size_t len = wcslen(txt);
+ UniChar *unistr = (UniChar *)malloc((len + 1) * sizeof(UniChar));
+ UniChar *copy = unistr;
+ while (*txt)
+ *copy++=*txt++;
+ *copy=0;
+
+ ATSUStyle style;
+ ATSUCreateStyle(&style);
+
+ CGContextSaveGState(context);
+ CGContextSetRGBFillColor(context,
+ QuartzRed(fontInfo->color), // red
+ QuartzGreen(fontInfo->color), // green
+ QuartzBlue(fontInfo->color), // blue
+ QuartzAlpha(fontInfo->color) // alpha
+ );
+
+ ATSUTextLayout layout;
+ ATSUCreateTextLayout(&layout);
+
+ ATSUSetTextPointerLocation(layout, unistr, kATSUFromTextBeginning, kATSUToTextEnd, len);
+
+ ATSUSetRunStyle(layout, style, kATSUFromTextBeginning, kATSUToTextEnd);
+
+ Rect imageRect;
+ ATSUMeasureTextImage(layout, kATSUFromTextBeginning, kATSUToTextEnd, 0, 0, &imageRect);
+ y-=(imageRect.bottom - imageRect.top);
+ CGContextScaleCTM(context, 1.0, -1.0);
+
+ ATSUAttributeTag tags[] = {kATSUCGContextTag};
+ ATSUAttributeValuePtr values[] = {&context};
+ ByteCount sizes[] = {sizeof(CGContextRef)};
+ ATSUSetLayoutControls(layout, 1, tags, sizes, values);
+ ATSUDrawText(layout, kATSUFromTextBeginning, kATSUToTextEnd, FloatToFixed(x), FloatToFixed(y));
+ ATSUDisposeTextLayout(layout);
+ ATSUDisposeStyle(style);
+ CGContextRestoreGState(context);
+ free(unistr);
+}
+
+void Canvas::drawSysObject(const RECT *r, int sysobj, int alpha)
+{
+#warning TODO
+ using namespace DrawSysObj;
+ switch(sysobj)
+ {
+ case OSBUTTON:
+ {
+ HIRect buttonRect = HIRectFromRECT(r);
+ HIThemeButtonDrawInfo buttonDrawInfo;
+ buttonDrawInfo.version=0;
+ buttonDrawInfo.state = kThemeStateActive;
+ buttonDrawInfo.kind = kThemePushButton;
+ buttonDrawInfo.value = kThemeButtonOn;
+ buttonDrawInfo.adornment = kThemeAdornmentNone;
+ buttonDrawInfo.animation.time.start = 0;
+ buttonDrawInfo.animation.time.current=0;
+ HIThemeDrawButton(&buttonRect, &buttonDrawInfo, context, /*kHIThemeOrientationNormal*/kHIThemeOrientationInverted, 0);
+ }
+ break;
+ case OSBUTTON_PUSHED:
+ {
+ HIRect buttonRect = HIRectFromRECT(r);
+ HIThemeButtonDrawInfo buttonDrawInfo;
+ buttonDrawInfo.version=0;
+ buttonDrawInfo.state = kThemeStatePressed;
+ buttonDrawInfo.kind = kThemePushButton;
+ buttonDrawInfo.value = kThemeButtonOn;
+ buttonDrawInfo.adornment = kThemeAdornmentNone;
+ buttonDrawInfo.animation.time.start = 0;
+ buttonDrawInfo.animation.time.current=0;
+ HIThemeDrawButton(&buttonRect, &buttonDrawInfo, context, /*kHIThemeOrientationNormal*/kHIThemeOrientationInverted, 0);
+ }
+ break;
+ case OSBUTTON_DISABLED:
+ {
+ HIRect buttonRect = HIRectFromRECT(r);
+ HIThemeButtonDrawInfo buttonDrawInfo;
+ buttonDrawInfo.version=0;
+ buttonDrawInfo.state = kThemeStateInactive;
+ buttonDrawInfo.kind = kThemePushButton;
+ buttonDrawInfo.value = kThemeButtonOn;
+ buttonDrawInfo.adornment = kThemeAdornmentNone;
+ buttonDrawInfo.animation.time.start = 0;
+ buttonDrawInfo.animation.time.current=0;
+ HIThemeDrawButton(&buttonRect, &buttonDrawInfo, context, /*kHIThemeOrientationNormal*/kHIThemeOrientationInverted, 0);
+ }
+ break;
+ }
+}
+
+void Canvas::getTextExtent(const wchar_t *text, int *w, int *h, const Wasabi::FontInfo *fontInfo)
+{
+ // TODO: turn this code into a svc_fontI, and use api_font here instead
+ size_t len = wcslen(text);
+ UniChar *unistr = (UniChar *)malloc((len + 1) * sizeof(UniChar));
+ UniChar *copy = unistr;
+ while (*text)
+ *copy++=*text++;
+ *copy=0;
+
+ ATSUStyle style;
+ ATSUCreateStyle(&style);
+
+ ATSUTextLayout layout;
+ ATSUCreateTextLayout(&layout);
+
+ ATSUSetTextPointerLocation(layout, unistr, kATSUFromTextBeginning, kATSUToTextEnd, len);
+
+ ATSUSetRunStyle(layout, style, kATSUFromTextBeginning, kATSUToTextEnd);
+
+ Rect imageRect;
+ ATSUMeasureTextImage(layout, kATSUFromTextBeginning, kATSUToTextEnd, 0, 0, &imageRect);
+ *h=(imageRect.bottom - imageRect.top);
+ *w = (imageRect.right - imageRect.left);
+
+ ATSUDisposeTextLayout(layout);
+ ATSUDisposeStyle(style);
+ free(unistr);
+}
+
+void Canvas::textOutCentered(RECT *r, const wchar_t *txt, const Wasabi::FontInfo *fontInfo)
+{
+ textOut(r->left, r->top, txt, fontInfo);
+}
+
+
+#define CBCLASS Canvas
+START_DISPATCH;
+CB(GETHDC, getHDC);
+END_DISPATCH;
+#undef CBCLASS
+
+BaseCloneCanvas::BaseCloneCanvas(ifc_canvas *cloner)
+{
+ if (cloner != NULL) clone(cloner);
+}
+
+int BaseCloneCanvas::clone(ifc_canvas *cloner)
+{
+ ASSERTPR(context == NULL, "can't clone twice");
+ context = cloner->getHDC();
+ CGContextRetain(context);
+// bits = cloner->getBits();
+// cloner->getDim(&width, &height, &pitch);
+ // srcwnd = cloner->getBaseWnd();
+// cloner->getOffsets(&xoffset, &yoffset);
+// setTextFont(cloner->getTextFont());
+// setTextSize(cloner->getTextSize());
+// setTextBold(cloner->getTextBold());
+// setTextOpaque(cloner->getTextOpaque());
+// setTextUnderline(cloner->getTextUnderline());
+// setTextItalic(cloner->getTextItalic());
+// setTextAlign(cloner->getTextAlign());
+// setTextColor(cloner->getTextColor());
+// setTextBkColor(cloner->getTextBkColor());
+ return (context != NULL);
+}
+
+BaseCloneCanvas::~BaseCloneCanvas()
+{
+ CGContextRelease(context);
+ context = NULL;
+}
+
diff --git a/Src/Wasabi/api/wnd/platform/osx/osx_region_hishape.cpp b/Src/Wasabi/api/wnd/platform/osx/osx_region_hishape.cpp
new file mode 100644
index 00000000..348ba1de
--- /dev/null
+++ b/Src/Wasabi/api/wnd/platform/osx/osx_region_hishape.cpp
@@ -0,0 +1,217 @@
+#include <Carbon/Carbon.h>
+#include <tataki/region/region.h>
+#include <tataki/bitmap/bitmap.h>
+
+RegionI::RegionI() : rgn(0)
+{
+}
+
+RegionI::RegionI(const RECT *r) : rgn(0)
+{
+ setRect(r);
+}
+
+RegionI::RegionI(HIMutableShapeRef _rgn) : rgn(_rgn)
+{
+}
+
+RegionI::RegionI(HIShapeRef _rgn)
+{
+ rgn=HIShapeCreateMutableCopy(_rgn);
+}
+
+RegionI::~RegionI()
+{
+ if (rgn)
+ CFRelease(rgn);
+}
+
+RegionI::RegionI(RgnHandle qdrgn)
+{
+ HIShapeRef shape = HIShapeCreateWithQDRgn(qdrgn);
+ rgn = HIShapeCreateMutableCopy(shape);
+ CFRelease(shape);
+}
+
+RegionI::RegionI(SkinBitmap *bitmap)
+{
+ // TODO: we need to find a much better way to do this
+ RECT r;
+ r.left=0;
+ r.top=0;
+ r.right=bitmap->getWidth();
+ r.bottom=bitmap->getHeight();
+ setRect(&r);
+}
+
+
+OSREGIONHANDLE RegionI::getOSHandle()
+{
+ if (!rgn)
+ rgn = HIShapeCreateMutable();
+ return rgn;
+}
+
+api_region *RegionI::clone()
+{
+ if (!rgn)
+ return new RegionI();
+ else
+ return new RegionI(HIShapeCreateMutableCopy(rgn));
+}
+
+void RegionI::disposeClone(api_region *r)
+{
+ if (r) // yes we need to check for NULL here because r != static_cast<>(r)
+ delete static_cast<RegionI *>(r);
+}
+
+bool RegionI::ptInRegion(const POINT *pt)
+{
+ if (!rgn)
+ return false;
+ HIPoint hipt = HIPointFromPOINT(pt);
+ return !!HIShapeContainsPoint(rgn, &hipt);
+}
+
+void RegionI::offset(int x, int y)
+{
+ if (!rgn)
+ rgn = HIShapeCreateMutable();
+
+ HIShapeOffset(rgn, x, y);
+}
+
+void RegionI::getBox(RECT *r)
+{
+ if (!rgn) // TODO: we could manually set r to 0,0,0,0
+ rgn = HIShapeCreateMutable();
+
+ HIRect rect;
+ HIShapeGetBounds(rgn, &rect);
+ *r = RECTFromHIRect(&rect);
+}
+
+void RegionI::subtractRegion(const api_region *r)
+{
+ if (rgn)
+ {
+ api_region *reg = const_cast<api_region *>(r);
+ HIShapeRef sub = reg->getOSHandle();
+ HIShapeDifference(rgn,sub, rgn);
+ }
+}
+
+void RegionI::subtractRect(const RECT *r)
+{
+ if (rgn)
+ {
+ HIRect rect = HIRectFromRECT(r);
+ HIShapeRef sub = HIShapeCreateWithRect(&rect);
+ HIShapeDifference(rgn, sub, rgn);
+ }
+}
+
+void RegionI::addRect(const RECT *r)
+{
+ if (!rgn)
+ rgn = HIShapeCreateMutable();
+ HIRect rect = HIRectFromRECT(r);
+ HIShapeRef add = HIShapeCreateWithRect(&rect);
+ HIShapeUnion(rgn, add, rgn);
+}
+
+void RegionI::addRegion(const api_region *r)
+{
+ if (!rgn)
+ rgn = HIShapeCreateMutable();
+ api_region *reg = const_cast<api_region *>(r);
+ HIShapeRef add = reg->getOSHandle();
+ HIShapeUnion(rgn, add, rgn);
+}
+
+void RegionI::andRegion(const api_region *r)
+{
+ if (rgn) // intersection with empty region will always be empty
+ {
+ api_region *reg = const_cast<api_region *>(r);
+ HIShapeRef intersection = reg->getOSHandle();
+ HIShapeIntersect(rgn, intersection, rgn);
+ }
+}
+
+void RegionI::setRect(const RECT *r)
+{
+ if (rgn)
+ CFRelease(rgn);
+ HIRect rect = HIRectFromRECT(r);
+ HIShapeRef rectRgn = HIShapeCreateWithRect(&rect);
+ rgn = HIShapeCreateMutableCopy(rectRgn);
+ CFRelease(rectRgn);
+}
+
+void RegionI::empty()
+{
+ if (rgn)
+ CFRelease(rgn);
+ rgn=0;
+}
+
+int RegionI::isEmpty()
+{
+ if (!rgn)
+ return 1;
+ return !!HIShapeIsEmpty(rgn);
+}
+
+int RegionI::isRect()
+{
+ if (!rgn)
+ return 1;
+ return !!HIShapeIsRectangular(rgn);
+}
+
+int RegionI::intersectRgn(const api_region *r, api_region *intersection)
+{
+ intersection->empty();
+ intersection->addRegion(this);
+ intersection->andRegion(r);
+ return !intersection->isEmpty();
+}
+
+int RegionI::intersectRect(const RECT *r, api_region *intersection)
+{
+ intersection->setRect(r);
+ intersection->andRegion(this);
+ return !intersection->isEmpty();
+}
+
+#define CBCLASS RegionI
+START_DISPATCH;
+CB(REGION_GETOSHANDLE, getOSHandle);
+CB(REGION_CLONE, clone);
+VCB(REGION_DISPOSECLONE, disposeClone);
+CB(REGION_PTINREGION, ptInRegion);
+VCB(REGION_OFFSET, offset);
+VCB(REGION_GETBOX, getBox);
+VCB(REGION_SUBTRACTRGN, subtractRegion);
+VCB(REGION_SUBTRACTRECT, subtractRect);
+VCB(REGION_ADDRECT, addRect);
+VCB(REGION_ADD, addRegion);
+VCB(REGION_AND, andRegion);
+VCB(REGION_SETRECT, setRect);
+VCB(REGION_EMPTY, empty);
+CB(REGION_ISEMPTY, isEmpty);
+CB(REGION_ISRECT, isRect);
+CB(REGION_INTERSECTRGN, intersectRgn);
+CB(REGION_INTERSECTRECT, intersectRect);
+END_DISPATCH;
+#undef CBCLASS
+
+#define CBCLASS RegionServerI
+START_DISPATCH;
+VCB(REGIONSERVER_ADDREF, addRef);
+VCB(REGIONSERVER_DELREF, delRef);
+CB(REGIONSERVER_GETREGION, getRegion);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/platform/osx/region.h b/Src/Wasabi/api/wnd/platform/osx/region.h
new file mode 100644
index 00000000..9879b642
--- /dev/null
+++ b/Src/Wasabi/api/wnd/platform/osx/region.h
@@ -0,0 +1,115 @@
+#ifndef __REGION_H
+#define __REGION_H
+
+#include <Carbon/Carbon.h>
+#include <bfc/platform/platform.h>
+#include <tataki/region/api_region.h>
+
+class SkinBitmap;
+
+class RegionI : public api_region
+{
+public:
+ RegionI();
+ RegionI(const RECT *r);
+ RegionI(RgnHandle qdrgn);
+ RegionI(HIShapeRef _rgn);
+ RegionI(SkinBitmap *bitmap);
+ ~RegionI();
+
+ // api_region
+ OSREGIONHANDLE getOSHandle();
+ api_region *clone();
+ void disposeClone(api_region *r);
+ bool ptInRegion(const POINT *pt);
+ void offset(int x, int y);
+ void getBox(RECT *r);
+ void subtractRegion(const api_region *r);
+ void subtractRect(const RECT *r);
+ void addRect(const RECT *r);
+ void addRegion(const api_region *r);
+ void andRegion(const api_region *r);
+ void setRect(const RECT *r);
+ void empty();
+ int isEmpty();
+ int equals(const api_region *r);
+ int enclosed(const api_region *r, api_region *outside = NULL);
+ int intersectRgn(const api_region *r, api_region *intersection);
+ int doesIntersectRgn(const api_region *r);
+ int intersectRect(const RECT *r, api_region *intersection);
+
+ int isRect();
+ void scale(double sx, double sy, bool round = 0);
+ void debug(int async = 0);
+ OSREGIONHANDLE makeWindowRegion(); // gives you a handle to a clone of the OSREGION object so you can insert it into a window's region with SetWindowRgn. ANY other use is prohibited
+
+ // this is how you can enumerate the subrects that compose to make up the
+ // entire region
+ int getNumRects();
+ int enumRect(int n, RECT *r);
+
+
+private:
+ RegionI(HIMutableShapeRef _rgn);
+ HIMutableShapeRef rgn;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+
+// TODO: we could take of advantage of HIShapeRef's built in reference counting to implement this
+class RegionServer : public Dispatchable {
+
+protected:
+ RegionServer() {}
+ virtual ~RegionServer() {}
+
+public:
+
+ void addRef(void *client);
+ void delRef(void *client);
+ api_region *getRegion();
+
+ enum {
+ REGIONSERVER_ADDREF = 500,
+ REGIONSERVER_DELREF = 550,
+ REGIONSERVER_GETREGION = 600,
+ };
+};
+
+inline void RegionServer::addRef(void *client) {
+ _voidcall(REGIONSERVER_ADDREF, (api_region *)NULL, client);
+}
+
+inline void RegionServer::delRef(void *client) {
+ _voidcall(REGIONSERVER_DELREF, client);
+}
+
+inline api_region * RegionServer::getRegion() {
+ return _call(REGIONSERVER_GETREGION, (api_region *)NULL);
+}
+
+class RegionServerI : public RegionServer {
+public :
+
+ RegionServerI() { numrefs = 0; }
+ virtual ~RegionServerI() {}
+
+ virtual void addRef(void *client) { numrefs++; }
+ virtual void delRef(void *client) { numrefs--; }
+ virtual api_region *getRegion()=0;
+
+ virtual int getNumRefs() { return numrefs; }
+
+protected:
+
+ RECVS_DISPATCH;
+
+private:
+
+ int numrefs;
+};
+#endif
+
+
diff --git a/Src/Wasabi/api/wnd/platform/win32/bitmap.h b/Src/Wasabi/api/wnd/platform/win32/bitmap.h
new file mode 100644
index 00000000..589f9a13
--- /dev/null
+++ b/Src/Wasabi/api/wnd/platform/win32/bitmap.h
@@ -0,0 +1,81 @@
+//NONPORTABLE
+#ifndef _BITMAP_H
+#define _BITMAP_H
+
+//#include <wasabicfg.h>
+//#include <bfc/common.h>
+#include <bfc/string/string.h>
+#include <bfc/string/StringW.h>
+
+class ifc_canvas; // see canvas.h
+
+//#define NO_MMX
+
+class api_region;
+
+// a skinnable bitmap
+class SkinBitmap
+{
+public:
+#ifndef _NOSTUDIO
+#ifdef WASABI_COMPILE_IMGLDR
+#ifdef _WIN32
+ SkinBitmap(HINSTANCE hInst, int _id, const wchar_t *colorgroup = NULL); //NONPORTABLE
+#endif
+ SkinBitmap(const wchar_t *elementname, int cached = 1);
+#endif
+#endif
+ // SkinBitmap(SkinBitmap *source, int w, int h);
+ SkinBitmap(int w, int h, ARGB32 bgcolor = RGBA(255,255,255,255)); //untested --BU
+#ifdef _WIN32
+ SkinBitmap(HBITMAP bitmap);
+ SkinBitmap(HBITMAP bitmap, HDC dc, int has_alpha = 0, void *bits = NULL);
+#endif
+ SkinBitmap(ARGB32 *bits, int w, int h); // added by benski, use if you have raw image bits
+ ~SkinBitmap();
+
+int getWidth() const { return subimage_w == -1 ? fullimage_w : subimage_w; };
+int getHeight() const { return subimage_h == -1 ? fullimage_h : subimage_h; };
+ int getFullWidth() const { return fullimage_w; };
+ int getFullHeight() const { return fullimage_h; };
+int getX() const { return x_offset == -1 ? 0 : x_offset; };
+int getY() const { return y_offset == -1 ? 0 : y_offset; };
+ int getBpp() const { return 32; };
+ int getAlpha() const { return has_alpha; };
+ void setHasAlpha(int ha);
+ virtual void *getBits();
+ int isInvalid();
+
+ const wchar_t *getBitmapName();
+
+ void blit(ifc_canvas *canvas, int x, int y);
+ void blitAlpha(ifc_canvas *canvas, int x, int y, int alpha = 255);
+ // blits a chunk of source into dest rect
+ void blitToRect(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha = 255);
+ void blitTile(ifc_canvas *canvas, RECT *dest, int xoffs = 0, int yoffs = 0, int alpha = 255);
+ void blitRectToTile(ifc_canvas *canvas, RECT *dest, RECT *src, int xoffs = 0, int yoffs = 0, int alpha = 255);
+ void stretch(ifc_canvas *canvas, int x, int y, int w, int h);
+ void stretchToRect(ifc_canvas *canvas, RECT *r);
+ void stretchRectToRect(ifc_canvas *canvas, RECT *src, RECT *dst);
+
+ void stretchToRectAlpha(ifc_canvas *canvas, RECT *r, int alpha = 255);
+ void stretchToRectAlpha(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha = 255);
+ ARGB32 getPixel(int x, int y);
+
+private:
+#ifdef _WIN32
+ void bmpToBits(HBITMAP hbmp, HDC defaultDC = NULL);
+#endif
+
+ int has_alpha;
+
+ int x_offset, y_offset, subimage_w, subimage_h, fullimage_w, fullimage_h;
+
+ ARGB32 *bits;
+ int ownbits;
+ int last_failed;
+ StringW bitmapname;
+ int fromskin;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/platform/win32/canvas.h b/Src/Wasabi/api/wnd/platform/win32/canvas.h
new file mode 100644
index 00000000..e6dea753
--- /dev/null
+++ b/Src/Wasabi/api/wnd/platform/win32/canvas.h
@@ -0,0 +1 @@
+#include <tataki/canvas/win/canvas.h>
diff --git a/Src/Wasabi/api/wnd/platform/win32/region.h b/Src/Wasabi/api/wnd/platform/win32/region.h
new file mode 100644
index 00000000..88491634
--- /dev/null
+++ b/Src/Wasabi/api/wnd/platform/win32/region.h
@@ -0,0 +1,135 @@
+#ifndef __REGION_H
+#define __REGION_H
+
+#include <api/wnd/bitmap.h>
+#include <bfc/dispatch.h>
+
+class BaseWnd;
+class Canvas;
+class api_region;
+class RegionServer;
+
+#include "api_region.h"
+
+class RegionI : public api_region
+{
+public:
+ RegionI();
+ RegionI(const RegionI *copy);
+ RegionI(const RECT *r);
+ RegionI(int l, int t, int r, int b);
+ RegionI(OSREGIONHANDLE region);
+ RegionI(SkinBitmap *bitmap, RECT *r=NULL, int xoffset=0, int yoffset=0, bool inverted=false, int dothreshold=0, __int8 threshold=0, int threversed=0, int minalpha=1);
+ RegionI(Canvas *c, RECT *defboundbox=NULL);
+ virtual ~RegionI();
+
+ api_region *clone();
+ void disposeClone(api_region *r);
+ bool ptInRegion(const POINT *pt);
+ void offset(int x, int y);
+ void getBox(RECT *r);
+ void subtractRegion(const api_region *reg);
+ void subtractRect(const RECT *r);
+ void addRect(const RECT *r);
+ void addRegion(const api_region *r);
+ void andRegion(const api_region *r);
+ void setRect(const RECT *r);
+ void empty();
+ int isEmpty();
+ int equals(const api_region *r);
+ int enclosed(const api_region *r, api_region *outside=NULL);
+ int intersectRgn(const api_region *r, api_region *intersection);
+ int doesIntersectRgn(const api_region *r);
+ int intersectRect(const RECT *r, api_region *intersection);
+ int doesIntersectRect(const RECT *r);
+ int isRect();
+ void scale(double sx, double sy, bool round=0);
+ void debug(int async=0);
+
+ // NONPORTABLE
+
+ OSREGIONHANDLE makeWindowRegion(); // gives you a handle to a clone of the OSREGION object so you can insert it into a window's region with SetWindowRgn. ANY other use is prohibited
+ OSREGIONHANDLE getOSHandle(); // avoid as much as you can, should be used only by WIN32-dependant classes
+
+ // END NONPORTABLE
+
+ int getNumRects();
+ int enumRect(int n, RECT *r);
+
+ OSREGIONHANDLE alphaToRegionRect(void *pbits32, int bmX, int bmY, int bmWidth, int bmHeight, int fullw, int fullh, int xoffset, int yoffset, bool portion, int _x, int _y, int _w, int _h, bool inverted, int dothreshold, unsigned __int8 threshold, int thinverse, int minalpha);
+
+private:
+
+ inline void init();
+ void optimize();
+ void deoptimize();
+
+ OSREGIONHANDLE hrgn;
+ OSREGIONHANDLE alphaToRegionRect(SkinBitmap *bitmap, int xoffset, int yoffset, bool portion, int _x, int _y, int _w, int _h, bool inverted=false, int dothreshold=0, unsigned __int8 threshold=0, int thinverse=0, int minalpha=1/* 1..255*/);
+ RECT overlay;
+ int clonecount;
+ RegionI *lastdebug;
+ RegionServer *srv;
+ RECT optrect;
+ int optimized;
+
+protected:
+
+ RECVS_DISPATCH;
+};
+
+class RegionServer : public Dispatchable {
+
+ protected:
+ RegionServer() {}
+ virtual ~RegionServer() {}
+
+ public:
+
+ void addRef(void *client);
+ void delRef(void *client);
+ api_region *getRegion();
+
+ enum {
+ REGIONSERVER_ADDREF = 500,
+ REGIONSERVER_DELREF = 550,
+ REGIONSERVER_GETREGION = 600,
+ };
+};
+
+inline void RegionServer::addRef(void *client) {
+ _voidcall(REGIONSERVER_ADDREF, (api_region *)NULL, client);
+}
+
+inline void RegionServer::delRef(void *client) {
+ _voidcall(REGIONSERVER_DELREF, client);
+}
+
+inline api_region * RegionServer::getRegion() {
+ return _call(REGIONSERVER_GETREGION, (api_region *)NULL);
+}
+
+class RegionServerI : public RegionServer {
+ public :
+
+ RegionServerI() { numrefs = 0; }
+ virtual ~RegionServerI() {}
+
+ virtual void addRef(void *client) { numrefs++; }
+ virtual void delRef(void *client) { numrefs--; }
+ virtual api_region *getRegion()=0;
+
+ virtual int getNumRefs() { return numrefs; }
+
+ protected:
+
+ RECVS_DISPATCH;
+
+ private:
+
+ int numrefs;
+};
+
+#endif
+
+
diff --git a/Src/Wasabi/api/wnd/popexitcb.cpp b/Src/Wasabi/api/wnd/popexitcb.cpp
new file mode 100644
index 00000000..45c9b8b2
--- /dev/null
+++ b/Src/Wasabi/api/wnd/popexitcb.cpp
@@ -0,0 +1,8 @@
+#include <precomp.h>
+#include "popexitcb.h"
+
+#define CBCLASS PopupExitCallbackI
+START_DISPATCH;
+ CB(POPUPEXIT_ONEXITPOPUP, popupexitcb_onExitPopup);
+ CB(POPUPEXIT_GETDEPENDENCYPTR, popupexit_getDependencyPtr);
+END_DISPATCH;
diff --git a/Src/Wasabi/api/wnd/popexitcb.h b/Src/Wasabi/api/wnd/popexitcb.h
new file mode 100644
index 00000000..bbd9de0d
--- /dev/null
+++ b/Src/Wasabi/api/wnd/popexitcb.h
@@ -0,0 +1,40 @@
+#ifndef _POPUPCB_H
+#define _POPUPCB_H
+
+#include <bfc/common.h>
+#include <bfc/dispatch.h>
+
+class ifc_dependent;
+
+class PopupExitCallback : public Dispatchable {
+ public:
+
+ int popupexitcb_onExitPopup();
+ ifc_dependent *popupexit_getDependencyPtr();
+
+ enum {
+ POPUPEXIT_ONEXITPOPUP=100,
+ POPUPEXIT_GETDEPENDENCYPTR=110,
+ };
+};
+
+inline int PopupExitCallback::popupexitcb_onExitPopup() {
+ return _call(POPUPEXIT_ONEXITPOPUP, 0);
+}
+
+inline ifc_dependent *PopupExitCallback::popupexit_getDependencyPtr() {
+ return _call(POPUPEXIT_GETDEPENDENCYPTR, (ifc_dependent *)NULL);
+}
+
+class PopupExitCallbackI : public PopupExitCallback {
+ public:
+
+ virtual int popupexitcb_onExitPopup()=0;
+ virtual ifc_dependent *popupexit_getDependencyPtr()=0;
+
+ protected:
+
+ RECVS_DISPATCH;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/popexitchecker.cpp b/Src/Wasabi/api/wnd/popexitchecker.cpp
new file mode 100644
index 00000000..31ec91a6
--- /dev/null
+++ b/Src/Wasabi/api/wnd/popexitchecker.cpp
@@ -0,0 +1,79 @@
+#include <precomp.h>
+#include "popexitchecker.h"
+#include <api/wnd/popexitcb.h>
+#include <api/wnd/api_window.h>
+#include <api/syscb/callbacks/syscbi.h>
+#include <api/wnd/wndtrack.h>
+
+//PopupExitChecker *popupExitChecker;
+
+PopupExitChecker::PopupExitChecker() {
+}
+
+PopupExitChecker::~PopupExitChecker() {
+ watchers.deleteAll();
+}
+
+void PopupExitChecker::registerCallback(PopupExitCallback *cb, ifc_window *watched) {
+ ifc_dependent *a = cb->popupexit_getDependencyPtr();
+ ifc_dependent *b = watched->getDependencyPtr();
+ watchers.addItem(new PopupExitCallbackEntry(cb, watched, a, b));
+ viewer_addViewItem(a);
+ viewer_addViewItem(b);
+}
+
+int PopupExitChecker::check(ifc_window *w) {
+ int n=0;
+ foreach(watchers)
+ PopupExitCallbackEntry *e = watchers.getfor();
+ if (w != e->watched && !isGrandChildren(e->watched, w)) {
+ e->cb->popupexitcb_onExitPopup();
+ n++;
+ }
+ endfor;
+ return n > 0;
+}
+
+void PopupExitChecker::signal() {
+ foreach(watchers)
+ watchers.getfor()->cb->popupexitcb_onExitPopup();
+ endfor;
+}
+
+int PopupExitChecker::isGrandChildren(ifc_window *parent, ifc_window *child) {
+ int i;
+ for (i=0;i<parent->getNumRootWndChildren();i++) {
+ if (parent->enumRootWndChildren(i) == child) return 1;
+ }
+
+ for (i=0;i<parent->getNumRootWndChildren();i++) {
+ ifc_window *w = parent->enumRootWndChildren(i);
+ int r = 0;
+ if (w->getNumRootWndChildren() > 0) r = isGrandChildren(w, child);
+ if (r) return 1;
+ }
+ return 0;
+}
+
+int PopupExitChecker::viewer_onItemDeleted(ifc_dependent *item) {
+ for (int i=0;i<watchers.getNumItems();i++) {
+ PopupExitCallbackEntry *e = watchers.enumItem(i);
+ if (e->cbd == item || e->wd == item) {
+ watchers.removeByPos(i); i--;
+ delete e;
+ // no break, wnd can be watched by many people
+ }
+ }
+ return 0;
+}
+
+void PopupExitChecker::deregisterCallback(PopupExitCallback *cb) {
+ for (int i=0;i<watchers.getNumItems();i++) {
+ PopupExitCallbackEntry *e = watchers.enumItem(i);
+ if (e->cb == cb) {
+ watchers.removeByPos(i); i--;
+ delete e;
+ // no break, watcher can watch many windows, but wait, there cannot be 2 popups at once on a screen! who says so ?
+ }
+ }
+}
diff --git a/Src/Wasabi/api/wnd/popexitchecker.h b/Src/Wasabi/api/wnd/popexitchecker.h
new file mode 100644
index 00000000..861aa592
--- /dev/null
+++ b/Src/Wasabi/api/wnd/popexitchecker.h
@@ -0,0 +1,39 @@
+#ifndef __POPUPEXITCHECKER_H
+#define __POPUPEXITCHECKER_H
+
+#include <bfc/depend.h>
+#include <bfc/ptrlist.h>
+
+class ifc_window;
+class PopupExitCallback;
+
+class PopupExitCallbackEntry
+{
+public:
+ PopupExitCallbackEntry(PopupExitCallback *_cb, ifc_window *_watched, api_dependent *_cbd, api_dependent *_wd) : cb(_cb), watched(_watched), cbd(_cbd), wd(_wd) {}
+ virtual ~PopupExitCallbackEntry() {}
+
+ PopupExitCallback *cb;
+ ifc_window *watched;
+ api_dependent *cbd;
+ api_dependent *wd;
+};
+
+class PopupExitChecker : public DependentViewerI
+{
+public:
+ PopupExitChecker();
+ virtual ~PopupExitChecker();
+
+ void registerCallback(PopupExitCallback *cb, ifc_window *watched);
+ void deregisterCallback(PopupExitCallback *cb);
+#undef check
+ int check(ifc_window *w);
+ void signal();
+ int isGrandChildren(ifc_window *parent, ifc_window *child); // recursive
+ PtrList<PopupExitCallbackEntry> watchers;
+
+ virtual int viewer_onItemDeleted(api_dependent *item);
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/popup.cpp b/Src/Wasabi/api/wnd/popup.cpp
new file mode 100644
index 00000000..1019fa91
--- /dev/null
+++ b/Src/Wasabi/api/wnd/popup.cpp
@@ -0,0 +1,1720 @@
+#include <precomp.h>
+#include <api/wnd/api_window.h>
+#include <api/locales/xlatstr.h>
+
+#ifndef WASABI_WANT_FF_POPUP
+
+#include "popup.h"
+#ifdef _WIN32
+#include "../../../Plugins/General/gen_ff/wa2frontend.h"
+extern HINSTANCE hInstance;
+#endif
+PopupMenu::PopupMenu()
+{
+ hmenu = NULL;
+ parent = NULL;
+}
+
+PopupMenu::PopupMenu(ifc_window *_parent)
+{
+ hmenu = NULL;
+ parent = _parent;
+}
+
+PopupMenu::PopupMenu(PopupMenu *_parent)
+{
+ hmenu = NULL;
+ parent = _parent->getParent();
+}
+
+PopupMenu::~PopupMenu()
+{
+ invalidateMenu();
+ entries.deleteAll();
+ sortedentries.removeAll();
+}
+
+void PopupMenu::addSubMenu(PopupMenu *menu, const wchar_t *text, int disabled)
+{
+ invalidateMenu();
+ PopupMenuEntry *e = new PopupMenuEntry(text, -1, menu, 0, disabled);
+ entries.addItem(e);
+ sortedentries.addItem(e);
+}
+
+void PopupMenu::addSubMenuCallback(const wchar_t *text, PopupMenuCallback *cb, int param)
+{
+ invalidateMenu();
+ PopupMenuEntry *e = new PopupMenuEntry(text, -1, NULL, 0, 0, cb, param);
+ entries.addItem(e);
+ sortedentries.addItem(e);
+}
+
+void PopupMenu::addCommand(const wchar_t *text, int command, int checked, int disabled, int addpos)
+{
+ invalidateMenu();
+ PopupMenuEntry *e = new PopupMenuEntry(text, command, NULL, checked, disabled);
+ entries.addItem(e);
+ sortedentries.addItem(e, addpos);
+}
+
+void PopupMenu::addSeparator(int addpos)
+{
+ invalidateMenu();
+ PopupMenuEntry *e = new PopupMenuEntry(NULL, -1, NULL, 0, 0);
+ entries.addItem(e);
+ sortedentries.addItem(e, addpos);
+};
+
+void PopupMenu::checkCommand(int cmd, int check)
+{
+ invalidateMenu();
+ PopupMenuEntry *e = sortedentries.findItem((const wchar_t *) & cmd);
+ if (e) e->setChecked(check);
+}
+
+void PopupMenu::disableCommand(int cmd, int disable)
+{
+ invalidateMenu();
+ PopupMenuEntry *e = sortedentries.findItem((const wchar_t *) & cmd);
+ if (e) e->setDisabled(disable);
+}
+
+int PopupMenu::popAtXY(int x, int y, int native)
+{
+ rebuildMenu();
+#ifdef _WIN32
+ if (!native)
+ return DoTrackPopup(getOSMenuHandle(), TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, (parent ? parent->gethWnd() : WASABI_API_WND->main_getRootWnd()->gethWnd())) - 1;
+ else
+ return TrackPopupMenuEx(getOSMenuHandle(), TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, (parent ? parent->gethWnd() : WASABI_API_WND->main_getRootWnd()->gethWnd()), NULL) - 1;
+#elif defined(__APPLE__)
+ return PopUpMenuSelect(getOSMenuHandle(), x, y, 0);
+#endif
+}
+
+int PopupMenu::popAnchored(int type)
+{ // dropped off the sourceWnd given above
+#ifdef _WIN32
+ int flag = 0;
+ switch (type)
+ {
+ case POPUP_ANCHOR_UL: flag |= TPM_LEFTALIGN | TPM_TOPALIGN; break;
+ case POPUP_ANCHOR_LL: flag |= TPM_LEFTALIGN | TPM_BOTTOMALIGN; break;
+ case POPUP_ANCHOR_UR: flag |= TPM_RIGHTALIGN | TPM_TOPALIGN; break;
+ case POPUP_ANCHOR_LR: flag |= TPM_RIGHTALIGN | TPM_BOTTOMALIGN; break;
+ }
+#endif
+ rebuildMenu();
+ int x, y;
+ Wasabi::Std::getMousePos(&x, &y);
+ #ifdef _WIN32
+ return DoTrackPopup(getOSMenuHandle(), flag | TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, (parent ? parent->gethWnd() : WASABI_API_WND->main_getRootWnd()->gethWnd())) - 1;
+#elif defined(__APPLE__)
+ return PopUpMenuSelect(getOSMenuHandle(), x, y, 0);
+#endif
+}
+
+int PopupMenu::popAtMouse()
+{
+ rebuildMenu();
+ int x, y;
+ Wasabi::Std::getMousePos(&x, &y);
+#ifdef _WIN32
+ return DoTrackPopup(getOSMenuHandle(), TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, (parent ? parent->gethWnd() : WASABI_API_WND->main_getRootWnd()->gethWnd())) - 1;
+#elif defined(__APPLE__)
+ return PopUpMenuSelect(getOSMenuHandle(), x, y, 0);
+#endif
+}
+
+int PopupMenu::getNumCommands()
+{
+ return entries.getNumItems();
+}
+
+const wchar_t *PopupMenu::getCommandText(int command)
+{
+ PopupMenuEntry *e = sortedentries.findItem((const wchar_t *) &command);
+ if (e) return e->getText();
+ return NULL;
+}
+
+OSMENUHANDLE PopupMenu::getOSMenuHandle()
+{
+ rebuildMenu();
+ return hmenu;
+}
+
+void PopupMenu::rebuildMenu()
+{
+#ifdef WIN32
+ if (hmenu != NULL) return ;
+ hmenu = CreatePopupMenu();
+ int i = 0;
+ foreach(entries)
+ PopupMenuEntry *e = entries.getfor();
+ OSMENUHANDLE submenu = NULL;
+ if (e->getCallback())
+ {
+ PopupMenu *m = e->getCallback()->popupMenuCallback(this, e->getCallbackParam());
+ if (m) submenu = m->getOSMenuHandle();
+ }
+ else if (e->isSubmenu())
+ {
+ submenu = e->getSubmenu()->getOSMenuHandle();
+ }
+ InsertMenuW(hmenu, i++, MF_BYPOSITION | (e->getChecked() ? MF_CHECKED : MF_UNCHECKED) | (e->getDisabled() ? MF_GRAYED : 0) | (e->isSeparator() ? MF_SEPARATOR : (e->isSubmenu() ? MF_POPUP : 0) | (e->getText() ? MF_STRING : 0)), e->isSubmenu() ? (UINT_PTR)submenu : e->getCommand() + 1, e->getText());
+ endfor;
+#else
+ if (hmenu != NULL) return ;
+ CreateNewMenu(0, 0, &hmenu);
+
+ foreach(entries)
+ PopupMenuEntry *e = entries.getfor();
+ OSMENUHANDLE submenu = NULL;
+ if (e->getCallback())
+ {
+ PopupMenu *m = e->getCallback()->popupMenuCallback(this, e->getCallbackParam());
+ if (m) submenu = m->getOSMenuHandle();
+ }
+ else if (e->isSubmenu())
+ {
+ submenu = e->getSubmenu()->getOSMenuHandle();
+ }
+
+ const wchar_t *name = e->getText();
+ CFStringRef menuStr = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)name, wcslen(name)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
+ MenuItemIndex newMenuItem;
+ MenuItemAttributes menuAttr = kMenuItemAttrIgnoreMeta;
+ if (e->getDisabled())
+ menuAttr|=kMenuItemAttrDisabled;
+ if (e->isSeparator())
+ menuAttr|=kMenuItemAttrSeparator;
+
+ AppendMenuItemTextWithCFString(hmenu, menuStr, menuAttr, e->getCommand(), &newMenuItem);
+ if (submenu)
+ SetMenuItemHierarchicalMenu(hmenu, newMenuItem, submenu);
+
+ if (e->getChecked())
+ CheckMenuItem(hmenu, newMenuItem, true);
+
+ CFRelease(menuStr);
+ endfor;
+#endif
+}
+
+void PopupMenu::invalidateMenu()
+{
+#ifdef WIN32
+ if (hmenu) DestroyMenu(hmenu);
+#elif defined(__APPLE__)
+ if (hmenu) DisposeMenu(hmenu);
+#endif
+ hmenu = NULL;
+}
+
+void PopupMenu::abort()
+{
+#ifdef WIN32
+ HWND w = (parent ? parent->gethWnd() : WASABI_API_WND->main_getRootWnd()->gethWnd());
+
+ PostMessage(w, WM_LBUTTONDOWN, 0, 0xdeadc0de);
+ PostMessage(w, WM_LBUTTONUP, 0, 0xdeadc0de);
+
+#elif defined(__APPLE__)
+ CancelMenuTracking(hmenu, true, 0);
+#endif
+}
+
+#else // WASABI_WANT_FF_POPUP
+
+#include <bfc/api/api_wnd.h>
+#include <bfc/api/api_syscb.h>
+#include "popup.h"
+#include <bfc/notifmsg.h>
+
+#include <studio/assert.h>
+#include <studio/api.h>
+
+#include <bfc/wasabi_std.h>
+#include <common/xlatstr.h>
+#include <bfc/wnds/buttwnd.h>
+
+#include <bfc/util/pathparse.h>
+#include <bfc/attribs/cfgitem.h>
+
+#include <common/script/c_script/c_guiobject.h>
+#include <common/script/c_script/c_menubutton.h>
+#include <common/script/scriptguid.h>
+#include <common/menusurface.h>
+
+#ifndef WANT_NEW_POPUPMENU
+#define SELMARGIN 1
+
+// todo:
+// check marks
+// more?
+
+PopupMenu::PopupMenu(ifc_window *sourceWnd)
+{
+ ASSERT(sourceWnd != NULL);
+ setStartHidden(1);
+ setRenderRatio(1.0);
+ parentRootWnd = sourceWnd;
+ parentWnd = sourceWnd->getOsWindowHandle();
+ reverse_side = 0;
+ kbdhooked = 0;
+ keyctrl = 0;
+ toplevelmenu = 0;
+ chainmenu = NULL;
+ lastxy.x = lastxy.y = -1;
+ WASABI_API_WND->appdeactivation_push_disallow(this);
+ init(sourceWnd->getOsModuleHandle(), parentWnd, TRUE);
+ WASABI_API_WND->appdeactivation_pop_disallow(this);
+}
+
+PopupMenu::PopupMenu()
+{
+ setStartHidden(1);
+ setRenderRatio(1.0);
+ parentRootWnd = NULL;
+ parentWnd = INVALIDOSWINDOWHANDLE;
+ chainmenu = NULL;
+ reverse_side = 0;
+ kbdhooked = 0;
+ toplevelmenu = 0;
+ keyctrl = 0;
+ lastxy.x = lastxy.y = -1;
+ WASABI_API_WND->appdeactivation_push_disallow(this);
+ init(hInstance, WASABI_API_WND->main_getRootWnd()->gethWnd(), TRUE);
+ WASABI_API_WND->appdeactivation_pop_disallow(this);
+}
+
+PopupMenu::PopupMenu(HWND sourceWnd)
+{
+ parentRootWnd = NULL;
+ parentWnd = sourceWnd;
+ setStartHidden(1);
+ setRenderRatio(1.0);
+ reverse_side = 0;
+ kbdhooked = 0;
+ toplevelmenu = 0;
+ keyctrl = 0;
+ chainmenu = NULL;
+ lastxy.x = lastxy.y = -1;
+ WASABI_API_WND->appdeactivation_push_disallow(this);
+ init(hInstance, sourceWnd, TRUE);
+ WASABI_API_WND->appdeactivation_pop_disallow(this);
+}
+
+PopupMenu::PopupMenu(PopupMenu *sourceWnd)
+{
+ parentRootWnd = sourceWnd;
+ parentWnd = sourceWnd->gethWnd();
+ setStartHidden(1);
+ setRenderRatio(1.0);
+ reverse_side = 0;
+ kbdhooked = 0;
+ toplevelmenu = 0;
+ chainmenu = NULL;
+ keyctrl = 0;
+ lastxy.x = lastxy.y = -1;
+ WASABI_API_WND->appdeactivation_push_disallow(this);
+ init(sourceWnd, TRUE);
+ WASABI_API_WND->appdeactivation_pop_disallow(this);
+}
+
+int PopupMenu::onInit()
+{
+ POPUPMENU_PARENT::onInit();
+ bdown = 0;
+ lastitem = -1;
+ rcp = 0;
+ openmenuid = -1;
+ timerset = 0;
+ timeritem = -1;
+ rcode = -1;
+ toplevelmenu = 0;
+ disable_autopop = 0;
+ popupdelay = 250; //TODO: Config
+#ifdef WASABI_COMPILE_CONFIG
+ // {9149C445-3C30-4e04-8433-5A518ED0FDDE}
+ const GUID uioptions_guid =
+ { 0x9149c445, 0x3c30, 0x4e04, { 0x84, 0x33, 0x5a, 0x51, 0x8e, 0xd0, 0xfd, 0xde } };
+ setTransparency(_intVal(WASABI_API_CONFIG->config_getCfgItemByGuid(uioptions_guid), "Popup menu alpha", 255));
+#else
+setTransparency(255);
+#endif
+
+ tex = "wasabi.popup.menu.background";
+ ful = "wasabi.popup.menu.border.topLeft";
+ fur = "wasabi.popup.menu.border.topRight";
+ fll = "wasabi.popup.menu.border.bottomLeft";
+ flr = "wasabi.popup.menu.border.bottomRight";
+ fl = "wasabi.popup.menu.border.left";
+ fr = "wasabi.popup.menu.border.right";
+ ft = "wasabi.popup.menu.border.top";
+ fb = "wasabi.popup.menu.border.bottom";
+ sl = "wasabi.popup.menu.selection.left";
+ sr = "wasabi.popup.menu.selection.right";
+ sc = "wasabi.popup.menu.selection.center";
+
+ return 1;
+}
+
+PopupMenu::~PopupMenu()
+{
+ if (kbdhooked)
+ {
+ WASABI_API_WND->unhookKeyboard(this);
+ kbdhooked = 0;
+ }
+ int x, n;
+ n = items.getNumItems();
+ for (x = 0; x < n; x ++)
+ {
+ if (items[x])
+ {
+ if (items[x]->butt) delete items[x]->butt;
+ if (items[x]->menu) delete items[x]->menu;
+ delete items[x];
+ }
+ }
+}
+
+void PopupMenu::addSubMenu(PopupMenu *menu, const wchar_t *text, int disabled)
+{
+ ASSERT(text != NULL);
+ ButtonWnd *b = new ButtonWnd();
+ b->init(this);
+ b->setParent(this);
+ b->setNotifyId( -1);
+ b->setButtonText(translateButtonText(text), 14);
+ // b->setTextJustification(BUTTONJUSTIFY_LEFT);
+ b->setTextAlign(TEXTALIGN_LEFT);
+ b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText");
+ if (disabled) b->enableButton(FALSE);
+ ItemT *t = new ItemT;
+ t->issep = 0;
+ t->butt = b;
+ t->menu = menu;
+ t->cmd = -1;
+ t->cb = NULL;
+ items.addItem(t);
+}
+
+void PopupMenu::addSubMenuImage(PopupMenu *menu, const char *bitmap, const char *pushedbitmap, const char *highlightbitmap)
+{
+ ButtonWnd *b = new ButtonWnd();
+ b->init(this);
+ b->setParent(this);
+ b->setBitmaps(bitmap, pushedbitmap, highlightbitmap);
+ b->setBitmapCenter(1);
+ b->setNotifyId( -1);
+ b->setAutoDim(1);
+ b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText");
+ ItemT *t = new ItemT;
+ t->issep = 0;
+ t->butt = b;
+ t->menu = menu;
+ t->cb = NULL;
+ t->cmd = -1;
+ items.addItem(t);
+}
+
+void PopupMenu::addSubMenuCallback(const wchar_t *text, PopupMenuCallback *cb, int param)
+{
+ ASSERT(text != NULL);
+ ASSERT(cb != NULL);
+ ButtonWnd *b = new ButtonWnd();
+ b->init(this);
+ b->setParent(this);
+ b->setNotifyId( -1);
+ b->setButtonText(translateButtonText(text), 14);
+ // b->setTextJustification(BUTTONJUSTIFY_LEFT);
+ b->setTextAlign(TEXTALIGN_LEFT);
+ b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText");
+ ItemT *t = new ItemT;
+ t->issep = 0;
+ t->butt = b;
+ t->menu = 0;
+ t->cb = cb;
+ t->cbparam = param;
+ t->cmd = -1;
+ items.addItem(t);
+}
+
+void PopupMenu::addSeparator(int addpos)
+{
+ ButtonWnd *b = new ButtonWnd();
+ b->init(this);
+ b->setParent(this);
+ b->setNotifyId( -1);
+ b->setBitmaps("wasabi.popup.menu.seperator");
+ b->setBitmapCenter(0);
+ b->enableButton(0);
+ b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText");
+ ItemT *t = new ItemT;
+ t->issep = 1;
+ t->butt = b;
+ t->menu = 0;
+ t->cb = NULL;
+ t->cmd = -1;
+ items.addItem(t, addpos);
+}
+
+void PopupMenu::addCommandImage(const char *bitmap, const char *pushedbitmap, const char *highlightbitmap, int command, int checked, int disabled, int addpos)
+{
+ ButtonWnd *b = new ButtonWnd();
+ b->init(this);
+ b->setParent(this);
+ b->setBitmaps(bitmap, pushedbitmap, highlightbitmap);
+ b->setBitmapCenter(1);
+ b->setNotifyId(command);
+ b->enableButton(disabled ? 0 : 1);
+ b->setChecked(checked ? 1 : 0);
+ b->setAutoDim(1);
+ b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText");
+ ItemT *t = new ItemT;
+ t->issep = 0;
+ t->butt = b;
+ t->menu = 0;
+ t->cb = NULL;
+ t->cmd = -1;
+ items.addItem(t);
+}
+
+void PopupMenu::addCommand(const wchar_t *_txt, int command, int checked, int disabled, int addpos)
+{
+ if (!_txt)
+ {
+ addSeparator();
+ return ;
+ }
+ String txt = translateButtonText(_txt);
+ ButtonWnd *b = new ButtonWnd();
+ b->init(this);
+ b->setParent(this);
+ b->setNotifyId(disabled ? -1 : command);
+
+#ifdef WASABI_COMPILE_LOCALES
+ const wchar_t *bind = (command != 0) ? WASABI_API_LOCALE->locales_getBindFromAction(command) : NULL;
+ if (bind) txt += StringPrintfW(L"\t%s", bind);
+#endif
+
+ b->setButtonText(txt);
+
+ // b->setTextJustification(BUTTONJUSTIFY_LEFT);
+ b->setTextAlign(TEXTALIGN_LEFT);
+ b->enableButton(disabled ? 0 : 1);
+ b->setChecked(checked);
+ if (checked == 2) b->setAlpha(128);
+ b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText");
+ ItemT *t = new ItemT;
+ t->issep = 0;
+ t->butt = b;
+ t->menu = 0;
+ t->cmd = command;
+ t->cb = NULL;
+ ASSERT(PTRLIST_POS_LAST == -1); //BU
+ items.addItem(t, addpos);
+}
+
+void PopupMenu::disableCommand(int cmd, int disable)
+{
+ for (int i = 0;i < items.getNumItems();i++)
+ if (items.enumItem(i)->cmd == cmd)
+ {
+ if (items.enumItem(i)->butt)
+ items.enumItem(i)->butt->enableButton(!!!disable);
+ break;
+ }
+}
+
+void PopupMenu::checkCommand(int cmd, int check)
+{
+ for (int i = 0;i < items.getNumItems();i++)
+ if (items.enumItem(i)->cmd == cmd)
+ {
+ if (items.enumItem(i)->butt)
+ items.enumItem(i)->butt->setChecked(check);
+ break;
+ }
+}
+
+const wchar_t *PopupMenu::getCommandText(int command)
+{
+ for (int i = 0;i < items.getNumItems();i++)
+ if (items.enumItem(i)->cmd == command && items.enumItem(i)->butt)
+ return items.enumItem(i)->butt->getName();
+ return NULL;
+}
+
+int PopupMenu::popAtXY(int x, int y)
+{
+ toplevelmenu = 1;
+ rcode = -1;
+ if (items.getNumItems())
+ {
+ POINT pt = {x, y};
+
+#ifdef WIN32
+ HWND oldcw = GetCapture(); // nonportable
+ ifc_window *oldcrw = (ifc_window*)GetWindowLong(oldcw, GWL_USERDATA);
+ if (oldcrw != NULL) oldcrw->cancelCapture();
+#endif
+
+ WASABI_API_SYSCB->syscb_registerCallback(static_cast<SkinCallbackI*>(this));
+
+ showAtXY(x, y, &rcode);
+ beginCapture();
+
+ MSG msg;
+
+#ifdef WIN32
+ SetCursor(LoadCursor(NULL, IDC_ARROW)); // NONPORTABLE
+#endif
+ while (rcode == -1 && GetMessage( &msg, INVALIDOSWINDOWHANDLE, 0, 0 ))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ endCapture();
+ hide();
+
+ // if (hadcapture && under) under->beginCapture();
+
+#ifdef WIN32
+ if (rcode == -2 || rcode == -3)
+ {
+ DWORD p = GetMessagePos();
+ POINT pt;
+ pt.x = (signed short)LOWORD(p);
+ pt.y = (signed short)HIWORD(p);
+ HWND w = WindowFromPoint(pt);
+ ScreenToClient(w, &pt);
+ p = (pt.x & 0xFFFF) | (pt.y << 16);
+ //if (under) under->getRootParent()->wndProc(under->getRootParent()->gethWnd(), WM_MOUSEMOVE, 0, p);
+ //PostMessage(w, (rcode == -2) ? WM_MOUSEMOVE : WM_RBUTTONDOWN, 0, p);
+ //PostMessage(w, (rcode == -2) ? WM_LBUTTONDOWN : WM_RBUTTONDOWN, 0, p);
+ }
+#else
+DebugString("portme: popup.cpp pass on click");
+#endif
+
+ }
+
+ WASABI_API_SYSCB->syscb_deregisterCallback(static_cast<SkinCallbackI*>(this));
+
+ //DebugString("appdeactivation_pop_disallow\n");
+ WASABI_API_WND->appdeactivation_pop_disallow(this);
+
+ onPostPop(rcode);
+
+#ifdef WASABI_COMPILE_SKIN
+ if (!switchskinto.isempty())
+ {
+ WASABI_API_SKIN->skin_switchSkin(switchskinto.getNonConstVal());
+ switchskinto = "";
+ }
+#endif
+
+ return rcode;
+}
+
+void PopupMenu::showAtXY(int x, int y, int *rc, int revside, int parentW)
+{
+ int i, n;
+ int w = 0, h = 0;
+ lastitem = -1;
+ rcp = rc;
+ n = items.getNumItems();
+ for (i = 0; i < n; i ++)
+ {
+ if (items[i]->menu || items[i]->cb)
+ items[i]->butt->setRightBitmap("wasabi.popup.menu.submenu");
+ if (!items[i]->butt->getChecked()) items[i]->butt->setChecked( -1);
+ h += items[i]->butt->getHeight();
+ items[i]->butt->setUseBaseTexture(0);
+ items[i]->butt->setBorders(0);
+ int tw = items[i]->butt->getWidth();
+ if (w < tw)w = tw;
+ }
+ int neww = w + 6 + fl.getWidth() + fr.getWidth();
+ int newh = h + 6 + ft.getHeight() + fb.getHeight();
+
+ POINT p = {x, y};
+ RECT vp;
+ Std::getViewport(&vp, &p);
+
+ // maintain parent's reversal state
+ reverse_side = revside;
+ int savx = x;
+ if (reverse_side) x -= (neww + parentW);
+ if (x + neww > vp.right || x < 0)
+ {
+ reverse_side = !reverse_side;
+ x = savx;
+ if (reverse_side) x -= (neww + parentW);
+ }
+
+ if (y + newh > vp.bottom) y -= newh;
+ if (x < vp.left) x = vp.left;
+ if (y < vp.top) y = vp.top;
+
+ resize(x, y, neww, newh);
+
+ h = 0;
+ for (i = 0; i < n; i ++)
+ {
+ int lh = h;
+ h += items[i]->butt->getHeight();
+ items[i]->butt->resize(3 + fl.getWidth(), 3 + lh + ft.getHeight(), w, h - lh);
+ items[i]->butt->setHilite(0);
+ items[i]->butt->setPushed(0);
+ }
+
+ WASABI_API_WND->appdeactivation_push_disallow(this);
+#ifdef WIN32
+ SetWindowPos(gethWnd(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+#elif defined(LINUX)
+Atom NET_STATE = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE", True );
+Atom state[2];
+state[0] = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE_SKIP_TASKBAR", True );
+state[1] = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE_ABOVE", True );
+
+if ( NET_STATE && state[0] && state[1] )
+{
+ XChangeProperty( Linux::getDisplay(), gethWnd(), NET_STATE, XA_ATOM, 32,
+ PropModeReplace, (unsigned char *)state, 2 );
+}
+#endif
+ WASABI_API_WND->appdeactivation_pop_disallow(this);
+ setVisible(1);
+}
+
+void PopupMenu::onSetVisible(int v)
+{
+ POPUPMENU_PARENT::onSetVisible(v);
+ if (v && !kbdhooked)
+ {
+ WASABI_API_WND->hookKeyboard(this);
+ kbdhooked = 1;
+ }
+ else if (!v && kbdhooked)
+ {
+ WASABI_API_WND->unhookKeyboard(this);
+ kbdhooked = 0;
+ }
+
+}
+
+void PopupMenu::hide()
+{
+ if (lastitem >= 0 && items[lastitem]->menu)
+ {
+ items[lastitem]->menu->hide();
+ lastitem = -1;
+ }
+ setVisible(0);
+}
+
+int PopupMenu::popAnchored(int type)
+{
+ RECT wr;
+ if (parentRootWnd != NULL)
+ {
+ parentRootWnd->getWindowRect(&wr);
+ }
+ else if (parentWnd != INVALIDOSWINDOWHANDLE)
+ {
+#ifdef WIN32
+ GetWindowRect(parentWnd, &wr);
+#else
+DebugString("portme PopupMenu::popAnchored\n");
+#endif
+
+ }
+ else
+ {
+ ASSERTALWAYS("can't call popAnchored without instantiating with a parent window");
+ }
+ switch (type)
+ {
+ case POPUP_ANCHOR_UL: return popAtXY(wr.left, wr.top);
+ case POPUP_ANCHOR_LL: return popAtXY(wr.left, wr.bottom);
+ case POPUP_ANCHOR_UR: return popAtXY(wr.right, wr.top);
+ case POPUP_ANCHOR_LR: return popAtXY(wr.right, wr.bottom);
+ }
+ return 0;
+}
+
+int PopupMenu::popAtMouse()
+{
+ int x, y;
+ Std::getMousePos(&x, &y);
+ return popAtXY(x, y);
+}
+
+int PopupMenu::childNotify(ifc_window *child, int msg, intptr_t p1, intptr_t p2)
+{
+ if (msg == ChildNotify::BUTTON_LEFTPUSH || msg == ChildNotify::BUTTON_RIGHTPUSH)
+ {
+ for (int i = 0;i < items.getNumItems();i++)
+ {
+ if (child == items[i]->butt && (items[i]->menu || items[i]->cb))
+ {
+ if (!items[i]->butt->getEnabled()) continue;
+ if (items[i]->cb) initMenuCallback(i);
+ if (!items[i]->menu) continue;
+ if (openmenuid == i) continue;
+ RECT r;
+ if (openmenuid >= 0)
+ {
+ items[openmenuid]->menu->hide();
+ openmenuid = -1;
+ }
+ items[i]->butt->getWindowRect(&r);
+ PopupMenu *p = items[i]->menu;
+ p->showAtXY(r.right, r.top, rcp, reverse_side, r.right - r.left);
+ if (p1)
+ {
+ p->selectFirst();
+ }
+ openmenuid = i;
+ }
+ }
+ // mig: changed this to call getNotifyId();
+ // *rcp=p1;
+ *rcp = child->getNotifyId();
+ return 0;
+ }
+ if (msg == ChildNotify::POPUP_SUBMENUCLOSE)
+ {
+ for (int i = 0;i < items.getNumItems();i++)
+ {
+ if (child == items[i]->menu)
+ {
+ if (openmenuid != i) continue;
+ items[openmenuid]->menu->hide();
+ openmenuid = -1;
+ return 0;
+ }
+ }
+ }
+ return POPUPMENU_PARENT::childNotify(child, msg, p1, p2);
+}
+
+void PopupMenu::selectFirst()
+{
+ ButtonWnd *b = NULL;
+ int i;
+ for (i = 0; i < items.getNumItems(); i++)
+ {
+ b = items.enumItem(i)->butt;
+ if (b != NULL) break;
+ }
+ if (b == NULL) return ;
+ lastitem = i;
+ b->setHilite(1);
+ invalidate();
+}
+
+int PopupMenu::getWhichItem(POINT &p)
+{
+ int x, n;
+ RECT r2;
+ getWindowRect(&r2);
+ n = items.getNumItems();
+ for (x = 0; x < n; x ++)
+ {
+ RECT r;
+ items[x]->butt->getWindowRect(&r);
+ r.right = r2.right;
+ r.left = r2.left;
+ if (Std::pointInRect(r, p))
+ {
+ return x;
+ }
+ }
+ return -1;
+}
+
+int PopupMenu::isMine(int x, int y)
+{
+ RECT r;
+ getWindowRect(&r);
+ POINT p = {x, y};
+ if (Std::pointInRect(r, p)) return 1;
+ if (lastitem >= 0 && items[lastitem]->menu && items[lastitem]->menu->isMine(x, y)) return 1;
+ return 0;
+}
+
+void PopupMenu::setFriendlyId(const char *id)
+{
+ friendid = id;
+}
+
+int PopupMenu::onLeftButtonDown(int x, int y)
+{
+ clientToScreen(&x, &y);
+ onButtonDown(1, x, y);
+ return 0;
+}
+
+int PopupMenu::onRightButtonDown(int x, int y)
+{
+ clientToScreen(&x, &y);
+ onButtonDown(2, x, y);
+ return 0;
+}
+
+int PopupMenu::onMouseMove(int x, int y)
+{
+ POPUPMENU_PARENT::onMouseMove(x, y);
+ POINT pnt = {x, y};
+ clientToScreen(&pnt);
+
+ if (keyctrl && lastxy.x == pnt.x && lastxy.y == pnt.y) return 1;
+ keyctrl = 0;
+ lastxy = pnt;
+
+ if (lastitem >= 0)
+ {
+ if (openmenuid >= 0 && items[openmenuid]->menu && items[openmenuid]->menu->isMine(pnt.x, pnt.y))
+ {
+ if (lastitem != openmenuid)
+ {
+ items[lastitem]->butt->setHilite(0);
+ items[lastitem]->butt->setPushed(0);
+ items[openmenuid]->butt->setHilite(1);
+ items[openmenuid]->butt->setPushed(1);
+ invalidateItem(lastitem);
+ lastitem = openmenuid;
+ invalidateItem(lastitem);
+ }
+ resetTimer( -1);
+ items[openmenuid]->menu->screenToClient(&pnt);
+ items[openmenuid]->menu->onMouseMove(pnt.x, pnt.y);
+ return 0;
+ }
+ }
+
+ int p = getWhichItem(pnt);
+ if (p >= 0)
+ {
+ ItemT *it = items[p];
+ if (!it->issep)
+ {
+ if (p != lastitem)
+ {
+ if (lastitem >= 0)
+ {
+ /* if (items[lastitem]->menu)
+ {
+ items[lastitem]->menu->hide();
+ }*/
+ items[lastitem]->butt->setHilite(0);
+ items[lastitem]->butt->setPushed(0);
+ invalidateItem(lastitem);
+ }
+ invalidateItem(lastitem);
+ lastitem = p;
+ invalidateItem(lastitem);
+ items[p]->butt->setHilite(1);
+ if (bdown) items[p]->butt->setPushed(1);
+ /* if (items[p]->menu) {
+ RECT r;
+ items[p]->butt->getWindowRect(&r);
+ items[p]->menu->showAtXY(r.right,r.top,rcp);
+ }*/
+ resetTimer(p);
+ invalidateItem(lastitem);
+ }
+ }
+ else
+ {
+ RECT _r;
+ getClientRect(&_r);
+ int inside = (x >= 0 && y >= 0 && x <= _r.right - _r.left && y <= _r.bottom - _r.top);
+ if (lastitem >= 0 && !inside)
+ {
+ items[lastitem]->butt->setHilite(0);
+ items[lastitem]->butt->setPushed(0);
+ invalidateItem(lastitem);
+ lastitem = -1;
+ }
+ }
+ }
+ else
+ {
+ if (!friendid.isempty())
+ {
+ ifc_window *w = WASABI_API_WND->rootWndFromPoint(&pnt);
+ if (w != NULL)
+ {
+ MenuButtonSurface *s = static_cast<MenuButtonSurface *>(w->getInterface(menuButtonSurfaceGuid));
+ if (s != NULL)
+ {
+ if (s->getParentWnd() != parentRootWnd)
+ {
+ const char *str = s->getParentMenuId();
+ if (STRCASEEQLSAFE(str, friendid))
+ {
+ abort();
+ rcode = -4;
+ chainmenu = s;
+ }
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void PopupMenu::resetTimer(int p)
+{
+ if (timerset)
+ {
+ killTimer(POPUP_TIMERID);
+ timeritem = -1;
+ }
+ if (p >= 0 && !disable_autopop)
+ {
+ setTimer(POPUP_TIMERID, popupdelay);
+ timeritem = p;
+ timerset = 1;
+ }
+}
+
+void PopupMenu::timerCallback(int id)
+{
+ switch (id)
+ {
+ case POPUP_TIMERID:
+ killTimer(POPUP_TIMERID);
+ timerset = 0;
+ if (timeritem == openmenuid)
+ {
+ timeritem = -1;
+ break;
+ }
+ if (openmenuid >= 0 && items[openmenuid]->menu)
+ {
+ items[openmenuid]->menu->hide();
+ openmenuid = -1;
+ }
+ if (timeritem >= 0)
+ {
+ if (items[timeritem]->cb) initMenuCallback(timeritem);
+ if (items[timeritem]->butt->getEnabled() && items[timeritem]->menu)
+ {
+ RECT r;
+ items[timeritem]->butt->getWindowRect(&r);
+ items[timeritem]->menu->showAtXY(r.right, r.top, rcp, reverse_side, r.right - r.left);
+ openmenuid = timeritem;
+ }
+ timeritem = -1;
+ }
+ break;
+ default:
+ POPUPMENU_PARENT::timerCallback(id);
+ break;
+ }
+}
+
+void PopupMenu::initMenuCallback(int item)
+{
+ int a = rcode;
+ rcode = 0;
+ PopupMenu *p = items[item]->cb->popupMenuCallback(this, items[item]->cbparam);
+ rcode = a;
+ if (p)
+ {
+ items[item]->cb = NULL;
+ items[item]->menu = p;
+ }
+}
+
+int PopupMenu::onLeftButtonUp(int x, int y)
+{
+ clientToScreen(&x, &y);
+ onButtonUp(1, x, y);
+ return 0;
+}
+
+int PopupMenu::onRightButtonUp(int x, int y)
+{
+ clientToScreen(&x, &y);
+ onButtonUp(2, x, y);
+ return 0;
+}
+
+void PopupMenu::onButtonDown(int wb, int x, int y)
+{
+ POINT pos = {x, y};
+ RECT r;
+ bdown |= wb;
+ if (lastitem >= 0)
+ {
+ if (items[lastitem]->menu && items[lastitem]->menu->isMine(pos.x, pos.y))
+ {
+ items[lastitem]->menu->onButtonDown(wb, x, y);
+ return ;
+ }
+ }
+ getWindowRect(&r);
+ if (!Std::pointInRect(r, pos))
+ {
+ rcode = (wb == 1) ? -2 : -3;
+ }
+ else
+ {
+ int item = getWhichItem(pos);
+ if (item >= 0) items[item]->butt->setPushed(1);
+ }
+}
+
+void PopupMenu::onButtonUp(int wb, int x, int y)
+{
+ if (lastitem >= 0)
+ {
+ POINT pos = {x, y};
+ if (items[lastitem]->menu && items[lastitem]->menu->isMine(pos.x, pos.y))
+ {
+ items[lastitem]->menu->onButtonUp(wb, x, y);
+ return ;
+ }
+ }
+ if (bdown & wb)
+ {
+ bdown &= ~wb;
+ POINT pnt = {x, y};
+ int p = getWhichItem(pnt);
+ if (p >= 0)
+ {
+ items[p]->butt->onLeftPush(x, y);
+ if (!bdown)
+ {
+ items[p]->butt->setPushed(0);
+ }
+ }
+ }
+}
+
+int PopupMenu::onKillFocus()
+{
+#ifndef LINUX
+ if (rcode == -1) rcode = -2;
+#endif
+ return POPUPMENU_PARENT::onKillFocus();
+}
+
+// only translates the text, not the optional accelerator
+String PopupMenu::translateButtonText(const wchar_t *text)
+{
+ PathParser pp(text, "\t");
+ String ret;
+ for (int i = 0; i < pp.getNumStrings(); i++)
+ {
+ if (i == 0) ret += _(pp.enumString(i)); // translate first
+ else ret += pp.enumString(i);
+ if (i != pp.getNumStrings() - 1) ret += "\t";
+ }
+ return ret;
+}
+
+int PopupMenu::onPaint(Canvas *canvas)
+{
+ PaintBltCanvas paintcanvas;
+ if (canvas == NULL)
+ {
+ if (!paintcanvas.beginPaint(this)) return 0;
+ canvas = &paintcanvas;
+ }
+ POPUPMENU_PARENT::onPaint(canvas);
+
+ RECT r, r2;
+
+ getClientRect(&r);
+ tex.getBitmap()->blitTile(canvas, &r);
+
+ // left side
+ ful.getBitmap()->blitAlpha(canvas, 0, 0);
+
+ r2.left = 0;
+ r2.right = fl.getWidth();
+ r2.top = ful.getHeight();
+ r2.bottom = r.bottom - fll.getHeight();
+ fl.getBitmap()->stretchToRectAlpha(canvas, &r2);
+
+ fll.getBitmap()->blitAlpha(canvas, 0, r.bottom - fll.getHeight());
+
+ // right side
+ fur.getBitmap()->blitAlpha(canvas, r.right - fur.getWidth(), 0);
+
+ r2.left = r.right - fr.getWidth();
+ r2.right = r.right;
+ r2.top = fur.getHeight();
+ r2.bottom = r.bottom - flr.getHeight();
+ fr.getBitmap()->stretchToRectAlpha(canvas, &r2);
+
+ flr.getBitmap()->blitAlpha(canvas, r.right - flr.getWidth(), r.bottom - flr.getHeight());
+
+ // top
+ r2.left = ful.getWidth();
+ r2.right = r.right - fur.getWidth();
+ r2.top = 0;
+ r2.bottom = ft.getHeight();
+ ft.getBitmap()->stretchToRectAlpha(canvas, &r2);
+
+ // bottom
+ r2.left = fll.getWidth();
+ r2.right = r.right - flr.getWidth();
+ r2.top = r.bottom - fb.getHeight();
+ r2.bottom = r.bottom;
+ fb.getBitmap()->stretchToRectAlpha(canvas, &r2);
+
+ // selection bar
+
+ if (lastitem != -1)
+ {
+ ItemT *it = items[lastitem];
+ RECT r3, c;
+
+ it->butt->getClientRect(&r3);
+
+ // left
+ r2.left = r.left + fl.getWidth() + SELMARGIN;
+ r2.top = r.top + r3.top;
+ r2.right = r2.left + sl.getWidth();
+ r2.bottom = r2.top + (r3.bottom - r3.top);
+ sl.getBitmap()->stretchToRectAlpha(canvas, &r2);
+
+ c = r2;
+ c.left = c.right - 1;
+
+ // right
+ r2.right = r.right - fr.getWidth() - SELMARGIN;
+ r2.left = r2.right - sr.getWidth();
+ sr.getBitmap()->stretchToRectAlpha(canvas, &r2);
+
+ c.right = r2.left;
+
+ // center
+ sc.getBitmap()->stretchToRectAlpha(canvas, &c);
+
+ }
+
+ return 1;
+}
+
+void PopupMenu::invalidateItem(int i)
+{
+ if (i < 0 || i >= items.getNumItems()) return ;
+ RECT r, r2, r3;
+ getClientRect(&r);
+
+ ItemT *it = items[i];
+ it->butt->getClientRect(&r3);
+
+ r2.left = r.left + fl.getWidth();
+ r2.top = r.top + r3.top;
+ r2.right = r.right - fl.getWidth();
+ r2.bottom = r2.top + (r3.bottom - r3.top);
+ invalidateRect(&r2);
+}
+
+int PopupMenu::getNumCommands()
+{
+ return items.getNumItems();
+}
+
+#ifdef WASABI_COMPILE_SKIN
+int PopupMenu::skincb_onCheckPreventSwitch(const char *skinname)
+{
+ switchskinto = skinname;
+ rcode = -2;
+ return 1;
+}
+#endif
+
+int PopupMenu::onSysKeyDown(int code, int d)
+{
+ int a = POPUPMENU_PARENT::onSysKeyDown(code, d);
+ /* if (d & (1<<29)) {
+ //ALT key pressed, abort menu (mimics win32 popup behavior)
+ abort();
+ if(getParent()) SendMessageW(getParent()->gethWnd(),WM_SYSKEYDOWN,code,d);
+ return 0;
+ }*/
+ if (a == 0)
+ return onKeyDown(code);
+ return 0;
+}
+
+int PopupMenu::onKeyDown(int code)
+{
+ if (POPUPMENU_PARENT::onKeyDown(code)) return 1;
+ switch (code)
+ {
+ case STDKEY_DOWN:
+ navigate(1);
+ return 1;
+ case STDKEY_UP:
+ navigate( -1);
+ return 1;
+ case STDKEY_RETURN:
+ navigate(0, 1);
+ return 1;
+ case STDKEY_RIGHT:
+ navigate(0, 0);
+ return 1;
+ case VK_LEFT:
+ if (!toplevelmenu)
+ notifyParent(ChildNotify::POPUP_SUBMENUCLOSE);
+ return 1;
+ case VK_ESCAPE:
+ abort();
+ return 1;
+ }
+ return 0;
+}
+
+void PopupMenu::abort()
+{
+ if (toplevelmenu)
+ rcode = -2;
+ else
+ notifyParent(ChildNotify::POPUP_SUBMENUCLOSE);
+}
+
+void PopupMenu::navigate(int p, int f)
+{
+ keyctrl = 1;
+ int i = lastitem;
+
+ ItemT *t = NULL;
+
+ if (p == 0)
+ {
+
+ if (lastitem >= 0)
+ {
+ ItemT *t = items.enumItem(lastitem);
+ if (f || t->menu || t->cb)
+ {
+ t->butt->setHilite(1);
+ t->butt->setPushed(1);
+ childNotify(t->butt, ChildNotify::BUTTON_LEFTPUSH, 1, 0);
+ }
+ }
+ return ;
+ }
+
+ while (!t || t->issep)
+ {
+ i += p;
+ i %= items.getNumItems();
+ if (i == -1) i = items.getNumItems() - 1;
+ if (i >= items.getNumItems()) return ;
+ t = items.enumItem(i);
+ }
+
+ if (t->butt)
+ {
+ int i;
+ i = items.searchItem(t);
+ t->butt->setHilite(1);
+ if (lastitem != -1)
+ {
+ ItemT *s = items.enumItem(lastitem);
+ if (s->butt)
+ {
+ s->butt->setPushed(0);
+ s->butt->setHilite(0);
+ }
+ }
+ lastitem = i;
+ invalidate();
+ }
+}
+
+
+
+
+#else
+
+//------------------------------------------------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------------------------------------------------
+// 3rd level popup menu, yay
+
+#include "script/c_script/c_text.h"
+#include "script/c_script/c_rootobj.h"
+#include "script/c_script/c_button.h"
+#include "script/c_script/c_group.h"
+
+
+PopupMenu::PopupMenu(ifc_window *sourceWnd)
+{
+ ASSERT(sourceWnd != NULL);
+ myInit();
+ setParent(sourceWnd);
+ sourceWnd->setAllowDeactivation(0);
+ init(HINSTANCEfromHWND(getParent()->gethWnd()), sourceWnd->gethWnd(), TRUE);
+ sourceWnd->setAllowDeactivation(1);
+}
+
+PopupMenu::PopupMenu()
+{
+ myInit();
+ setParent(WASABI_API_WND->main_getRootWnd());
+ WASABI_API_WND->main_getRootWnd()->setAllowDeactivation(0);
+ init(hInstance, WASABI_API_WND->main_getRootWnd()->gethWnd(), TRUE);
+ WASABI_API_WND->main_getRootWnd()->setAllowDeactivation(1);
+}
+
+PopupMenu::PopupMenu(PopupMenu *sourceWnd)
+{
+ myInit();
+ setParent(sourceWnd);
+ sourceWnd->setAllowDeactivation(0);
+ init(GetModuleHandle(NULL), sourceWnd->gethWnd(), TRUE);
+ sourceWnd->setAllowDeactivation(1);
+}
+
+void PopupMenu::myInit()
+{
+ setVirtual(0);
+ setStartHidden(1);
+ setRenderRatio(1.0);
+ reverse_side = 0;
+ rcode = 0;
+ submenus = 0;
+ c_grouplist = NULL;
+ WASABI_API_WND->popupexit_register(this, this);
+}
+
+PopupMenu::~PopupMenu()
+{
+ WASABI_API_WND->popupexit_deregister(this);
+ delete c_grouplist;
+}
+
+int PopupMenu::onInit()
+{
+ POPUPMENU_PARENT::onInit();
+#ifdef WASABI_COMPILE_CONFIG
+ // {9149C445-3C30-4e04-8433-5A518ED0FDDE}
+ const GUID uioptions_guid =
+ { 0x9149c445, 0x3c30, 0x4e04, { 0x84, 0x33, 0x5a, 0x51, 0x8e, 0xd0, 0xfd, 0xde } };
+ setTransparency(_intVal(WASABI_API_CONFIG->config_getCfgItemByGuid(uioptions_guid), "Popup menu alpha", 255));
+#else
+setTransparency(255);
+#endif
+
+
+
+ setContent("wasabi.popup.main.group");
+
+ return 1;
+}
+
+int PopupMenu::popAtXY(int x, int y)
+{
+ rcode = -1;
+ if (1 /*items.getNumItems()*/)
+ {
+ POINT pt = {x, y};
+
+ //DebugString("appdeactivation_push_disallow\n");
+ WASABI_API_WND->appdeactivation_push_disallow(this);
+
+ showAtXY(x, y, &rcode);
+
+ //MSG msg;
+ /*while (rcode == -1 && GetMessage( &msg, NULL, 0, 0 )) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }*/
+
+ SetCursor(LoadCursor(NULL, IDC_ARROW)); // NONPORTABLE
+
+ int quit = 0;
+ while (!quit)
+ {
+ rcode = getGuiObject()->guiobject_runModal();
+ if (rcode & 0x40000000 && rcode != -2 && rcode != -1)
+ {
+ int submenuentry = rcode & ~0x40000000;
+ ItemT *t = items.enumItem(submenuentry);
+ if (t->cb != NULL)
+ initMenuCallback(submenuentry);
+ if (t->menu != NULL)
+ {
+ setAllowDeactivation(0);
+ t->menu->showAtXY(0, 0, NULL, 0, 0);
+ setAllowDeactivation(1);
+ }
+ }
+ else
+ quit = 1;
+ }
+
+ setVisible(0);
+ }
+
+ //DebugString("appdeactivation_pop_disallow\n");
+ WASABI_API_WND->appdeactivation_pop_disallow(this);
+
+ onPostPop(rcode);
+
+ return rcode;
+}
+
+void PopupMenu::showAtXY(int x, int y, int *rc, int revside /* =0 */, int parentW /* =0 */)
+{
+ fillContent();
+ int neww = getPreferences(SUGGESTED_W);
+ int newh = getPreferences(SUGGESTED_H);;
+
+ POINT p = {x, y};
+ RECT vp;
+ Std::getViewport(&vp, &p);
+
+ // maintain parent's reversal state
+ reverse_side = revside;
+ int savx = x;
+ if (reverse_side) x -= (neww + parentW);
+ if (x + neww > vp.right || x < 0)
+ {
+ reverse_side = !reverse_side;
+ x = savx;
+ if (reverse_side) x -= (neww + parentW);
+ }
+
+ if (y + newh > vp.bottom) y -= newh;
+ if (x < vp.left) x = vp.left;
+ if (y < vp.top) y = vp.top;
+
+ resize(x, y, neww, newh);
+
+ WASABI_API_WND->appdeactivation_push_disallow(this);
+#ifdef WIN32
+ SetWindowPos(gethWnd(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+#else
+Atom NET_STATE = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE", True );
+Atom state[2];
+state[0] = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE_SKIP_TASKBAR", True );
+state[1] = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE_ABOVE", True );
+
+if ( NET_STATE && state[0] && state[1] )
+{
+ XChangeProperty( Linux::getDisplay(), gethWnd(), NET_STATE, XA_ATOM, 32,
+ PropModeReplace, (unsigned char *)state, 2 );
+}
+#endif
+ WASABI_API_WND->appdeactivation_pop_disallow(this);
+ setVisible(1);
+}
+
+int PopupMenu::popAnchored(int type)
+{
+ RECT wr;
+ getParent()->getWindowRect(&wr);
+ switch (type)
+ {
+ case POPUP_ANCHOR_UL: return popAtXY(wr.left, wr.top);
+ case POPUP_ANCHOR_LL: return popAtXY(wr.left, wr.bottom);
+ case POPUP_ANCHOR_UR: return popAtXY(wr.right, wr.top);
+ case POPUP_ANCHOR_LR: return popAtXY(wr.right, wr.bottom);
+ }
+ return 0;
+}
+
+int PopupMenu::popAtMouse()
+{
+ int x, y;
+ Std::getMousePos(&x, &y);
+ return popAtXY(x, y);
+}
+
+void PopupMenu::onNewContent()
+{
+ POPUPMENU_PARENT::onNewContent();
+ if (isVisible())
+ fillContent();
+}
+
+void PopupMenu::fillContent()
+{
+ GuiObject *grouplist = findObject("popup.content");
+ if (grouplist != NULL)
+ {
+
+ delete c_grouplist;
+
+ c_grouplist = new C_GroupList(*grouplist);
+ c_grouplist->removeAll();
+ c_grouplist->setRedraw(0);
+
+ for (int i = 0;i < items.getNumItems();i++)
+ {
+ addItem(items.enumItem(i));
+ }
+
+ c_grouplist->setRedraw(1);
+ }
+}
+
+void PopupMenu::addItem(ItemT *i)
+{
+ if (c_grouplist == NULL) return ;
+ switch (i->type)
+ {
+
+ case POPUPITEM_TYPE_TEXT:
+ {
+ c_grouplist->instantiate("wasabi.popup.text.item", 1);
+ ScriptObject *o = c_grouplist->enumItem(c_grouplist->getNumItems() - 1);
+ if (o != NULL)
+ {
+ C_Group grp(o);
+
+ C_RootObject g(o);
+ g.notify("arrow", StringPrintfW(L"%d", (submenus) ? 1 : 0), 0, 0);
+ g.notify("checkmark", StringPrintfW(L"%d", menuchecks ? 1 : 0), 0, 0);
+ g.notify("id", StringPrintfW(L"%d", i->cmd), 0, 0);
+
+ ScriptObject *check = grp.getObject("popup.item.checkmark");
+ if (check != NULL)
+ {
+ C_Button toggle(check);
+ toggle.setActivated(i->checked);
+ }
+
+ ScriptObject *arrow = grp.getObject("popup.item.submenuarrow");
+ if (check != NULL)
+ {
+ C_Button sub(arrow);
+ sub.setActivated((i->menu != NULL || i->cb != NULL));
+ }
+
+ ScriptObject *txt = grp.getObject("popup.item.text");
+ if (txt != NULL)
+ {
+ C_Text itemtxt(txt);
+ itemtxt.setText(i->txt);
+ }
+ }
+ break;
+ }
+
+ case POPUPITEM_TYPE_IMAGE:
+ c_grouplist->instantiate("wasabi.popup.image.item", 1);
+ break;
+
+ case POPUPITEM_TYPE_SEPARATOR:
+ c_grouplist->instantiate("wasabi.popup.separator.item", 1);
+ break;
+
+ }
+}
+
+String PopupMenu::translateButtonText(const wchar_t *text)
+{
+ PathParser pp(text, "\t");
+ String ret;
+ for (int i = 0; i < pp.getNumStrings(); i++)
+ {
+ if (i == 0) ret += _(pp.enumString(i)); // translate first
+ else ret += pp.enumString(i);
+ if (i != pp.getNumStrings() - 1) ret += "\t";
+ }
+ return ret;
+}
+
+void PopupMenu::addCommand(const wchar_t *_txt, int command, int checked, int disabled, int addpos)
+{
+ if (!_txt)
+ {
+ addSeparator();
+ return ;
+ }
+
+ String txt = translateButtonText(_txt);
+#ifdef WASABI_COMPILE_LOCALES
+ const char *bind = WASABI_API_LOCALE->locales_getBindFromAction(command);
+ if (bind) txt += StringPrintfW(L"\t%s", bind);
+#endif
+ ItemT *t = new ItemT;
+ t->type = POPUPITEM_TYPE_TEXT;
+ t->cmd = command;
+ t->txt = txt;
+ t->checked = checked;
+ t->menu = NULL;
+ t->cb = NULL;
+ t->cmd = -1;
+ ASSERT(PTRLIST_POS_LAST == -1); //BU
+ items.addItem(t, addpos);
+}
+
+int PopupMenu::popupexitcb_onExitPopup()
+{
+ getGuiObject()->guiobject_endModal( -2);
+ return 1;
+}
+
+void PopupMenu::addSubMenu(PopupMenu *menu, const wchar_t *text)
+{
+ ASSERT(text != NULL);
+ submenus = 1;
+ ItemT *t = new ItemT;
+ t->type = POPUPITEM_TYPE_TEXT;
+ t->cmd = items.getNumItems() | 0x40000000;
+ t->txt = translateButtonText(text);
+ t->checked = 0;
+ t->menu = menu;
+ t->cb = NULL;
+ t->cmd = -1;
+ t->cmd = -1;
+ items.addItem(t);
+}
+
+void PopupMenu::addSubMenuCallback(const wchar_t *text, PopupMenuCallback *cb, int param)
+{
+ ASSERT(text != NULL);
+ ASSERT(cb != NULL);
+ ItemT *t = new ItemT;
+ submenus = 1;
+ t->type = POPUPITEM_TYPE_TEXT;
+ t->checked = 0;
+ t->cmd = items.getNumItems() | 0x40000000;
+ t->menu = NULL;
+ t->cb = cb;
+ t->cbparam = param;
+ t->txt = translateButtonText(text);
+ t->cmd = -1;
+ items.addItem(t);
+}
+
+void PopupMenu::initMenuCallback(int item)
+{
+ int a = rcode;
+ rcode = 0;
+ PopupMenu *p = items[item]->cb->popupMenuCallback(this, items[item]->cbparam);
+ rcode = a;
+ if (p)
+ {
+ items[item]->cb = NULL;
+ items[item]->menu = p;
+ }
+}
+
+#endif
+
+
+#endif //WASABI_WANT_FF_POPUP
diff --git a/Src/Wasabi/api/wnd/popup.h b/Src/Wasabi/api/wnd/popup.h
new file mode 100644
index 00000000..9ee6d7f9
--- /dev/null
+++ b/Src/Wasabi/api/wnd/popup.h
@@ -0,0 +1,341 @@
+// PopupMenu NONPORTABLE, NewPopupMenu portable
+#ifndef _POPUP_H
+#define _POPUP_H
+
+#include <wasabicfg.h>
+#include <bfc/string/StringW.h>
+#include <bfc/PtrList.h>
+#include <api/locales/xlatstr.h>
+//#define WANT_NEW_POPUPMENU
+
+class PopupMenu;
+
+class PopupMenuCallback
+{
+public:
+ virtual PopupMenu *popupMenuCallback(PopupMenu *parent, intptr_t param) = 0; // returns the new popupmenu to be displayed
+};
+
+enum { POPUP_ANCHOR_UL, POPUP_ANCHOR_LL, POPUP_ANCHOR_UR, POPUP_ANCHOR_LR };
+
+#ifndef WASABI_WANT_FF_POPUP
+
+class PopupMenuEntry
+{
+public:
+ PopupMenuEntry(const wchar_t *txt, int cmd, PopupMenu *_submenu, int _checked, int _disabled, PopupMenuCallback *cb = NULL, int cbparam = 0) : text(_(txt)), command(cmd), submenu(_submenu), checked(_checked), disabled(_disabled), callback(cb), callbackparam(cbparam) {} // txt = null for separators and menus, cmd = -1 for separators and submenus, if submenu == null && cmd == -1 and text == NULL then it's a separator
+ virtual ~PopupMenuEntry() {}
+ int getCommand() { return command; }
+ const wchar_t *getText() { return text; }
+ PopupMenu *getSubmenu() { return submenu; }
+ int getChecked() { return checked; }
+ int getDisabled() { return disabled; }
+ int isSeparator() { return command == -1 && submenu == NULL && text == NULL; }
+ int isSubmenu() { return (command == -1 && submenu != NULL) || callback; }
+ void setChecked(int check) { checked = check; }
+ void setDisabled(int disable) { disabled = disable; }
+ PopupMenuCallback *getCallback() { return callback; }
+ int getCallbackParam() { return callbackparam; }
+private:
+ StringW text;
+ int command;
+ PopupMenu *submenu;
+ int checked;
+ int disabled;
+ PopupMenuCallback *callback;
+ int callbackparam;
+};
+
+class SortMenuEntries
+{
+public:
+ static int compareItem(PopupMenuEntry *p1, PopupMenuEntry *p2)
+ {
+ if (p1->getCommand() < p2->getCommand()) return -1;
+ if (p1->getCommand() > p2->getCommand()) return 1;
+ return 0;
+ }
+ static int compareAttrib(const wchar_t *attrib, PopupMenuEntry *item)
+ {
+ int c = *(int *)attrib;
+ if (c < item->getCommand()) return -1;
+ if (c > item->getCommand()) return 1;
+ return 0;
+ }
+};
+
+
+class PopupMenu
+{
+public:
+ PopupMenu();
+ PopupMenu(ifc_window *parent);
+ PopupMenu(PopupMenu *parent);
+ ~PopupMenu();
+
+ virtual void addSubMenu(PopupMenu *menu, const wchar_t *text, int disabled = FALSE);
+ virtual void addSubMenuCallback(const wchar_t *text, PopupMenuCallback *cb, int param);
+ virtual void addCommand(const wchar_t *text, int command, int checked = 0, int disabled = 0, int addpos = -1);
+ virtual void addSeparator(int addpos = -1);
+ virtual void checkCommand(int cmd, int check);
+ virtual void disableCommand(int cmd, int disable);
+ virtual int popAtXY(int x, int y, int native = 0);
+ virtual int popAnchored(int type = POPUP_ANCHOR_LL); // dropped off the sourceWnd given above
+ virtual int popAtMouse();
+ virtual int getNumCommands();
+ virtual const wchar_t *getCommandText(int command);
+ OSMENUHANDLE getOSMenuHandle();
+ virtual void abort();
+
+private:
+ void rebuildMenu();
+ void invalidateMenu(); // no virtual please (it's called in the destructor)
+ ifc_window *getParent() { return parent; }
+
+ PtrList<PopupMenuEntry> entries;
+ PtrListQuickSorted<PopupMenuEntry, SortMenuEntries> sortedentries;
+ OSMENUHANDLE hmenu;
+ ifc_window *parent;
+};
+
+#else // WASABI_WANT_FF_POPUP
+
+#include "../bfc/basewnd.h"
+#include "../bfc/ptrlist.h"
+#include <tataki/bitmap/autobitmap.h>
+#include "../studio/skincb.h"
+
+#define POPUP_TIMERID 1171
+
+class PopupMenu;
+class ButtonWnd;
+class MenuButtonSurface;
+
+class _PopupMenu
+{
+public:
+ virtual ~_PopupMenu() {}
+
+ virtual void addSubMenu(PopupMenu *menu, const wchar_t *text, int disabled = FALSE) = 0;
+ virtual void addSubMenuImage(PopupMenu *menu, const wchar_t *bitmap, const wchar_t *pushedbitmap = 0, const wchar_t *highlightbitmap = 0) = 0;
+ virtual void addSubMenuCallback(const wchar_t *text, PopupMenuCallback *cb, int param) = 0;
+
+ virtual void addCommand(const char *text, int command, int checked = 0, int disabled = 0, int addpos = -1) = 0;
+ virtual void addCommandImage(const wchar_t *bitmap, const wchar_t *pushedbitmap, const wchar_t *highlightbitmap, int command, int checked, int disabled, int addpos = -1) = 0;
+ virtual void addSeparator(int addpos = -1) = 0;
+
+ virtual void checkCommand(int cmd, int check) = 0;
+ virtual void disableCommand(int cmd, int disable) = 0;
+
+ virtual int popAtXY(int x, int y) = 0;
+ virtual int popAnchored(int type = POPUP_ANCHOR_LL) = 0; // dropped off the sourceWnd given above
+ virtual int popAtMouse() = 0;
+ virtual void showAtXY(int x, int y, int *rc, int revside = 0, int parentW = 0) = 0;
+ virtual int getNumCommands() = 0;
+ virtual const wchar_t *getCommandText(int command) = 0;
+ virtual void onPostPop(intptr_t result) = 0;
+ virtual void selectFirst() = 0;
+};
+
+#ifndef WANT_NEW_POPUPMENU
+
+#define POPUPMENU_PARENT BaseWnd
+
+class PopupMenu : public _PopupMenu, public POPUPMENU_PARENT, public SkinCallbackI
+{
+public:
+ PopupMenu(ifc_window *sourceWnd);
+ PopupMenu(HWND sourceWnd);
+ PopupMenu(PopupMenu *sourceWnd);
+ PopupMenu();
+ virtual ~PopupMenu();
+
+ void addSubMenu(PopupMenu *menu, const wchar_t *text, int disabled = FALSE);
+ void addSubMenuImage(PopupMenu *menu, const wchar_t *bitmap, const wchar_t *pushedbitmap = 0, const wchar_t *highlightbitmap = 0);
+ void addSubMenuCallback(const wchar_t *text, PopupMenuCallback *cb, int param);
+
+ void addCommand(const wchar_t *text, int command, int checked = 0, int disabled = 0, int addpos = -1);
+ void addCommandImage(const wchar_t *bitmap, const wchar_t *pushedbitmap, const wchar_t *highlightbitmap, int command, int checked, int disabled, int addpos = -1);
+ void addSeparator(int addpos = -1);
+
+ void checkCommand(int cmd, int check);
+ void disableCommand(int cmd, int disable);
+
+ int popAtXY(int x, int y);
+ int popAnchored(int type = POPUP_ANCHOR_LL); // dropped off the sourceWnd given above
+ int popAtMouse();
+ int getNumCommands();
+
+ virtual int bypassModal() { return 1; }
+
+ const wchar_t *getCommandText(int command);
+
+ virtual int onPaint(Canvas *canvas);
+
+ virtual int childNotify(ifc_window *child, int msg, intptr_t param1 = 0, intptr_t param2 = 0);
+
+ virtual int onLeftButtonDown(int x, int y);
+ virtual int onRightButtonDown(int x, int y);
+ virtual int onMouseMove(int x, int y); // only called when mouse captured
+ virtual int onLeftButtonUp(int x, int y);
+ virtual int onRightButtonUp(int x, int y);
+ virtual void timerCallback(int id);
+
+ virtual int onKillFocus();
+
+ virtual int skincb_onCheckPreventSwitch(const char *skinname);
+
+ virtual int onKeyDown(int code);
+
+ virtual void navigate(int p, int f = 0); // 1 = next, -1 = previous, 0 = self (open submenu or run action)
+
+ virtual void onSetVisible(int p);
+ virtual void selectFirst();
+ virtual int onSysKeyDown(int code, int d);
+
+ virtual void abort();
+
+ virtual void setFriendlyId(const wchar_t *id);
+ virtual MenuButtonSurface *getNextFriend() { return chainmenu; }
+
+protected:
+ virtual int onInit();
+
+ void invalidateItem(int i);
+ String translateButtonText(const wchar_t *text);
+
+ virtual void onPostPop(intptr_t result) {}
+
+ // used internally, as well as by parent Popups.
+ void showAtXY(int x, int y, int *rc, int revside = 0, int parentW = 0);
+ void hide();
+ int isMine(int x, int y);
+private:
+ int getWhichItem(POINT &p);
+ void onButtonUp(int wb, int x, int y);
+ void onButtonDown(int wb, int x, int y);
+ void resetTimer(int p);
+ void initMenuCallback(int item);
+
+ int bdown;
+ int lastitem;
+ int rcode;
+ int *rcp;
+ typedef struct
+ {
+ int cmd;
+ ButtonWnd *butt;
+ PopupMenu *menu;
+ PopupMenuCallback *cb;
+ int issep;
+ int cbparam;
+ }
+ ItemT;
+ PtrList<ItemT> items;
+ ifc_window *parentRootWnd;
+ HWND parentWnd;
+ AutoSkinBitmap tex, ful, fur, fll, flr, fl, fr, ft, fb, sr, sl, sc;
+ int openmenuid;
+ int timerset;
+ int timeritem;
+ int popupdelay;
+ int reverse_side;
+ ifc_window *init_with;
+ int disable_autopop;
+ int kbdhooked;
+ int toplevelmenu;
+ POINT lastxy;
+ int keyctrl;
+ String friendid;
+ MenuButtonSurface *chainmenu;
+
+#ifdef WASABI_COMPILE_SKIN
+ String switchskinto;
+#endif
+};
+
+#else
+
+#include "guiobjwnd.h"
+#include "script/c_script/c_grouplist.h"
+#include "../bfc/popexitcb.h"
+#include "../bfc/notifmsg.h"
+
+#define POPUPMENU_PARENT GuiObjectWnd
+
+enum {
+ POPUPITEM_TYPE_TEXT = 0,
+ POPUPITEM_TYPE_IMAGE,
+ POPUPITEM_TYPE_SEPARATOR,
+};
+
+typedef struct
+{
+ int type;
+ int cmd;
+ PopupMenu *menu;
+ PopupMenuCallback *cb;
+ String txt;
+ int checked;
+ int disabled;
+ int cbparam;
+}
+ItemT;
+
+class PopupMenu : public _PopupMenu, public POPUPMENU_PARENT, public PopupExitCallbackI
+{
+public:
+ PopupMenu(ifc_window *sourceWnd);
+ // PopupMenu(HWND sourceWnd);
+ PopupMenu(PopupMenu *sourceWnd);
+ PopupMenu();
+ virtual ~PopupMenu();
+
+ virtual void addSubMenu(PopupMenu *menu, const wchar_t *text, int disabled = FALSE);
+ virtual void addSubMenuImage(PopupMenu *menu, const wchar_t *bitmap, const wchar_t *pushedbitmap = 0, const wchar_t *highlightbitmap = 0) {}
+ virtual void addSubMenuCallback(const wchar_t *text, PopupMenuCallback *cb, int param);
+
+ virtual void addCommand(const wchar_t *text, int command, int checked = 0, int disabled = 0, int addpos = -1);
+ virtual void addCommandImage(const wchar_t *bitmap, const wchar_t *pushedbitmap, const wchar_t *highlightbitmap, int command, int checked, int disabled, int addpos = -1) {}
+ virtual void addSeparator(int addpos = -1) {}
+
+ virtual void checkCommand(int cmd, int check) {}
+ virtual void disableCommand(int cmd, int disable) {}
+
+ virtual int popAtXY(int x, int y);
+ virtual int popAnchored(int type = POPUP_ANCHOR_LL);
+ virtual int popAtMouse();
+ virtual void showAtXY(int x, int y, int *rc, int revside = 0, int parentW = 0);
+ virtual int getNumCommands() { return 0;}
+ virtual const wchar_t *getCommandText(int command) { return NULL; }
+ virtual void onPostPop(intptr_t result) {}
+
+ virtual int onInit();
+
+ virtual void onNewContent();
+
+ virtual int popupexitcb_onExitPopup();
+ virtual ifc_dependent *popupexit_getDependencyPtr() { return getDependencyPtr(); }
+
+private:
+
+ virtual int bypassModal() { return 1; }
+ String translateButtonText(const wchar_t *text);
+ void fillContent();
+ void addItem(ItemT *item);
+ void initMenuCallback(int item);
+
+ void myInit();
+ int reverse_side;
+ int rcode;
+
+ PtrList<ItemT> items;
+ int menuchecks;
+ int submenus;
+ C_GroupList *c_grouplist;
+ int totalheight, totalwidth;
+};
+
+#endif
+#endif // WASABI_WANT_FF_POPUP
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/region.cpp b/Src/Wasabi/api/wnd/region.cpp
new file mode 100644
index 00000000..ceeb0d64
--- /dev/null
+++ b/Src/Wasabi/api/wnd/region.cpp
@@ -0,0 +1 @@
+#include "precomp.h"
diff --git a/Src/Wasabi/api/wnd/region.h b/Src/Wasabi/api/wnd/region.h
new file mode 100644
index 00000000..a925f3e1
--- /dev/null
+++ b/Src/Wasabi/api/wnd/region.h
@@ -0,0 +1,5 @@
+#ifdef _WIN32
+#include <api/wnd/platform/win32/region.h>
+#elif defined(__APPLE__)
+#include <api/wnd/platform/osx/region.h>
+#endif
diff --git a/Src/Wasabi/api/wnd/resizable.h b/Src/Wasabi/api/wnd/resizable.h
new file mode 100644
index 00000000..7b8b6faf
--- /dev/null
+++ b/Src/Wasabi/api/wnd/resizable.h
@@ -0,0 +1,21 @@
+#ifndef _RESIZABLE_H
+#define _RESIZABLE_H
+
+// {834F172D-FE95-4324-B0EE-BCE29886D7BE}
+static const GUID guiResizableGuid =
+{ 0x834f172d, 0xfe95, 0x4324, { 0xb0, 0xee, 0xbc, 0xe2, 0x98, 0x86, 0xd7, 0xbe } };
+
+class GuiResizable {
+public:
+ virtual void beginMove()=0;
+ virtual void beginScale()=0;
+ virtual void beginResize()=0;
+ virtual void endMove()=0;
+ virtual void endScale()=0;
+ virtual void endResize()=0;
+ virtual ifc_window *guiresizable_getRootWnd()=0;
+ virtual void setEndMoveResize(int w, int h)=0;
+};
+
+
+#endif
diff --git a/Src/Wasabi/api/wnd/rootwnd.cpp b/Src/Wasabi/api/wnd/rootwnd.cpp
new file mode 100644
index 00000000..2f302a34
--- /dev/null
+++ b/Src/Wasabi/api/wnd/rootwnd.cpp
@@ -0,0 +1,197 @@
+#include <precomp.h>
+#include "rootwnd.h"
+
+#define CBCLASS RootWndI
+START_DISPATCH;
+ CB(GETTIMERCLIENT, getTimerClient);
+ VCB(BATCHPROCESSES, performBatchProcesses);
+ CB(GETOSWINDOWHANDLE, getOsWindowHandle);
+ CB(GETOSMODULEHANDLE, getOsModuleHandle);
+ CB(GETROOTWNDNAME, getRootWndName);
+ CB(GETID, getId);
+ CB(GETGUIOBJECT, getGuiObject);
+ CB(INIT, init);
+ CB(ISINITED, isInited);
+ CB(ISPOSTONINIT, isPostOnInit);
+ CB(SETVIRTUAL, setVirtual);
+ CB(CLICKTHROUGH, isClickThrough);
+ CB(GETFORWARDWND, getForwardWnd);
+ CB(ONMOUSEMOVE, onMouseMove);
+ CB(ONLBUP, onLeftButtonUp);
+ CB(ONRBUP, onRightButtonUp);
+ CB(ONLBDOWN, onLeftButtonDown);
+ CB(ONRBDOWN, onRightButtonDown);
+ CB(ONLBDBLCLK, onLeftButtonDblClk);
+ CB(ONRBDBLCLK, onRightButtonDblClk);
+ CB(GETDRAGINTERFACE, getDragInterface);
+ CB(GETCURSORTYPE, getCursorType);
+ CB(GETCUSTOMCURSOR, getCustomCursor);
+ CB(FROMPOINT, rootWndFromPoint);
+ VCB(GETCLIENTRECT, getClientRect);
+ VCB(GETNONCLIENTRECT, getNonClientRect);
+ VCB(GETWINDOWRECT, getWindowRect);
+ VCB(SETVISIBLE, setVisible);
+ VCB(SETCLOAKED, setCloaked);
+ VCB(ONSETVISIBLE, onSetVisible);
+ CB(ISVISIBLE, isVisible);
+ CB(GETINTERFACE, getInterface);
+ VCB(INVALIDATE, invalidate);
+ VCB(INVALIDATERECT, invalidateRect);
+ VCB(INVALIDATERGN, invalidateRgn);
+ VCB(INVALIDATEFROM, invalidateFrom);
+ VCB(INVALIDATERECTFROM, invalidateRectFrom);
+ VCB(INVALIDATERGNFROM, invalidateRgnFrom);
+ VCB(ONCHILDINVALIDATE, onChildInvalidate);
+ VCB(VALIDATE, validate);
+ VCB(VALIDATERECT, validateRect);
+ VCB(VALIDATERGN, validateRgn);
+ CB(PAINTTREE, rootwnd_paintTree);
+ CB(PAINT, paint);
+ CB(GETFRAMEBUFFER, getFrameBuffer);
+ CB(GETPARENT, getParent);
+ CB(GETROOTPARENT, getRootParent);
+ CB(GETDESKTOPPARENT, getDesktopParent);
+ VCB(SETPARENT, setParent);
+ CB(ONSIBINVALIDATE, onSiblingInvalidateRgn);
+ CB(WANTSIBINVALIDATE, wantSiblingInvalidations);
+ CB(CASCADEREPAINTFROM, cascadeRepaintFrom);
+ CB(CASCADEREPAINTRGNFROM, cascadeRepaintRgnFrom);
+ CB(CASCADEREPAINTRECTFROM, cascadeRepaintRectFrom);
+ CB(CASCADEREPAINT, cascadeRepaint);
+ CB(CASCADEREPAINTRGN, cascadeRepaintRgn);
+ CB(CASCADEREPAINTRECT, cascadeRepaintRect);
+ VCB(REPAINT, repaint);
+ CB(GETTEXTUREWND, getBaseTextureWindow);
+ CB(CHILDNOTIFY, childNotify);
+ CB(GETPREFERENCES, getPreferences);
+ VCB(SETPREFERENCES, setPreferences);
+ CB(GETREGION, getRegion);
+ VCB(SETSTARTHIDDEN, setStartHidden);
+ CB(GETRENDERRATIO, getRenderRatio);
+ VCB(SETRENDERRATIO, setRenderRatio);
+ VCB(SETRATIOLINKED, setRatioLinked);
+ CB(HANDLERATIO, handleRatio);
+ VCB(_RESIZE, resize);
+ VCB(_MOVE, move);
+ VCB(NOTIFYDEFERREDMOVE, notifyDeferredMove);
+ VCB(GETPOSITION, getPosition);
+ VCB(REGISTERROOTWNDCHILD, registerRootWndChild);
+ VCB(UNREGISTERROOTWNDCHILD, unregisterRootWndChild);
+ CB(FINDROOTWNDCHILD, findRootWndChild);
+ CB(ENUMROOTWNDCHILDREN, enumRootWndChildren);
+ CB(GETNUMROOTWNDCHILDREN, getNumRootWndChildren);
+ CB(ISVIRTUAL, isVirtual);
+ VCB(BRINGVTOFRONT, bringVirtualToFront);
+ VCB(BRINGVTOBACK, bringVirtualToBack);
+ VCB(BRINGVABOVE, bringVirtualAbove);
+ VCB(BRINGVBELOW, bringVirtualBelow);
+ CB(CHECKDBLCLK, checkDoubleClick);
+ VCB(SETVCAPTURE, setVirtualChildCapture);
+ CB(GETVCAPTURE, getVirtualChildCapture);
+ CB(PTINREGION, ptInRegion);
+ VCB(CLIENTSCREEN, clientToScreen);
+ VCB(SCREENCLIENT, screenToClient);
+ CB(ONACTIVATE, onActivate);
+ VCB(ACTIVATE, activate);
+ CB(ONDEACTIVATE, onDeactivate);
+ CB(ISACTIVATED, isActive);
+ CB(HANDLETRANSPARENCY, handleTransparency);
+ CB(HANDLEDESKTOPALPHA, handleDesktopAlpha);
+ CB(GETNOTIFYID, getNotifyId);
+ VCB(SETENABLED, setEnabled);
+ CB(ONENABLE, onEnable);
+ CB(ISENABLED, isEnabled);
+ CB(GETPAINTALPHA, getPaintingAlpha);
+ VCB(SETALPHA, setAlpha);
+ VCB(GETALPHA, getAlpha);
+ VCB(SETCLICKTHROUGH, setClickThrough);
+ VCB(SETTOOLTIP, setTip);
+ CB(RUNMODAL, runModal);
+ VCB(ENDMODAL, endModal);
+ CB(WANTAUTOCONTEXTMENU, wantAutoContextMenu);
+ VCB(ONCANCELCAPTURE, onCancelCapture);
+ VCB(CANCELCAPTURE, cancelCapture);
+ VCB(BRINGTOFRONT, bringToFront);
+ VCB(BRINGTOBACK, bringToBack);
+ VCB(SETFOCUS, setFocus);
+ CB(GOTFOCUS, gotFocus);
+ CB(ONGETFOCUS, onGetFocus);
+ CB(ONKILLFOCUS, onKillFocus);
+ CB(GETNEXTVFOCUS, getNextVirtualFocus);
+ VCB(SETVFOCUS, setVirtualChildFocus);
+ CB(WANTFOCUS, wantFocus);
+ CB(ONACCELERATOREVENT, onAcceleratorEvent);
+ CB(ONCHAR, onChar);
+ CB(ONKEYDOWN, onKeyDown);
+ CB(ONKEYUP, onKeyUp);
+ CB(ONSYSKEYDOWN, onSysKeyDown);
+ CB(ONSYSKEYUP, onSysKeyUp);
+ CB(GETREGIONOP, getRegionOp);
+ VCB(SETREGIONOP, setRegionOp);
+ VCB(INVALWNDRGN, invalidateWindowRegion);
+ CB(GETCOMPOSEDRGN, getComposedRegion);
+ CB(GETSUBTRACTORRGN, getSubtractorRegion);
+ CB(ISRECTRGN, isRectRgn);
+ VCB(SETRECTRGN, setRectRgn);
+ CB(GETDEPENDENCYPTR, rootwnd_getDependencyPtr);
+ VCB(ADDMINMAXENFORCER, addMinMaxEnforcer);
+ VCB(REMOVEMINMAXENFORCER, removeMinMaxEnforcer);
+ CB(GETNUMMINMAXENFORCERS, getNumMinMaxEnforcers);
+ CB(ENUMMINMAXENFORCER, enumMinMaxEnforcer);
+ VCB(SIGNALMINMAXCHANGED, signalMinMaxEnforcerChanged);
+ CB(ROOTWNDONACTION, onAction);
+ VCB(SETRENDERBASETEXTURE, setRenderBaseTexture);
+ CB(GETRENDERBASETEXTURE, getRenderBaseTexture);
+ VCB(RENDERBASETEXTURE, rootwnd_renderBaseTexture);
+ CB(TRIGGEREVENT, triggerEvent);
+ CB(GETFLAG, getFlag);
+ CB(ALLOWDEACTIVATE, allowDeactivation);
+ VCB(SETALLOWDEACTIVATE, setAllowDeactivation);
+ CB(FINDWND_BYID, findWindow);
+ CB(FINDWND_BYGUID, findWindowByInterface);
+ CB(FINDWND_BYCB, findWindowByCallback);
+ CB(FINDWNDCHAIN, findWindowChain);
+ VCB(SETTABORDER, setTabOrder);
+ CB(GETTABORDER, getTabOrder);
+ VCB(SETVIRTUALTABORDER, setVirtualTabOrder);
+ CB(GETVIRTUALTABORDER, getVirtualTabOrder);
+ VCB(SETAUTOTABORDER, setAutoTabOrder);
+ VCB(SETVIRTUALAUTOTABORDER, setVirtualAutoTabOrder);
+ CB(GETCURVIRTUALCHILDFOCUS, getCurVirtualChildFocus);
+ CB(GETTAB, getTab);
+ VCB(FOCUSNEXT, focusNext);
+ VCB(FOCUSPREVIOUS, focusPrevious);
+ VCB(SETWINDOWTITLE, setWindowTitle);
+ CB(ENUMTAB, enumTab);
+ CB(GETNUMTABS, getNumTabs);
+ VCB(ONSETROOTFOCUS, onSetRootFocus);
+ VCB(SETFOCUSONCLICK, setFocusOnClick);
+ CB(GETFOCUSONCLICK, getFocusOnClick);
+ VCB(SETNODOUBLECLICKS, setNoDoubleClicks);
+ VCB(SETNOLEFTCLICKS, setNoLeftClicks);
+ VCB(SETNORIGHTCLICKS, setNoRightClicks);
+ VCB(SETNOMOUSEMOVES, setNoMouseMoves);
+ VCB(SETNOCONTEXTMENUS, setNoContextMenus);
+ CB(WANTLEFTCLICKS, wantLeftClicks);
+ CB(WANTRIGHTCLICKS, wantRightClicks);
+ CB(WANTDOUBLECLICKS, wantDoubleClicks);
+ CB(WANTMOUSEMOVES, wantMouseMoves);
+ CB(WANTCONTEXTMENUS, wantContextMenus);
+ CB(WANTACTIVATION, wantActivation);
+ VCB(SETDEFAULTCURSOR, setDefaultCursor);
+ CB(GETACCESSIBLEOBJECT, getAccessibleObject);
+ CB(ACCGETSTATE,accessibility_getState);
+#ifndef WA3COMPATIBILITY
+ VCB(SETDROPTARGET, setDropTarget);
+ CB(GETDROPTARGET, getDropTarget);
+#endif
+#ifdef EXPERIMENTAL_INDEPENDENT_AOT
+ VCB(SETALWAYSONTOP, setAlwaysOnTop);
+ CB(GETALWAYSONTOP, getAlwaysOnTop);
+#endif
+ CB(ISMINIMIZED, isMinimized);
+ VCB(MAXIMIZE, maximize);
+ VCB(RESTORE, restore);
+ CB(GETRESTOREDRECT, getRestoredRect);
+END_DISPATCH;
+#undef CBCLASS
diff --git a/Src/Wasabi/api/wnd/rootwnd.h b/Src/Wasabi/api/wnd/rootwnd.h
new file mode 100644
index 00000000..2b33e324
--- /dev/null
+++ b/Src/Wasabi/api/wnd/rootwnd.h
@@ -0,0 +1,275 @@
+#ifndef _ROOTWND_H
+#define _ROOTWND_H
+
+#include "api_window.h"
+#include <bfc/wasabi_std.h>
+#include <bfc/dispatch.h>
+#include <api/wnd/cursor.h>
+
+class ifc_canvas;
+class api_region;
+class TimerClient;
+class ifc_dependent;
+class GuiObject;
+class FindObjectCallback;
+class Cursor;
+class Accessible;
+class Canvas;
+
+// only these methods are safe across dll boundaries
+// this is the pointer you find in the GWL_USERDATA of a window
+
+class DragInterface;
+
+class NOVTABLE RootWndI : public ifc_window
+{
+protected:
+ RootWndI() {} // protect constructor
+
+public:
+ virtual OSWINDOWHANDLE getOsWindowHandle()=0;
+ virtual OSMODULEHANDLE getOsModuleHandle()=0;
+ virtual void performBatchProcesses()=0;
+ virtual TimerClient *getTimerClient()=0;
+ virtual const wchar_t *getRootWndName()=0;
+ virtual const wchar_t *getId()=0;
+ virtual int init(ifc_window *parent, int nochild)=0;
+ virtual int isInited()=0;
+ virtual int isPostOnInit()=0;
+
+ virtual int setVirtual(int i)=0;
+
+ virtual int isClickThrough()=0;
+ virtual int onMouseMove(int x, int y)=0;
+ virtual int onLeftButtonUp(int x, int y)=0;
+ virtual int onRightButtonUp(int x, int y)=0;
+ virtual int onLeftButtonDown(int x, int y)=0;
+ virtual int onRightButtonDown(int x, int y)=0;
+ virtual int onLeftButtonDblClk(int x, int y)=0;
+ virtual int onRightButtonDblClk(int x, int y)=0;
+
+ virtual DragInterface *getDragInterface()=0;
+
+ virtual int getCursorType(int x, int y)=0;
+ virtual OSCURSORHANDLE getCustomCursor(int x, int y)=0;
+ virtual ifc_window *rootWndFromPoint(POINT *pt)=0;
+
+ virtual void getClientRect(RECT *r)=0;
+ virtual void getNonClientRect(RECT *rect)=0;
+ virtual void getWindowRect(RECT *r)=0;
+
+ virtual void setVisible(int show)=0;
+ virtual void setCloaked(int cloak)=0;
+ virtual void onSetVisible(int show)=0;
+ virtual int isVisible(int within=0)=0;
+
+ virtual void *getInterface(GUID interface_guid)=0;
+
+ virtual void invalidate()=0;
+ virtual void invalidateRect(RECT *r)=0;
+ virtual void invalidateRgn(api_region *r)=0;
+ virtual void invalidateFrom(ifc_window *who)=0;
+ virtual void invalidateRectFrom(RECT *r, ifc_window *who)=0;
+ virtual void invalidateRgnFrom(api_region *r, ifc_window *who)=0;
+ virtual void validate()=0;
+ virtual void validateRect(RECT *r)=0;
+ virtual void validateRgn(api_region *reg)=0;
+ virtual void onChildInvalidate(api_region *r, ifc_window *who)=0;
+
+ virtual int rootwnd_paintTree(ifc_canvas *canvas, api_region *r)=0;
+ virtual int paint (Canvas *canvas, api_region *r)=0;
+ virtual Canvas *getFrameBuffer()=0;
+
+ virtual ifc_window *getParent()=0;
+ virtual ifc_window *getRootParent()=0;
+ virtual ifc_window *getDesktopParent()=0;
+ virtual void setParent(ifc_window *parent)=0;
+
+ virtual int onSiblingInvalidateRgn(api_region *r, ifc_window *who, int who_idx, int my_idx)=0;
+ virtual int wantSiblingInvalidations()=0;
+
+ virtual int cascadeRepaintFrom(ifc_window *who, int pack=1)=0;
+ virtual int cascadeRepaintRgnFrom(api_region *reg, ifc_window *who, int pack=1)=0;
+ virtual int cascadeRepaintRectFrom(RECT *r, ifc_window *who, int pack=1)=0;
+ virtual int cascadeRepaint(int pack=1)=0;
+ virtual int cascadeRepaintRgn(api_region *reg, int pack=1)=0;
+ virtual int cascadeRepaintRect(RECT *r, int pack=1)=0;
+ virtual void repaint()=0;
+
+ virtual void setClickThrough(int ct)=0;
+ virtual ifc_window *getBaseTextureWindow()=0;
+ virtual void rootwnd_renderBaseTexture(ifc_canvas *c, const RECT *r, int alpha=255)=0;
+#if defined (_WIN64)
+ virtual int childNotify(ifc_window* child, int msg, int p1, int p2) = 0;
+#else
+ virtual int childNotify(ifc_window *child, int msg, intptr_t p1, intptr_t p2)=0;
+#endif
+ virtual int getPreferences(int what)=0;
+ virtual void setPreferences(int what, int v)=0;
+
+ virtual api_region *getRegion()=0;
+ virtual int getRegionOp()=0;
+ virtual void setRegionOp(int op)=0;
+ virtual int isRectRgn()=0;
+ virtual void setRectRgn(int rrgn)=0;
+ virtual void invalidateWindowRegion()=0;
+ virtual api_region *getComposedRegion()=0;
+ virtual api_region *getSubtractorRegion()=0;
+
+ virtual void setStartHidden(int sh)=0;
+ virtual double getRenderRatio()=0;
+ virtual void setRenderRatio(double r)=0;
+ virtual void setRatioLinked(int l)=0;
+ virtual int handleRatio()=0;
+ virtual void resize(int x, int y, int w, int h, int wantcb=1)=0;
+ virtual void move(int x, int y)=0;
+ virtual void notifyDeferredMove(int x, int y)=0;
+
+ virtual void getPosition(POINT *pt)=0;
+ virtual ifc_window *getForwardWnd()=0;
+
+ virtual void registerRootWndChild(ifc_window *child)=0;
+ virtual void unregisterRootWndChild(ifc_window *child)=0;
+ virtual ifc_window *findRootWndChild(int x, int y, int only_virtuals=0)=0;
+ virtual ifc_window *enumRootWndChildren(int _enum)=0;
+ virtual int getNumRootWndChildren()=0;
+
+ virtual int isVirtual()=0;
+
+ virtual void bringVirtualToFront(ifc_window *w)=0;
+ virtual void bringVirtualToBack(ifc_window *w)=0;
+ virtual void bringVirtualAbove(ifc_window *w, ifc_window *b)=0;
+ virtual void bringVirtualBelow(ifc_window *w, ifc_window *b)=0;
+ virtual int checkDoubleClick(int button, int x, int y)=0;
+
+ virtual void onCancelCapture()=0;
+ virtual void cancelCapture()=0;
+
+ virtual void clientToScreen(int *x, int *y)=0;
+ virtual void screenToClient(int *x, int *y)=0;
+
+ virtual void setVirtualChildCapture(ifc_window *child)=0;
+ virtual ifc_window *getVirtualChildCapture()=0;
+
+ virtual int ptInRegion(int x, int y)=0;
+
+ virtual int onActivate()=0;
+ virtual void activate()=0;
+ virtual int onDeactivate()=0;
+ virtual int isActive()=0;
+ virtual int handleTransparency()=0;
+ virtual int handleDesktopAlpha()=0;
+
+ virtual int getNotifyId()=0;
+ virtual void setEnabled(int en)=0;
+ virtual int isEnabled(int within=0)=0;
+ virtual int onEnable(int e)=0;
+
+ virtual int getPaintingAlpha()=0;
+ virtual void getAlpha(int *active=NULL, int *inactive=NULL)=0;
+ virtual void setAlpha(int activealpha, int inactivealpha=-1)=0;
+
+ virtual void setTip(const wchar_t *tip)=0;
+ virtual int runModal()=0;
+ virtual void endModal(int retcode)=0;
+ virtual int wantAutoContextMenu()=0;
+ virtual int wantActivation()=0;
+
+ virtual void bringToFront()=0;
+ virtual void bringToBack()=0;
+ virtual void setFocus()=0;
+ virtual int gotFocus()=0;
+ virtual ifc_window *getNextVirtualFocus(ifc_window *w)=0;
+ virtual void setVirtualChildFocus(ifc_window *w)=0;
+ virtual void setVirtualTabOrder(ifc_window *w, int a)=0;
+ virtual int getVirtualTabOrder(ifc_window *w)=0;
+ virtual int wantFocus()=0;
+ virtual void setTabOrder(int a)=0;
+ virtual int getTabOrder()=0;
+ virtual ifc_window *getTab(int what=TAB_GETCURRENT)=0;
+ virtual void setAutoTabOrder()=0;
+ virtual void setVirtualAutoTabOrder(ifc_window *w)=0;
+ virtual ifc_window *getCurVirtualChildFocus()=0;
+ virtual void onSetRootFocus(ifc_window *w)=0;
+
+ virtual int onAcceleratorEvent(const wchar_t *name)=0;
+
+ virtual int onChar(unsigned int c)=0;
+ virtual int onKeyDown(int keycode)=0;
+ virtual int onKeyUp(int keycode)=0;
+ virtual int onSysKeyDown(int keyCode, int keyData)=0;
+ virtual int onSysKeyUp(int keyCode, int keyData)=0;
+ virtual int onKillFocus()=0;
+ virtual int onGetFocus()=0;
+ virtual ifc_dependent *rootwnd_getDependencyPtr()=0;
+ virtual void addMinMaxEnforcer(ifc_window *w)=0;
+ virtual void removeMinMaxEnforcer(ifc_window *w)=0;
+ virtual ifc_window *enumMinMaxEnforcer(int n)=0;
+ virtual int getNumMinMaxEnforcers()=0;
+ virtual void signalMinMaxEnforcerChanged()=0;
+
+ virtual int onAction(const wchar_t *action, const wchar_t *param=NULL, int x=-1, int y=-1, intptr_t p1=0, intptr_t p2=0, void *data=NULL, size_t datalen=0, ifc_window *source=NULL)=0;
+
+ virtual void setRenderBaseTexture(int r)=0;
+ virtual int getRenderBaseTexture()=0;
+ virtual GuiObject *getGuiObject()=0; // not guaranteed non null
+
+ virtual int getFlag(int flag)=0;
+ virtual int triggerEvent(int event, intptr_t p1, intptr_t p2)=0;
+
+
+ virtual int allowDeactivation()=0;
+ virtual void setAllowDeactivation(int allow)=0;
+
+ virtual ifc_window *findWindow(const wchar_t *id)=0;
+ virtual ifc_window *findWindowByInterface(GUID interface_guid)=0;
+ virtual ifc_window *findWindowByCallback(FindObjectCallback *cb)=0;
+ virtual ifc_window *findWindowChain(FindObjectCallback *cb, ifc_window *wcaller)=0;
+
+ virtual void focusNext()=0;
+ virtual void focusPrevious()=0;
+
+ virtual void setWindowTitle(const wchar_t *title) = 0;
+ virtual ifc_window *enumTab(int i)=0;
+ virtual int getNumTabs()=0;
+
+ virtual int getFocusOnClick()=0;
+ virtual void setFocusOnClick(int i)=0;
+
+ virtual void setNoDoubleClicks(int no)=0;
+ virtual void setNoLeftClicks(int no)=0;
+ virtual void setNoRightClicks(int no)=0;
+ virtual void setNoMouseMoves(int no)=0;
+ virtual void setNoContextMenus(int no)=0;
+
+ virtual int wantDoubleClicks()=0;
+ virtual int wantLeftClicks()=0;
+ virtual int wantRightClicks()=0;
+ virtual int wantMouseMoves()=0;
+ virtual int wantContextMenus()=0;
+
+ virtual void setDefaultCursor(Cursor *c)=0;
+
+ virtual Accessible *getAccessibleObject(int createifnotexist=1)=0;
+ virtual int accessibility_getState()=0;
+
+#ifdef EXPERIMENTAL_INDEPENDENT_AOT
+ virtual void setAlwaysOnTop(int i)=0;
+ virtual int getAlwaysOnTop()=0;
+#endif
+
+#ifndef WA3COMPATIBILITY
+ virtual void setDropTarget(void *dt)=0;
+ virtual void *getDropTarget()=0;
+#endif
+
+ virtual int isMinimized()=0;
+ virtual void maximize(int axis=MAXIMIZE_WIDTH|MAXIMIZE_HEIGHT)=0;
+ virtual void restore(int what=RESTORE_X|RESTORE_Y|RESTORE_WIDTH|RESTORE_HEIGHT)=0;
+ virtual int getRestoredRect(RECT *r)=0;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/textalign.h b/Src/Wasabi/api/wnd/textalign.h
new file mode 100644
index 00000000..83ea89e5
--- /dev/null
+++ b/Src/Wasabi/api/wnd/textalign.h
@@ -0,0 +1,32 @@
+/*
+
+Darkain Made This. :)
+// and BU tweaked it
+
+*/
+
+/*
+Darkain: i wanted one base for ALL text alignment in ALL classes.
+*/
+
+
+#ifndef _TEXTALIGN_H
+#define _TEXTALIGN_H
+
+typedef enum {
+ TEXTALIGN_LEFT,
+ TEXTALIGN_CENTER, //what ever default center style is... see bellow
+ TEXTALIGN_RIGHT,
+ TEXTALIGN_EVENSPACING, //add more space between letters/words to make it fit in 100% of the area
+ TEXTALIGN_FITTOWIDTH, //make the font larger or smaller to fit in 100% of the area
+ TEXTALIGN_LEFT_ELLIPSIS, //align left, and truncate text to fit if too large
+ TEXTALIGN_CENTER_CENTER, //if text is too wide, it will still center on the middle, choping off left and right sides
+ TEXTALIGN_CENTER_LEFT, //will chop off right side if too big
+ TEXTALIGN_CENTER_RIGHT, //will chop off left side if too big
+ TEXTALIGN_SCROLL, //if text is too large, it will use default scrolling (see bellow)
+ TEXTALIGN_SCROLL_BACKFORTH, //text will scroll back and forth if too large
+ TEXTALIGN_SCROLL_TICKER, //text will scroll in one direction, and loop
+} TextAlign;
+
+
+#endif // TEXT_ALIGN_H
diff --git a/Src/Wasabi/api/wnd/usermsg.h b/Src/Wasabi/api/wnd/usermsg.h
new file mode 100644
index 00000000..21da3e5a
--- /dev/null
+++ b/Src/Wasabi/api/wnd/usermsg.h
@@ -0,0 +1,23 @@
+#ifndef _USERMSG_H
+#define _USERMSG_H
+
+// WM_USER+ messages for common classes
+// DO NOT PUT ANY MORE FUCKING NON WNDPROC SHIT IN HERE
+// childNotify stuff goes into notifmsg.h
+#ifdef _WIN32
+enum
+{
+ UMSG_NOP = WM_USER,
+
+ UMSG_DEFERRED_CALLBACK,
+
+//CUT UMSG_TREEVIEW_EDITLABELDEFERRED,
+//CUT UMSG_TREEVIEW_SELECTITEM,
+
+ UMSG_COMPON_POSTMESSAGE,
+
+ LAST_COMMON_UMSG
+};
+#endif
+
+#endif
diff --git a/Src/Wasabi/api/wnd/virtualwnd.cpp b/Src/Wasabi/api/wnd/virtualwnd.cpp
new file mode 100644
index 00000000..dd45da11
--- /dev/null
+++ b/Src/Wasabi/api/wnd/virtualwnd.cpp
@@ -0,0 +1,672 @@
+#include <precomp.h>
+#include "virtualwnd.h"
+#include <tataki/region/api_region.h>
+
+#include <api/wnd/usermsg.h>
+#include <api/wnd/accessible.h>
+
+VirtualWnd::VirtualWnd()
+{
+ virtualX = virtualY = virtualH = virtualW = 0;
+ bypassvirtual = 0;
+ focus = 0;
+ resizecount = 0;
+ lastratio = 1;
+}
+
+VirtualWnd::~VirtualWnd()
+{}
+
+int VirtualWnd::init(ifc_window *parWnd, int nochild)
+{
+ if (!bypassvirtual)
+ setParent(parWnd);
+
+ return (VIRTUALWND_PARENT::init(parWnd, nochild));
+}
+
+int VirtualWnd::init(OSMODULEHANDLE moduleHandle, OSWINDOWHANDLE parent, int nochild)
+{
+ if (!bypassvirtual)
+ {
+ ASSERTPR(getParent() != NULL, "Virtual window created without specifying BaseWnd parent");
+
+ if (getStartHidden())
+ this_visible = 0;
+ else
+ this_visible = 1;
+
+ onInit();
+
+ onPostOnInit();
+
+ if (isVisible())
+ onSetVisible(1);
+
+ return 1;
+ }
+ else
+ return VIRTUALWND_PARENT::init(moduleHandle, parent, nochild);
+}
+
+OSWINDOWHANDLE VirtualWnd::getOsWindowHandle()
+{
+ // ASSERTPR(getParent() != NULL, "Virtual window used as base parent !");
+ if (!bypassvirtual)
+ {
+ if (!getParent())
+ return INVALIDOSWINDOWHANDLE;
+
+ return getParent()->getOsWindowHandle();
+ }
+ else
+ {
+ return VIRTUALWND_PARENT::getOsWindowHandle();
+ }
+}
+
+OSMODULEHANDLE VirtualWnd::getOsModuleHandle()
+{
+ if (!bypassvirtual)
+ {
+ if (!getParent())
+ return INVALIDOSMODULEHANDLE;
+
+ return getParent()->getOsModuleHandle();
+ }
+ else
+ return VIRTUALWND_PARENT::getOsModuleHandle();
+}
+
+void VirtualWnd::resize(RECT *r, int wantcb)
+{
+ if (!bypassvirtual)
+ {
+ resize(r->left, r->top, r->right - r->left, r->bottom - r->top, wantcb);
+ }
+ else
+ {
+ VIRTUALWND_PARENT::resize( r, wantcb );
+
+ //virtualX = rx;
+ //virtualY = ry;
+ //virtualW = rwidth;
+ //virtualH = rheight;
+ }
+}
+
+// fg> the resizecount > 1 is a hack, it should be 0 but i need more time to fix this thing, at least this way we don't lose the optim
+void VirtualWnd::resize(int x, int y, int w, int h, int wantcb)
+{
+ if (!bypassvirtual)
+ {
+ if (x == NOCHANGE)
+ x = virtualX;
+
+ if (y == NOCHANGE)
+ y = virtualY;
+
+ if (w == NOCHANGE)
+ w = virtualW;
+
+ if (h == NOCHANGE)
+ h = virtualH;
+
+ double thisratio = getRenderRatio();
+
+ if (resizecount > 1 && virtualX == x && virtualY == y && virtualW == w && virtualH == h && lastratio == thisratio)
+ return ;
+
+ lastratio = thisratio;
+
+ if (isVisible())
+ {
+ RECT r;
+ getNonClientRect(&r);
+ invalidateRect(&r);
+ }
+
+ virtualX = x;
+ virtualY = y;
+ virtualW = w;
+ virtualH = h;
+
+ if (isVisible())
+ {
+ RECT r;
+ getNonClientRect(&r);
+ invalidateRect(&r);
+ }
+
+ setRSize(x, y, w, h);
+
+ if (wantcb && isPostOnInit())
+ {
+ resizecount = MIN(resizecount + 1, 2);
+ onResize();
+ }
+ }
+ else
+ {
+ VIRTUALWND_PARENT::resize( x, y, w, h, wantcb );
+
+ //virtualX = rx;
+ //virtualY = ry;
+ //virtualW = rwidth;
+ //virtualH = rheight;
+ }
+}
+
+//CUTvoid VirtualWnd::resize(RECT *r) {
+//CUT resize(r->left, r->top, r->right-r->left, r->bottom-r->top);
+//CUT}
+
+void VirtualWnd::move(int x, int y)
+{
+ //DebugStringW( L"VirtualWnd::move( x = %d, y = %d )\n", x, y );
+
+ if (!bypassvirtual)
+ {
+ if (isVisible())
+ {
+ RECT r;
+ getNonClientRect(&r);
+ invalidateRect(&r);
+ }
+
+ virtualX = x;
+ virtualY = y;
+
+ if (isVisible())
+ {
+ RECT r;
+ getNonClientRect(&r);
+ invalidateRect(&r);
+ }
+ }
+ else
+ {
+ VIRTUALWND_PARENT::move( x, y );
+
+ //virtualX = x;
+ //virtualY = y;
+ }
+}
+
+void VirtualWnd::invalidate()
+{
+ if (!bypassvirtual)
+ {
+ if (!getRootParent()) return ;
+ RECT r(clientRect());
+ getRootParent()->invalidateRectFrom(&r, this);
+ // VIRTUALWND_PARENT::invalidate();
+ }
+ else
+ VIRTUALWND_PARENT::invalidate();
+}
+
+void VirtualWnd::invalidateRect(RECT *r)
+{
+ if (!bypassvirtual)
+ {
+ if (!getRootParent()) return ;
+ getRootParent()->invalidateRectFrom(r, this);
+ }
+ else
+ VIRTUALWND_PARENT::invalidateRect(r);
+}
+
+void VirtualWnd::invalidateRgn(api_region *reg)
+{
+ if (!bypassvirtual)
+ {
+ if (!getRootParent()) return ;
+ getRootParent()->invalidateRgnFrom(reg, this);
+ }
+ else
+ VIRTUALWND_PARENT::invalidateRgn(reg);
+}
+
+void VirtualWnd::validate()
+{
+ if (!bypassvirtual)
+ {
+ if (!getRootParent()) return ;
+ RECT r;
+ getClientRect(&r);
+ getRootParent()->validateRect(&r);
+ }
+ else
+ VIRTUALWND_PARENT::validate();
+}
+
+void VirtualWnd::validateRect(RECT *r)
+{
+ if (!bypassvirtual)
+ {
+ if (!getRootParent())
+ return ;
+
+ getRootParent()->validateRect(r);
+ }
+ else
+ VIRTUALWND_PARENT::validateRect( r );
+}
+
+void VirtualWnd::validateRgn(api_region *reg)
+{
+ if (!bypassvirtual)
+ {
+ if (!getRootParent()) return ;
+ getRootParent()->validateRgn(reg);
+ }
+ else
+ VIRTUALWND_PARENT::validateRgn(reg);
+}
+
+void VirtualWnd::getClientRect(RECT *rect)
+{
+ if (!bypassvirtual)
+ {
+ // CT:getClientRect behaves differently here for virtual windows
+ // so we can use onPaint directly on the destination canvas
+ // without using another temporary canvas.
+ Wasabi::Std::setRect(rect, virtualX, virtualY, virtualX + virtualW, virtualY + virtualH);
+ // rect->left=0; rect->right=virtualW;
+ // rect->top=0; rect->bottom=virtualH;
+ }
+ else
+ VIRTUALWND_PARENT::getClientRect(rect);
+}
+
+void VirtualWnd::getNonClientRect(RECT *rect)
+{
+ VirtualWnd::getClientRect(rect);
+}
+
+void VirtualWnd::getWindowRect(RECT *rect)
+{
+ if (!bypassvirtual)
+ {
+ RECT a;
+ getRootParent()->getWindowRect(&a);
+
+ int x = virtualX, y = virtualY, w = virtualW, h = virtualH;
+
+ if (renderRatioActive())
+ {
+ multRatio(&x, &y);
+ multRatio(&w, &h);
+ }
+
+ rect->left = a.left + x; rect->right = rect->left + w;
+ rect->top = a.top + y; rect->bottom = rect->top + h;
+ }
+ else
+ VIRTUALWND_PARENT::getWindowRect(rect);
+}
+
+int VirtualWnd::beginCapture()
+{
+ if (!bypassvirtual)
+ {
+ disable_tooltip_til_recapture = 0;
+ getRootParent()->setVirtualChildCapture(this);
+ return 1;
+ }
+ else
+ return VIRTUALWND_PARENT::beginCapture();
+}
+
+int VirtualWnd::endCapture()
+{
+ if (!bypassvirtual)
+ {
+ if (getRootParent() == NULL) return 0;
+ getRootParent()->setVirtualChildCapture(NULL);
+ return 1;
+ }
+ else
+ return VIRTUALWND_PARENT::endCapture();
+}
+
+int VirtualWnd::getCapture()
+{
+ if (!bypassvirtual)
+ {
+ if (getRootParent() == NULL) return 0;
+ return getRootParent()->getVirtualChildCapture() == this;
+ }
+ else
+ return VIRTUALWND_PARENT::getCapture();
+}
+
+void VirtualWnd::setVirtualChildCapture(BaseWnd *child)
+{
+ if (!bypassvirtual)
+ {
+ getParent()->setVirtualChildCapture(child);
+ }
+ else
+ VIRTUALWND_PARENT::setVirtualChildCapture(child);
+}
+
+// eek
+void VirtualWnd::repaint()
+{
+ if (!bypassvirtual)
+ {
+ if (!getParent()) return ;
+ getParent()->repaint();
+ }
+ else
+ VIRTUALWND_PARENT::repaint();
+}
+
+/*int VirtualWnd::focusNextSibbling(int dochild) {
+ return 1;
+}
+
+int VirtualWnd::focusNextVirtualChild(BaseWnd *child) {
+ return 1;
+}*/
+
+int VirtualWnd::cascadeRepaint(int pack)
+{
+ if (!bypassvirtual)
+ {
+ if (getRootParent())
+ {
+ RECT r;
+ VirtualWnd::getNonClientRect(&r);
+ getRootParent()->cascadeRepaintRectFrom(&r, this, pack);
+ }
+ return 1;
+ }
+ else
+ return VIRTUALWND_PARENT::cascadeRepaint(pack);
+}
+
+int VirtualWnd::cascadeRepaintRect(RECT *r, int pack)
+{
+ if (!bypassvirtual)
+ {
+ if (getRootParent())
+ {
+ getRootParent()->cascadeRepaintRectFrom(r, this, pack);
+ }
+ return 1;
+ }
+ else
+ return VIRTUALWND_PARENT::cascadeRepaintRect(r, pack);
+}
+
+int VirtualWnd::cascadeRepaintRgn(api_region *r, int pack)
+{
+ if (!bypassvirtual)
+ {
+ if (getRootParent())
+ {
+ getRootParent()->cascadeRepaintRgnFrom(r, this, pack);
+ }
+ return 1;
+ }
+ else
+ return VIRTUALWND_PARENT::cascadeRepaintRgn(r, pack);
+}
+
+/*api_window *VirtualWnd::getWindowBehindMyself(int x, int y) {
+ RECT r;
+ if (!bypassvirtual) {
+ if (!getParent()) return NULL;
+ int n = getParent()->getNumVirtuals();
+
+ api_window *c = NULL;
+
+ for (int i=n-1;i>=0;i++) {
+ c = getParent()->getVirtualChild(i);
+ if (c == this) break;
+ }
+
+ i--;
+ if (i < 0) return getParent();
+
+ for (;i>=0; i--) {
+ c = getParent()->getVirtualChild(i);
+ c->getNonClientRect(&r);
+ if (x>=r.left&&x<=r.right&&y>=r.top&&y<=r.bottom)
+ return c;
+ }
+ return getParent();
+ } else
+ return NULL;
+}*/
+
+ifc_window *VirtualWnd::rootWndFromPoint(POINT *pt)
+{
+ if (!bypassvirtual)
+ {
+ if (!getParent()) return NULL;
+ return getParent()->rootWndFromPoint(pt);
+ }
+ else
+ return VIRTUALWND_PARENT::rootWndFromPoint(pt);
+}
+
+double VirtualWnd::getRenderRatio()
+{
+ if (!bypassvirtual)
+ {
+ if (!getParent()) return 1.0;
+ return getParent()->getRenderRatio();
+ }
+ else
+ return VIRTUALWND_PARENT::getRenderRatio();
+}
+
+void VirtualWnd::bringToFront()
+{
+ if (!bypassvirtual)
+ {
+ if (!getParent()) return ;
+ //getParent()->bringVirtualToFront(this); TODO: FIX!!!
+ }
+ else
+ VIRTUALWND_PARENT::bringToFront();
+}
+
+void VirtualWnd::bringToBack()
+{
+ if (!bypassvirtual)
+ {
+ if (!getParent()) return ;
+ //getParent()->bringVirtualToBack(this); TODO: FIX!!!
+ }
+ else
+ VIRTUALWND_PARENT::bringToBack();
+}
+
+void VirtualWnd::bringAbove(BaseWnd *o)
+{
+ if (!bypassvirtual)
+ {
+ if (!getParent()) return ;
+ getParent()->bringVirtualAbove(this, o);
+ } /* else
+ VIRTUALWND_PARENT::bringAbove();*/
+}
+
+void VirtualWnd::bringBelow(BaseWnd *o)
+{
+ if (!bypassvirtual)
+ {
+ if (!getParent()) return ;
+ getParent()->bringVirtualBelow(this, o);
+ } /* else
+ VIRTUALWND_PARENT::bringBelow();*/
+}
+
+int VirtualWnd::reparent(ifc_window *newparent)
+{
+ if (!bypassvirtual)
+ {
+ if (getParent())
+ getParent()->unregisterRootWndChild(this);
+ parentWnd = NULL;
+ newparent->registerRootWndChild(this);
+ onSetParent(newparent);
+ newparent->invalidate();
+ return 1;
+ }
+ else
+ {
+ return VIRTUALWND_PARENT::reparent(newparent);
+ }
+}
+
+int VirtualWnd::setVirtual(int i)
+{
+ // ASSERT(!isInited()); // cut
+
+ if (isInited()) return 0;
+ bypassvirtual = !i;
+ return 1;
+}
+
+ifc_window *VirtualWnd::getRootParent()
+{
+ if (!bypassvirtual)
+ {
+ if (!getParent()) return NULL;
+ ifc_window *t = this;
+ while (t->isVirtual())
+ {
+ if (!t->getParent()) return NULL;
+ t = t->getParent();
+ }
+ return t;
+ }
+ else
+ {
+ return VIRTUALWND_PARENT::getRootParent();
+ }
+}
+
+int VirtualWnd::gotFocus()
+{
+ if (!bypassvirtual)
+ return focus;
+ else
+ return VIRTUALWND_PARENT::gotFocus();
+}
+
+int VirtualWnd::onGetFocus()
+{
+ if (!bypassvirtual)
+ {
+ focus = 1;
+ getRootParent()->onSetRootFocus(this);
+ invalidate();
+ Accessible *a = getAccessibleObject();
+ if (a != NULL)
+ a->onGetFocus();
+ }
+ else
+ return VIRTUALWND_PARENT::onGetFocus();
+ return 1;
+}
+
+int VirtualWnd::onKillFocus()
+{
+ if (!bypassvirtual)
+ {
+ focus = 0;
+ invalidate();
+ }
+ else
+ return VIRTUALWND_PARENT::onKillFocus();
+ return 1;
+}
+
+void VirtualWnd::setFocus()
+{
+ ifc_window *f = this;
+ if (!f->wantFocus() && f->getParent())
+ {
+ while (f)
+ {
+ ifc_window *rp = f->getRootParent();
+ if (rp == f) rp = f->getParent();
+ f = rp;
+ if (f && (!f->getParent() || f->wantFocus() || f == WASABI_API_WND->main_getRootWnd()))
+ {
+ f->setFocus();
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (!bypassvirtual)
+ {
+ if (getParent())
+ {
+ getParent()->setVirtualChildFocus(this);
+ }
+ }
+ else
+ VIRTUALWND_PARENT::setFocus();
+ }
+}
+
+void VirtualWnd::setVirtualChildFocus(ifc_window *child)
+{
+ if (!bypassvirtual)
+ {
+ getParent()->setVirtualChildFocus(child);
+ }
+ else
+ VIRTUALWND_PARENT::setVirtualChildFocus(child);
+}
+
+int VirtualWnd::onActivate()
+{
+ if (bypassvirtual)
+ return VIRTUALWND_PARENT::onActivate();
+ return 1;
+}
+
+int VirtualWnd::onDeactivate()
+{
+ if (bypassvirtual)
+ return VIRTUALWND_PARENT::onDeactivate();
+ return 1;
+}
+
+void VirtualWnd::setAllowDeactivation(int allow)
+{
+ ifc_window *w = getDesktopParent();
+ if (w != NULL && w != this)
+ w->setAllowDeactivation(allow);
+ else VIRTUALWND_PARENT::setAllowDeactivation(allow);
+}
+
+int VirtualWnd::allowDeactivation()
+{
+ ifc_window *w = getDesktopParent();
+ if (w != NULL && w != this)
+ return w->allowDeactivation();
+ return VIRTUALWND_PARENT::allowDeactivation();
+}
+
+
+
+/* todo: setCursor
+
+ + real childs going invisible should deferedInvalidate their rect on their parent window if it has a virtualCanvas
+*/
+
+
+
+// No need for screenToClient/clientToScreen overrides since the virtual's origin is the same as it's parent
diff --git a/Src/Wasabi/api/wnd/virtualwnd.h b/Src/Wasabi/api/wnd/virtualwnd.h
new file mode 100644
index 00000000..fc10ef63
--- /dev/null
+++ b/Src/Wasabi/api/wnd/virtualwnd.h
@@ -0,0 +1,84 @@
+#ifndef _VIRTUALWND_H
+#define _VIRTUALWND_H
+
+#include <api/wnd/basewnd.h>
+
+#define VIRTUALWND_PARENT BaseWnd
+#define AUTOWH 0xFFFE
+#define NOCHANGE 0xFFFD
+
+class NOVTABLE VirtualWnd : public VIRTUALWND_PARENT
+{
+protected:
+ VirtualWnd();
+ virtual ~VirtualWnd();
+public:
+ virtual int init( ifc_window *parent, int nochild = FALSE );
+ virtual int init( OSMODULEHANDLE moduleHandle, OSWINDOWHANDLE parent, int nochild = FALSE );
+
+ virtual void bringToFront();
+ virtual void bringToBack();
+ virtual void bringAbove( BaseWnd *w );
+ virtual void bringBelow( BaseWnd *w );
+
+ //NONPORTABLE--avoid prolonged use
+ virtual HWND getOsWindowHandle();
+ virtual HINSTANCE getOsModuleHandle();
+
+public:
+ virtual void resize( int x, int y, int w, int h, int wantcb = 1 ) override;
+ virtual void resize( RECT *r, int wantcb = 1 );
+ virtual void move( int x, int y ) override;
+ virtual void invalidate() override;
+ virtual void invalidateRect( RECT *r ) override;
+ virtual void invalidateRgn( api_region *reg ) override;
+ virtual void validate() override;
+ virtual void validateRect( RECT *r ) override;
+ virtual void validateRgn( api_region *reg ) override;
+ virtual void getClientRect( RECT * ) override;
+ virtual void getNonClientRect( RECT * ) override;
+ virtual void getWindowRect( RECT * ) override;
+ virtual int beginCapture() override;
+ virtual int endCapture() override;
+ virtual int getCapture() override;
+ virtual void setVirtualChildCapture( BaseWnd *child );
+ virtual void repaint() override;
+ /* virtual int focusNextSibbling(int dochild);
+ virtual int focusNextVirtualChild(BaseWnd *child);*/
+ virtual int cascadeRepaint( int pack = 1 ) override;
+ virtual int cascadeRepaintRect( RECT *r, int pack = 1 ) override;
+ virtual int cascadeRepaintRgn( api_region *r, int pack = 1 ) override;
+ virtual ifc_window *rootWndFromPoint( POINT *pt ) override;
+ virtual double getRenderRatio() override;
+ virtual int reparent( ifc_window *newparent ) override;
+ virtual int setVirtual( int i ) override;
+ virtual ifc_window *getRootParent() override;
+ virtual int gotFocus() override;
+ virtual int onGetFocus() override;
+ virtual int onKillFocus() override;
+ virtual void setFocus() override;
+ virtual int onActivate() override;
+ virtual int onDeactivate() override;
+ virtual void setVirtualChildFocus( ifc_window *child ) override;
+ virtual int wantFocus() override
+ {
+ return 0;
+ }
+ virtual void setAllowDeactivation( int allow ) override;
+ virtual int allowDeactivation() override;
+
+public:
+ virtual int isVirtual() override
+ {
+ return !bypassvirtual;
+ }
+
+protected:
+ int virtualX, virtualY, virtualH, virtualW;
+ int bypassvirtual;
+ int focus;
+ int resizecount;
+ double lastratio;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndapi.cpp b/Src/Wasabi/api/wnd/wndapi.cpp
new file mode 100644
index 00000000..25de4d94
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndapi.cpp
@@ -0,0 +1,384 @@
+#include <precomp.h>
+#include <api.h>
+#include "wndapi.h"
+#include <api/wnd/api_window.h>
+#include <tataki/canvas/ifc_canvas.h>
+
+#include <api/wnd/deactivatemgr.h>
+#include <api/wnd/wndtrack.h>
+
+#include <api/syscb/callbacks/consolecb.h>
+#include <api/wnd/keyboard.h>
+
+#ifdef WASABI_COMPILE_SKIN
+// #include <api/skin/groupmgr.h>
+#endif
+
+#ifdef WASABI_COMPILE_PAINTSETS
+#ifdef WASABI_COMPILE_IMGLDR
+ #include <api/wnd/paintset.h>
+#endif
+#endif
+
+#ifdef WASABI_COMPILE_SKIN
+//#include <api/skin/skin.h>
+#endif
+#include <bfc/stack.h>
+#include <tataki/region/region.h>
+wnd_api *wndApi = NULL;
+
+#ifndef ODS
+#define ODS(msg1, msg2) __ODS(__LINE__, msg1, msg2, 0);
+#endif
+
+static Stack<ifc_window*> modal_wnd_stack;
+
+static void __ODS(int line, wchar_t *message1, wchar_t *message2, int severity) {
+ StringPrintfW s(L"wndApi(%d): %s: %s\n", line, message1, message2);
+#ifdef WIN32
+ DebugStringW(L"%s\n", s);
+#endif
+ WASABI_API_SYSCB->syscb_issueCallback(SysCallback::CONSOLE, ConsoleCallback::DEBUGMESSAGE, severity, reinterpret_cast<intptr_t>(s.getValue()));
+}
+
+WndApi::WndApi()
+{
+}
+
+WndApi::~WndApi()
+{
+
+}
+
+void WndApi::main_setRootWnd(ifc_window *w) {
+ genericwnd = w;
+}
+
+ifc_window *WndApi::main_getRootWnd() {
+ return genericwnd;
+}
+
+ifc_window *WndApi::getModalWnd() {
+ if (!modal_wnd_stack.peek()) return NULL;
+ return modal_wnd_stack.top();
+}
+
+void WndApi::pushModalWnd(ifc_window *w) {
+ modal_wnd_stack.push(w);
+}
+
+void WndApi::popModalWnd(ifc_window *w) {
+ if (getModalWnd() != w) return;
+ modal_wnd_stack.pop();
+}
+/* TODO: Benski> move to api_wndmgr */
+ifc_window *WndApi::rootWndFromPoint(POINT *pt) {
+ return WindowTracker::rootWndFromPoint(pt);
+}
+
+ifc_window *WndApi::rootWndFromOSHandle(OSWINDOWHANDLE wnd) {
+ return WindowTracker::rootWndFromHwnd(wnd);
+}
+
+void WndApi::registerRootWnd(ifc_window *wnd) {
+ WindowTracker::addRootWnd(wnd);
+}
+
+void WndApi::unregisterRootWnd(ifc_window *wnd) {
+ WindowTracker::removeRootWnd(wnd);
+}
+/* --- end TO MOVE ---*/
+
+int WndApi::rootwndIsValid(ifc_window *wnd) {
+ return windowTracker->checkWindow(wnd);
+}
+void WndApi::hookKeyboard(ifc_window *hooker) {
+ Keyboard::hookKeyboard(hooker);
+}
+
+void WndApi::unhookKeyboard(ifc_window *hooker) {
+ Keyboard::unhookKeyboard(hooker);
+}
+
+void WndApi::kbdReset() {
+ Keyboard::reset();
+}
+
+// so when a key is pressed in a basewnd, it is first intercepted and sent to these functions to check if the system should handle it instead of the wnd...
+
+int WndApi::interceptOnChar(unsigned int c) {
+ return Keyboard::interceptOnChar(c);
+}
+
+int WndApi::interceptOnKeyDown(int k) {
+ return Keyboard::interceptOnKeyDown(k);
+}
+
+int WndApi::interceptOnKeyUp(int k) {
+ return Keyboard::interceptOnKeyUp(k);
+}
+
+int WndApi::interceptOnSysKeyDown(int k, int kd) {
+ return Keyboard::interceptOnSysKeyDown(k, kd);
+}
+
+int WndApi::interceptOnSysKeyUp(int k, int kd) {
+ return Keyboard::interceptOnSysKeyUp(k, kd);
+}
+
+// ... if not, then it is sent to the wnd, and if the wnd doesn't need it, it is then forwarded to the system again, for default handling :
+
+int WndApi::forwardOnChar(ifc_window *from, unsigned int c, int kd) {
+ return Keyboard::onForwardOnChar(from, c, kd);
+}
+
+int WndApi::forwardOnKeyDown(ifc_window *from, int k, int kd) {
+ return Keyboard::onForwardOnKeyDown(from, k, kd);
+}
+
+int WndApi::forwardOnKeyUp(ifc_window *from, int k, int kd) {
+ return Keyboard::onForwardOnKeyUp(from, k, kd);
+}
+
+int WndApi::forwardOnSysKeyDown(ifc_window *from, int k, int kd) {
+ return Keyboard::onForwardOnSysKeyDown(from, k, kd);
+}
+
+int WndApi::forwardOnSysKeyUp(ifc_window *from, int k, int kd) {
+ return Keyboard::onForwardOnSysKeyUp(from, k, kd);
+}
+
+int WndApi::forwardOnKillFocus() {
+ return Keyboard::onForwardOnKillFocus();
+}
+
+void WndApi::popupexit_register(PopupExitCallback *cb, ifc_window *watched)
+{
+ popupExitChecker.registerCallback(cb, watched);
+}
+void WndApi::popupexit_deregister(PopupExitCallback *cb)
+{
+ popupExitChecker.deregisterCallback(cb);
+}
+
+int WndApi::popupexit_check(ifc_window *w) {
+
+ return popupExitChecker.check(w);
+}
+
+void WndApi::popupexit_signal()
+{
+ popupExitChecker.signal();
+}
+
+#define RenderBaseTexture renderBaseTexture //CUT
+void WndApi::skin_renderBaseTexture(ifc_window *basetexturewnd, ifc_canvas *c, const RECT *r, ifc_window *destwnd, int alpha) {
+ if (c == NULL) {
+ ODS(L"illegal param", L"c == NULL");
+ return;
+ }
+ if (basetexturewnd == NULL) {
+ ODS(L"illegal param", L"base == NULL");
+ BaseCloneCanvas canvas(c);
+ canvas.fillRect(r, 0xFF00FF);
+ return;
+ }
+ if (destwnd == NULL) {
+ ODS(L"illegal param", L"destwnd == NULL");
+ return;
+ }
+ renderBaseTexture(basetexturewnd, c, *r, destwnd, alpha);
+}
+
+void WndApi::skin_registerBaseTextureWindow(ifc_window *window, const wchar_t *bitmap) {
+ if (window == NULL) {
+ ODS(L"illegal param", L"window == NULL");
+ return;
+ }
+ BaseTexture *s = new BaseTexture(window, bitmap);
+ baseTextureList.addItem(s);
+}
+
+void WndApi::skin_unregisterBaseTextureWindow(ifc_window *window) {
+ if (window == NULL) {
+ ODS(L"illegal param", L"window == NULL");
+ return;
+ }
+ for (int i=0;i<baseTextureList.getNumItems();i++) {
+ if (baseTextureList.enumItem(i)->getWnd() == window) {
+ BaseTexture *s = baseTextureList.enumItem(i);
+ baseTextureList.delByPos(i);
+ delete s;
+ if (baseTextureList.getNumItems() == 0)
+ baseTextureList.removeAll();
+ break;
+ }
+ }
+}
+
+void WndApi::appdeactivation_push_disallow(ifc_window *from_whom) {
+ AppDeactivationMgr::push_disallow(from_whom);
+}
+
+void WndApi::appdeactivation_pop_disallow(ifc_window *from_whom) {
+ AppDeactivationMgr::pop_disallow(from_whom);
+}
+
+int WndApi::appdeactivation_isallowed(ifc_window *w) {
+ return AppDeactivationMgr::is_deactivation_allowed(w);
+}
+
+void WndApi::appdeactivation_setbypass(int i) {
+ AppDeactivationMgr::setbypass(i);
+}
+
+#ifdef WASABI_COMPILE_PAINTSETS
+#ifdef WASABI_COMPILE_IMGLDR
+
+void WndApi::paintset_render(int set, ifc_canvas *c, const RECT *r, int alpha) {
+ if (c == NULL) {
+ ODS(L"illegal param", L"c == NULL");
+ return;
+ }
+ if (r == NULL) {
+ ODS(L"illegal param", L"r == NULL");
+ return;
+ }
+ paintset_renderPaintSet(set, c, r, alpha);
+}
+
+#ifdef WASABI_COMPILE_FONTS
+void WndApi::paintset_renderTitle(const wchar_t *t, ifc_canvas *c, const RECT *r, int alpha) {
+ if (c == NULL) {
+ ODS(L"illegal param", L"c == NULL");
+ return;
+ }
+ if (r == NULL) {
+ ODS(L"illegal param", L"r == NULL");
+ return;
+ }
+ ::paintset_renderTitle(t, c, r, alpha);
+}
+#endif // WASABI_COMPILE_FONTS
+#endif // WASABI_COMPILE_IMGLDR
+#endif // WASABI_COMPILE_PAINTSETS
+
+BaseTexture *WndApi::getBaseTexture(ifc_window *b) {
+ if (b == NULL) return NULL;
+ for (int i=0;i<baseTextureList.getNumItems();i++)
+ if (baseTextureList.enumItem(i)->getWnd() == b)
+ return baseTextureList.enumItem(i);
+ return NULL;
+}
+
+void WndApi::renderBaseTexture(ifc_window *base, ifc_canvas *c, const RECT &r, ifc_window *dest, int alpha) {
+ renderBaseTexture(base, getBaseTexture(base), c, r, dest, alpha);
+}
+
+void WndApi::renderBaseTexture(ifc_window *base, BaseTexture *bt, ifc_canvas *c, const RECT &r, ifc_window *dest, int alpha) {
+ if (!bt) {
+ DebugString("Warning, no base texture found in renderBaseTexture\n");
+ return;
+ }
+
+ bt->renderBaseTexture(base, c, r, dest, alpha);
+}
+
+#ifndef SAFEROUND
+#define SAFEROUND(d) ((float)(int)d == d) ? (int)d : (d - (float)(int)d > 0) ? ((int)d)+1 : ((int)d)-1
+#endif
+
+void BaseTexture::renderBaseTexture(ifc_window *wndbase, ifc_canvas *c, const RECT &r, ifc_window *dest, int alpha)
+{
+ // pick our basetexture
+ AutoSkinBitmap *b = &texture;
+
+ if(!b) return;
+
+ // srcRect is the source rectangle in the basetexture
+ RECT srcRect;
+ // destProjectedRect is the basetexture rectangle projected to dest coordinates
+ RECT destProjectedRect;
+
+ ifc_window *p = dest;
+ POINT pt;
+ int sx=0, sy=0;
+ while (p && p != wndbase) {
+ if (!p->isVirtual()) {
+ p->getPosition(&pt);
+ sx += pt.x;
+ sy += pt.y;
+ }
+ p = p->getParent();
+ }
+ ASSERT(p);
+
+ wndbase->getNonClientRect(&destProjectedRect);
+ Wasabi::Std::offsetRect(&destProjectedRect, -sx, -sy);
+
+ Wasabi::Std::setRect(&srcRect, 0, 0, b->getWidth(), b->getHeight());
+
+#if 0
+ // NONPORTABLE
+ HDC hdc=c->getHDC();
+ HRGN oldRgn=CreateRectRgn(0,0,0,0);
+ HRGN newRgn=CreateRectRgnIndirect(&r);
+
+ int cs=GetClipRgn(hdc,oldRgn);
+
+ ExtSelectClipRgn(hdc,newRgn,(cs!=1)?RGN_COPY:RGN_AND);
+#endif
+#ifdef _WIN32
+ // TODO: review: wtf does this even accomplish? we're still blitting to c at the end
+ BaseCloneCanvas clone(c);
+ RegionI oldRgn;
+ RegionI newRgn(&r);
+
+ int cs = clone.getClipRgn(&oldRgn);
+
+ if ( cs ) newRgn.andRegion(&oldRgn);
+
+ clone.selectClipRgn( &newRgn );
+#endif
+ b->stretchToRectAlpha(c, &srcRect, &destProjectedRect, alpha);
+
+#ifdef _WIN32
+ // TODO: review: wtf does this even accomplish? we're still blitting to c at the end
+ clone.selectClipRgn(cs ? &oldRgn : NULL);
+#endif
+}
+
+int WndApi::forwardOnMouseWheel(int l, int a) {
+ return 0;
+}
+
+#ifdef WASABI_COMPILE_PAINTSETS
+int WndApi::paintset_present(int set) {
+ return ::paintset_present(set);
+}
+#endif
+
+void WndApi::setDefaultDropTarget(void *dt) {
+ default_drop_target = dt;
+}
+
+void *WndApi::getDefaultDropTarget() {
+ return default_drop_target;
+}
+
+int WndApi::pushKeyboardLock() {
+ return ++kbdlock;
+}
+
+int WndApi::popKeyboardLock() {
+ return --kbdlock;
+}
+
+int WndApi::isKeyboardLocked() {
+ return kbdlock;
+}
+
+ifc_window *WndApi::genericwnd = NULL;
+PtrList<BaseTexture> WndApi::baseTextureList;
+void *WndApi::default_drop_target = NULL;
+int WndApi::kbdlock = 0;
diff --git a/Src/Wasabi/api/wnd/wndapi.h b/Src/Wasabi/api/wnd/wndapi.h
new file mode 100644
index 00000000..21e5a748
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndapi.h
@@ -0,0 +1,101 @@
+#ifndef _WNDAPI_H
+#define _WNDAPI_H
+
+#include <api/wnd/api_wnd.h>
+#include <bfc/ptrlist.h>
+#include <tataki/bitmap/autobitmap.h>
+#include <api/wnd/popexitchecker.h>
+// ---
+
+class BaseTexture
+{
+ public:
+ BaseTexture(ifc_window *_wnd, const wchar_t *_bmp) : wnd(_wnd), texture(_bmp) {}
+ virtual ~BaseTexture() {}
+
+ SkinBitmap *getTexture() { return texture.getBitmap(); }
+ ifc_window *getWnd() { return wnd; }
+
+ virtual void renderBaseTexture(ifc_window *wndbase, ifc_canvas *c, const RECT &r, ifc_window *dest, int alpha);
+
+ private:
+ ifc_window *wnd;
+ AutoSkinBitmap texture;
+};
+
+// ---
+
+class WndApi : public wnd_apiI
+{
+ public:
+
+ WndApi();
+ virtual ~WndApi();
+
+ virtual ifc_window *main_getRootWnd();
+ virtual void main_setRootWnd(ifc_window *w);
+ virtual ifc_window *getModalWnd();
+ virtual void pushModalWnd(ifc_window *w=MODALWND_NOWND);
+ virtual void popModalWnd(ifc_window *w=MODALWND_NOWND);
+ virtual ifc_window *rootWndFromPoint(POINT *pt);
+ virtual ifc_window *rootWndFromOSHandle(OSWINDOWHANDLE wnd);
+ virtual void registerRootWnd(ifc_window *wnd);
+ virtual void unregisterRootWnd(ifc_window *wnd);
+ virtual int rootwndIsValid(ifc_window *wnd);
+ virtual void hookKeyboard(ifc_window *hooker);
+ virtual void unhookKeyboard(ifc_window *hooker);
+ virtual void kbdReset();
+ virtual int interceptOnChar(unsigned int c);
+ virtual int interceptOnKeyDown(int k);
+ virtual int interceptOnKeyUp(int k);
+ virtual int interceptOnSysKeyDown(int k, int kd);
+ virtual int interceptOnSysKeyUp(int k, int kd);
+ virtual int forwardOnChar(ifc_window *from, unsigned int c, int kd);
+ virtual int forwardOnKeyDown(ifc_window *from, int k, int kd);
+ virtual int forwardOnKeyUp(ifc_window *from, int k, int kd);
+ virtual int forwardOnSysKeyDown(ifc_window *from, int k, int kd);
+ virtual int forwardOnSysKeyUp(ifc_window *from, int k, int kd);
+ virtual int forwardOnKillFocus();
+ virtual void popupexit_deregister(PopupExitCallback *cb);
+ virtual void popupexit_register(PopupExitCallback *cb, ifc_window *watched);
+ virtual int popupexit_check(ifc_window *w);
+ virtual void popupexit_signal();
+ virtual void skin_renderBaseTexture(ifc_window *base, ifc_canvas *c, const RECT *r, ifc_window *destWnd, int alpha=255);
+ virtual void skin_registerBaseTextureWindow(ifc_window *window, const wchar_t *bmp=NULL);
+ virtual void skin_unregisterBaseTextureWindow(ifc_window *window);
+ virtual void appdeactivation_push_disallow(ifc_window *w);
+ virtual void appdeactivation_pop_disallow(ifc_window *w);
+ virtual int appdeactivation_isallowed(ifc_window *w);
+ virtual void appdeactivation_setbypass(int i);
+#ifdef WASABI_COMPILE_PAINTSETS
+ virtual int paintset_present(int set);
+#ifdef WASABI_COMPILE_IMGLDR
+ virtual void paintset_render(int set, ifc_canvas *c, const RECT *r, int alpha=255);
+#ifdef WASABI_COMPILE_FONTS
+ virtual void paintset_renderTitle(const wchar_t *t, ifc_canvas *c, const RECT *r, int alpha=255);
+#endif // fonts
+#endif // imgldr
+#endif // paintsets
+ virtual int forwardOnMouseWheel(int l, int a);
+ virtual void setDefaultDropTarget(void *dt);
+ virtual void *getDefaultDropTarget();
+ static int getNumBaseTextures() { return baseTextureList.getNumItems(); }
+ virtual int pushKeyboardLock();
+ virtual int popKeyboardLock();
+ virtual int isKeyboardLocked();
+
+ PopupExitChecker popupExitChecker;
+ private:
+
+ static BaseTexture *getBaseTexture(ifc_window *b);
+ static void renderBaseTexture(ifc_window *base, ifc_canvas *c, const RECT &r, ifc_window *dest, int alpha);
+ static void renderBaseTexture(ifc_window *base, BaseTexture *s, ifc_canvas *c, const RECT &r, ifc_window *dest, int alpha);
+ static PtrList<BaseTexture> baseTextureList;
+ static ifc_window *genericwnd;
+ static void *default_drop_target;
+ static int kbdlock;
+};
+
+extern WndApi _wndApi;
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/SelItemList.cpp b/Src/Wasabi/api/wnd/wndclass/SelItemList.cpp
new file mode 100644
index 00000000..07f5edd9
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/SelItemList.cpp
@@ -0,0 +1,72 @@
+#include <precomp.h>
+#include "SelItemList.h"
+#include "listwnd.h"
+
+#define SELITEMEXPAND 2040
+
+SelItemList::SelItemList(ListWnd *parent) :
+listwnd(parent), list(SELITEMEXPAND), num_selected(0) { }
+
+void SelItemList::setSelected(int pos, int selected, int cb)
+{
+ int s = list.getSize();
+ if (pos >= s)
+ {
+ if (!selected)
+ {
+ // turning off something that's out of range is a no-brainer
+ return ;
+ }
+ s = ((s / SELITEMEXPAND) + 1) * SELITEMEXPAND;
+ list.setSize(s);
+ }
+
+ char *l = list.getMemory();
+ if (selected)
+ {
+ // quick and dirty way to prevent more than one item from
+ // ever being selected?
+ if (listwnd->getPreventMultipleSelection())
+ {
+ listwnd->deselectAll(cb);
+ }
+ if (!isSelected(pos))
+ {
+ l[pos] = 1;
+ num_selected++;
+ if (cb) listwnd->itemSelection(pos, TRUE);
+ listwnd->invalidateItem(pos);
+ }
+ }
+ else
+ {
+ if (isSelected(pos))
+ {
+ l[pos] = 0;
+ num_selected--;
+ if (cb) listwnd->itemSelection(pos, FALSE);
+ listwnd->invalidateItem(pos);
+ }
+ }
+}
+int SelItemList::isSelected(int pos)
+{
+ if (pos >= list.getSize()) return 0;
+ return list.getMemory()[pos];
+}
+int SelItemList::getNumSelected() { return num_selected; }
+
+void SelItemList::deleteByPos(int pos)
+{
+ ASSERT(pos >= 0);
+ int s = list.getSize();
+ if (pos >= s) return ;
+ num_selected -= isSelected(pos);
+ char *m = list.getMemory() + pos;
+ MEMCPY(m, m + 1, s - (pos + 1));
+}
+void SelItemList::deselectAll()
+{ // for internal use, doesn't send callbacks
+ list.zeroMemory();
+ num_selected = 0;
+}
diff --git a/Src/Wasabi/api/wnd/wndclass/SelItemList.h b/Src/Wasabi/api/wnd/wndclass/SelItemList.h
new file mode 100644
index 00000000..f17a1511
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/SelItemList.h
@@ -0,0 +1,31 @@
+#ifndef NULLSOFT_SELITEMLISTH
+#define NULLSOFT_SELITEMLISTH
+
+class ListWnd;
+
+#define SELITEMEXPAND 2040
+
+//note to whoever redid this as a bitlist
+// a) this is pointlessly slow as a bitlist given the memory used
+// b) perhaps you should investigate bitlist.h
+class SelItemList
+{
+public:
+ SelItemList(ListWnd *parent);
+
+ void setSelected(int pos, int selected, int cb=1);
+ int isSelected(int pos);
+ int getNumSelected();
+
+ void deleteByPos(int pos);
+protected:
+friend ListWnd;
+ void deselectAll();
+
+private:
+ ListWnd *listwnd;
+ MemBlock<char> list;
+ int num_selected;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/wndclass/abstractwndhold.cpp b/Src/Wasabi/api/wnd/wndclass/abstractwndhold.cpp
new file mode 100644
index 00000000..95af35a8
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/abstractwndhold.cpp
@@ -0,0 +1,287 @@
+#include "precomp.h"
+#include <api/syscb/api_syscb.h>
+
+#include "abstractwndhold.h"
+#include <api/service/svc_enum.h>
+#include <api/wnd/wndclass/guiobjwnd.h>
+#include <api/service/svcs/svc_wndcreate.h>
+#include <api/script/scriptguid.h>
+#include <api/script/objects/c_script/c_guiobject.h>
+#include <api/script/objects/c_script/c_group.h>
+#include <api/wnd/notifmsg.h>
+
+
+#define CB_ABSTRACTLOAD 0x1125
+
+AbstractWndHolder::AbstractWndHolder(const wchar_t *grpid, int autoresize) : ServiceWndHolder(NULL, NULL)
+{
+ scripts_enabled = 1;
+ groupid = grpid;
+ group_item = NULL;
+ guid = INVALID_GUID;
+ group = NULL;
+ cbreg = 0;
+ inselfresize = 0;
+ autoresizefromcontent = autoresize;
+ allow_deferred_content = 0;
+ need_deferred_load = 0;
+}
+
+AbstractWndHolder::AbstractWndHolder(SkinItem *groupitem, int autoresize) : ServiceWndHolder(NULL, NULL) {
+ group_item = groupitem;
+ guid = INVALID_GUID;
+ group = NULL;
+ cbreg = 0;
+ inselfresize = 0;
+ autoresizefromcontent = autoresize;
+ allow_deferred_content = 0;
+ need_deferred_load = 0;
+}
+
+AbstractWndHolder::AbstractWndHolder(GUID g, int autoresize) : ServiceWndHolder(NULL, NULL) {
+ guid = g;
+ group = NULL;
+ cbreg = 0;
+ group_item = NULL;
+ inselfresize = 0;
+ autoresizefromcontent = autoresize;
+ allow_deferred_content = 0;
+ need_deferred_load = 0;
+}
+
+AbstractWndHolder::~AbstractWndHolder() {
+ if (group) {
+#ifdef WASABI_COMPILE_SKIN
+ WASABI_API_SKIN->group_destroy(group);
+#endif
+ group = NULL;
+ }
+ if (cbreg) WASABI_API_SYSCB->syscb_deregisterCallback(this);
+}
+
+int AbstractWndHolder::onInit() {
+ ABSTRACTWNDHOLDER_PARENT::onInit();
+ createChild();
+ return 1;
+}
+
+ifc_window *AbstractWndHolder::rootwndholder_getRootWnd() {
+ if (group != NULL) return group;
+ return ABSTRACTWNDHOLDER_PARENT::rootwndholder_getRootWnd();
+}
+
+void AbstractWndHolder::abstract_setContent(const wchar_t *group_id, int autoresize)
+{
+ setBothContent(group_id, INVALID_GUID, autoresize);
+}
+
+void AbstractWndHolder::abstract_setContentBySkinItem(SkinItem *item, int autoresize) {
+ setContentSkinItem(item, autoresize);
+}
+
+void AbstractWndHolder::abstract_setContent(GUID g, int autoresize) {
+ setBothContent(NULL, g, autoresize);
+}
+
+void AbstractWndHolder::setBothContent(const wchar_t *group_id, GUID g, int autoresize)
+{
+ group_item = NULL;
+ if (autoresize != -1)
+ autoresizefromcontent = autoresize;
+ if (WCSCASEEQLSAFE(groupid, group_id) || (guid != INVALID_GUID && guid == g)) return;
+ GUID _g = nsGUID::fromCharW(group_id);
+ if (g == INVALID_GUID && _g != INVALID_GUID) {
+ groupid = NULL;
+ guid = _g;
+ } else {
+ groupid = group_id;
+ guid = g;
+ }
+ createChild();
+}
+
+void AbstractWndHolder::setContentSkinItem(SkinItem *item, int autoresize)
+{
+ if (autoresize != -1)
+ autoresizefromcontent = autoresize;
+ groupid.trunc(0);
+ guid = INVALID_GUID;
+ group_item = item;
+ createChild();
+}
+
+int AbstractWndHolder::onGroupChange(const wchar_t *grpid)
+{
+ if (WCSCASEEQLSAFE(groupid, grpid))
+ {
+ createChild();
+ notifyParent(ChildNotify::GROUPRELOAD);
+ notifyParent(ChildNotify::AUTOWHCHANGED);
+ }
+ return 1;
+}
+
+void AbstractWndHolder::createChild() {
+ if (!isInited()) return;
+ destroyContent();
+ if (allow_deferred_content && !isVisible())
+ need_deferred_load = 1;
+ else
+ doLoadContent();
+}
+
+void AbstractWndHolder::destroyContent()
+{
+ if (group != NULL) {
+#ifdef WASABI_COMPILE_SKIN
+ WASABI_API_SKIN->group_destroy(group);
+#endif
+ if (cbreg) {
+ WASABI_API_SYSCB->syscb_deregisterCallback(this);
+ cbreg=0;
+ }
+ ABSTRACTWNDHOLDER_PARENT::setChild(NULL, NULL);
+ }
+ group = NULL;
+}
+
+int AbstractWndHolder::onDeferredCallback(intptr_t p1, intptr_t p2)
+{
+ if (p1 == CB_ABSTRACTLOAD) {
+ doLoadContent();
+ return 1;
+ }
+ return ABSTRACTWNDHOLDER_PARENT::onDeferredCallback(p1, p2);
+}
+
+#include <bfc/util/profiler.h>
+
+void AbstractWndHolder::doLoadContent() {
+ int didsomething = 0;
+ need_deferred_load = 0;
+ if (group_item != NULL) {
+#ifdef WASABI_COMPILE_SKIN
+ group = WASABI_API_SKIN->group_createBySkinItem(group_item, scripts_enabled);
+#endif
+ if (group) {
+ if (!cbreg) {
+ WASABI_API_SYSCB->syscb_registerCallback(this);
+ cbreg=1;
+ }
+ group->setParent(this);
+ group->init(this);
+ abstract_onNewContent();
+ didsomething = 1;
+ }
+ } else if (!groupid.isempty()) {
+#ifdef WASABI_COMPILE_SKIN
+ group = WASABI_API_SKIN->group_create(groupid, scripts_enabled);
+#endif
+ if (group) {
+ if (!cbreg) {
+ WASABI_API_SYSCB->syscb_registerCallback(this);
+ cbreg=1;
+ }
+ group->setParent(this);
+ group->init(this);
+ abstract_onNewContent();
+ didsomething = 1;
+ }
+ } else if (guid != INVALID_GUID) {
+ svc_windowCreate *svc = WindowCreateByGuidEnum(guid).getNext();
+ ABSTRACTWNDHOLDER_PARENT::setChild(svc->createWindowByGuid(guid, this), svc);
+ abstract_onNewContent();
+ didsomething = 1;
+ }
+ if (didsomething && isPostOnInit())
+ {
+ onResize();
+ }
+}
+
+void AbstractWndHolder::abstract_onNewContent()
+{
+ if (isPostOnInit()) {
+ ifc_window *w = getDesktopParent();
+ if (w != NULL) {
+ if (w->enumMinMaxEnforcer(0)) {
+ w->signalMinMaxEnforcerChanged();
+ }
+ }
+ }
+}
+
+GuiObject *AbstractWndHolder::abstract_findObject(const wchar_t *object_id)
+{
+ ifc_window *w = rootwndholder_getRootWnd();
+ if (w == NULL) return NULL;
+ GuiObject *o = static_cast<GuiObject *>(w->getInterface(guiObjectGuid));
+ return o->guiobject_findObject(object_id);
+}
+
+ScriptObject *AbstractWndHolder::abstract_findScriptObject(const wchar_t *object_id)
+{
+ ifc_window *w = rootwndholder_getRootWnd();
+ if (w == NULL) return NULL;
+ GuiObject *o = static_cast<GuiObject *>(w->getInterface(guiObjectGuid));
+ GuiObject *fo = o->guiobject_findObject(object_id);
+ if (fo != NULL) return fo->guiobject_getScriptObject();
+ return NULL;
+}
+
+
+GuiObject *AbstractWndHolder::abstract_getContent() {
+ ifc_window *w = rootwndholder_getRootWnd();
+ if (w == NULL) return NULL;
+ return static_cast<GuiObject *>(w->getInterface(guiObjectGuid));
+}
+
+ScriptObject *AbstractWndHolder::abstract_getContentScriptObject() {
+ ifc_window *w = rootwndholder_getRootWnd();
+ if (w == NULL) return NULL;
+ return static_cast<ScriptObject *>(w->getInterface(scriptObjectGuid));
+}
+
+int AbstractWndHolder::onResize() {
+ int rt = ABSTRACTWNDHOLDER_PARENT::onResize();
+ if (group != NULL && abstract_wantAutoResizeFromContent()) {
+ if (inselfresize) return rt;
+ inselfresize=1;
+ int w = group->getPreferences(SUGGESTED_W);
+ int h = group->getPreferences(SUGGESTED_H);
+ resize(NOCHANGE, NOCHANGE, w == AUTOWH ? NOCHANGE : w, h == AUTOWH ? NOCHANGE : h);
+ inselfresize = 0;
+ }
+ return rt;
+}
+
+void AbstractWndHolder::onSetVisible( int show )
+{
+ ABSTRACTWNDHOLDER_PARENT::onSetVisible( show );
+ if ( allow_deferred_content )
+ {
+ if ( show & need_deferred_load )
+ {
+ doLoadContent();
+ }
+ if ( !show && !need_deferred_load )
+ {
+ destroyContent();
+ need_deferred_load = 1;
+ }
+ }
+}
+
+void AbstractWndHolder::abstract_setScriptsEnabled(int en)
+{
+ if (scripts_enabled == en) return;
+ scripts_enabled = en;
+ if (group != NULL) {
+ destroyContent();
+ doLoadContent();
+ }
+}
+
+int AbstractWndHolder::abstact_getScriptsEnabled() {
+ return scripts_enabled;
+}
diff --git a/Src/Wasabi/api/wnd/wndclass/abstractwndhold.h b/Src/Wasabi/api/wnd/wndclass/abstractwndhold.h
new file mode 100644
index 00000000..c81ad683
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/abstractwndhold.h
@@ -0,0 +1,267 @@
+#ifndef __ABSTRACTWNDHOLD_H
+#define __ABSTRACTWNDHOLD_H
+
+#include <api/wnd/wndclass/svcwndhold.h>
+#include <api/syscb/callbacks/wndcb.h>
+
+class GuiObject;
+class ScriptObject;
+class SkinItem;
+
+#define ABSTRACTWNDHOLDER_PARENT ServiceWndHolder
+
+
+/**
+ The AbstractWndHolder enables you to display deferred content. This means
+ the content does not actually need to exist at creation. It will be automatically
+ loaded when it is found.
+
+ This class is meant to be derived from. You shouldn't create an AbstractWndHolder
+ directly to implement this kind of functionality. Please use GuiObjectWnd along
+ with the setContent() method.
+
+ @short An abstracted window holder with deferred content loading.
+ @author Nullsoft
+ @ver 1.0
+ @see GuiObjectWnd
+*/
+class AbstractWndHolder : public ABSTRACTWNDHOLDER_PARENT, public WndCallbackI {
+
+ protected:
+
+ // don't create me directly, create a GuiObjectWnd and setContent("group.id") on it
+ // these are for inheriting and have a deferred content (so if you _were_ using that,
+ // your findObjects would fail right after init and before abstract_onNewContent)
+
+ /**
+ Sets the group id of the content and the auto resize flag.
+
+ Setting the auto resize flag to 1 will enable the automatic resize of
+ the window according to the size of the content attempting to be
+ displayed.
+
+ @param groupid The content group.
+ @param _autoresizefromcontent 0, disable auto resize; 1, enable auto resize;
+ */
+ AbstractWndHolder(const wchar_t *groupid=NULL, int _autoresizefromcontent=0);
+ AbstractWndHolder(SkinItem *groupitem, int _autoresizefromcontent=0);
+
+ /**
+ Finds the group with the matching GUID and uses that group as the content.
+ This insures you get the exact group and not a replacement.
+
+ Setting the auto resize flag to 1 will enable the automatic resize of
+ the window according to the size of the content attempting to be
+ displayed.
+
+ @param _guid The GUID the content group.
+ @param _autoresizefromcontent 0, disable auto resize; 1, enable auto resize;
+ */
+ AbstractWndHolder(GUID _guid, int _autoresizefromcontent=0);
+
+ public:
+
+
+ /**
+ Destroys the instance of the group used for content automatically.
+ */
+ virtual ~AbstractWndHolder();
+
+
+ /**
+ Sets the content group using the group id.
+
+ @param groupid The content group id.
+ @param _autoresizefromcontent -1, no change; 0, disable auto resize; 1, enable auto resize;
+ */
+ virtual void abstract_setContent(const wchar_t *groupid, int _autoresizefromcontent=-1); // -1 = no change, 0 = false, 1 = true
+
+ /**
+ Sets the content group using the group's GUID.
+ This insures you get the exact group and not a replacement.
+
+ @param g The content group's GUID.
+ @param _autoresizefromcontent -1, no change; 0, disable auto resize; 1, enable auto resize;
+ */
+ virtual void abstract_setContent(GUID g, int _autoresizefromcontent=-1); // -1 = no change, 0 = false, 1 = true
+
+ virtual void abstract_setContentBySkinItem(SkinItem *groupitem, int _autoresizefromcontent=-1); // -1 = no change, 0 = false, 1 = true
+
+ /**
+ This event is triggered when the content is loaded or the content changes.
+ Override it to implement your own handling of this event.
+ */
+ virtual void abstract_onNewContent();
+
+ /**
+ This event is triggered when the content group is changed.
+ Override it to implement your own handling of this event.
+
+ @see abstract_setContant()
+ @ret 1, if you handle the event;
+ @param grpid The new group that was set.
+ */
+ virtual int onGroupChange(const wchar_t *grpid);
+
+ /**
+ This event is triggered when the visibility of the window changes.
+ Override it to implement your own handling of this event.
+
+ @see onGroupChange()
+ @param show 0, hide window; 1, show window;
+ */
+ virtual void onSetVisible(int show);
+
+
+ /**
+ This event is triggered when the window is being initialized.
+ Override it to implement your own handling of this event.
+
+ @ret 1, if you handle the event;
+ */
+ virtual int onInit();
+
+ /**
+ This event is triggered when the window is resized.
+ Override it to implement your own handling of this event.
+
+ @ret 1, if you handle the event;
+ */
+ virtual int onResize();
+
+
+ /**
+ Get the api_window.
+
+ @ret
+ */
+ ifc_window *rootwndholder_getRootWnd();
+
+ /**
+ Find an object in the content group. This is done via
+ the object's text id.
+
+ @see abstract_findScriptObject()
+ @ret !NULL, The requested object pointer; NULL, Failed to find object.
+ @param The id of the object to find.
+ */
+ virtual GuiObject *abstract_findObject(const wchar_t *object_id);
+
+ /**
+ Find a script object in the content group. This is done via the
+ script object's text id.
+
+ @see abstract_findObject()
+ @ret !NULL, The requested script object pointer; NULL, Failed to find the object.
+ @param The id of the script object to find.
+ // TODO: benski> currently unused. cut?
+ */
+ virtual ScriptObject *abstract_findScriptObject(const wchar_t *object_id);
+
+ /**
+ Get the content group.
+
+ @see abstract_getContentScriptObject()
+ @ret A pointer to the content group GuiObject.
+ */
+ virtual GuiObject *abstract_getContent();
+
+ /**
+ Get the content script object.
+
+ @see abstract_getContent()
+ @ret A pointer to the content ScriptObject.
+ */
+ virtual ScriptObject *abstract_getContentScriptObject();
+
+ /**
+ Get the ifc_window that is holding the content group.
+
+ @see rootwndholder_getRootWnd()
+ @ret A pointer to the ifc_window holding the content group.
+ */
+ virtual ifc_window *abstract_getContentRootWnd() { return group; }
+
+ /**
+ Read the auto-resize from content flag.
+
+ @see abstract_setAutoResizeFromContent()
+ @ret 0, disable auto resize; 1, enable auto resize;
+ @param
+ */
+ virtual int abstract_wantAutoResizeFromContent() { return autoresizefromcontent; }
+
+ /**
+ Set the auto-resize from content flag.
+
+ @see abstract_wantAutoResizeFromContent()
+ @param i 0, disable auto resize; 1, enable auto resize;
+ */
+ virtual void abstract_setAutoResizeFromContent(int i) { autoresizefromcontent = i; }
+
+ /**
+ Set the allow deferred content flag. Allowing deferred content enables content to be
+ loaded after the window is shown.
+
+ @param allow 0, Do not allow; 1, Allow
+ */
+ virtual void abstract_setAllowDeferredContent(int allow) { allow_deferred_content = allow; }
+
+
+ /**
+ The deferred callback.
+
+ @ret 1, If you handle the event.
+ @param p1
+ @param p2
+ */
+ virtual int onDeferredCallback(intptr_t p1, intptr_t p2);
+
+ virtual void setContentSkinItem(SkinItem *groupitem, int autoresize=-1);
+
+ virtual void abstract_setScriptsEnabled(int en);
+ virtual int abstact_getScriptsEnabled();
+
+ private:
+
+
+ /**
+ Creates the child content window when required.
+ */
+ void createChild();
+
+ /**
+ Set Both Content.
+
+ @param guid
+ @param g
+ @param _autoresizefromcontent
+ */
+ void setBothContent(const wchar_t *guid, GUID g, int _autoresizefromcontent);
+
+ /**
+ Loads the content from the previously specified group.
+
+ @see abstract_setContent()
+ */
+ void doLoadContent();
+
+ /**
+ Destroys the instantiated copy of the content group.
+ */
+ void destroyContent();
+
+ StringW groupid;
+ GUID guid;
+
+ ifc_window *group;
+ int cbreg;
+ int inselfresize;
+ int autoresizefromcontent;
+ int allow_deferred_content;
+ int need_deferred_load;
+ SkinItem *group_item;
+ int scripts_enabled = 0;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/appbarwnd.cpp b/Src/Wasabi/api/wnd/wndclass/appbarwnd.cpp
new file mode 100644
index 00000000..11629fc1
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/appbarwnd.cpp
@@ -0,0 +1,1113 @@
+#include "precomp.h"
+#include "appbarwnd.h"
+#include <tataki/region/region.h>
+#include <api/wnd/resizable.h>
+#include <api/wndmgr/layout.h>
+#include <api/config/items/cfgitem.h>
+#include <api/config/items/attrint.h>
+#include "../../../../Plugins/General/gen_ff/wa2cfgitems.h"
+
+#define CB_CHECK 0x101
+#define DOCK_DISTANCE_X 5
+#define DOCK_DISTANCE_Y 5
+
+#ifndef WIN32
+#error port me or remove me from the inheritance on this platform !
+#endif
+
+#include <windows.h>
+#include <windowsx.h>
+#include <shlobj.h>
+#include "../../../../Plugins/General/gen_ff/main.h"
+#include "appbarwnd.h"
+
+extern _int cfg_options_appbardockingdistance;
+
+// -----------------------------------------------------------------------
+AppBarWnd::AppBarWnd() {
+ m_registered = 0;
+ m_side = APPBAR_NOTDOCKED;
+ m_enabled = 0;
+ m_cur_side = APPBAR_NOTDOCKED;
+ m_cur_autohide = 0;
+ m_cur_hiding = 0;
+ m_oldZOrder = NULL;
+ m_destroying = FALSE;
+ m_norestore = 0;
+ m_sliding = 0;
+ m_autounhide_timer_set = 0;
+ m_autohide_timer_set = 0;
+ m_suspended = 0;
+ m_fs = 0;
+ m_wahidden = 0;
+}
+
+// -----------------------------------------------------------------------
+AppBarWnd::~AppBarWnd() {
+ m_destroying = TRUE;
+ if (m_cur_side != APPBAR_NOTDOCKED) unDock();
+ unregisterWinAppBar();
+}
+
+// -----------------------------------------------------------------------
+int AppBarWnd::registerWinAppBar()
+{
+ if (m_registered)
+ unregisterWinAppBar();
+
+ APPBARDATA abd;
+
+ abd.cbSize = sizeof(APPBARDATA);
+ abd.hWnd = getOsWindowHandle();
+ abd.uCallbackMessage = APPBAR_CALLBACK;
+
+ m_registered = (int)SHAppBarMessage(ABM_NEW, &abd);
+ return m_registered;
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::unregisterWinAppBar() {
+ if (m_registered) {
+ APPBARDATA abd;
+
+ abd.cbSize = sizeof(APPBARDATA);
+ abd.hWnd = getOsWindowHandle();
+
+ SHAppBarMessage(ABM_REMOVE, &abd);
+ m_registered = 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::appbar_dock(int side) {
+ m_side = side;
+ updateDocking();
+}
+
+// -----------------------------------------------------------------------
+int AppBarWnd::appbar_isDocked() {
+ return m_side != APPBAR_NOTDOCKED;
+}
+
+// -----------------------------------------------------------------------
+int AppBarWnd::appbar_getSide() {
+ return m_side;
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::appbar_setEnabledSides(int mask) {
+ m_enabled = mask;
+}
+
+// -----------------------------------------------------------------------
+int AppBarWnd::appbar_getEnabledSides() {
+ return m_enabled;
+}
+
+// -----------------------------------------------------------------------
+int AppBarWnd::appbar_isSideEnabled(int side) {
+ if (side == APPBAR_LEFT && !(m_enabled & APPBAR_LEFT_ENABLED)) return 0;
+ if (side == APPBAR_TOP && !(m_enabled & APPBAR_TOP_ENABLED)) return 0;
+ if (side == APPBAR_RIGHT && !(m_enabled & APPBAR_RIGHT_ENABLED)) return 0;
+ if (side == APPBAR_BOTTOM && !(m_enabled & APPBAR_BOTTOM_ENABLED)) return 0;
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+int AppBarWnd::appbar_isSideAutoHideSafe(int side) {
+ OSWINDOWHANDLE cur = getCurAutoHide(side);
+
+ if (cur == NULL || cur == getOsWindowHandle()) {
+ RECT primary = {0};
+ Wasabi::Std::getViewport(&primary, hwnd, 1);
+
+ DebugStringW( L"primary screen coords = %d,%d -> %d,%d (%dx%d)\n", primary.left, primary.top, primary.right, primary.bottom, primary.right - primary.left, primary.bottom - primary.top );
+ int monitor = 0;
+ //int g = 0;
+ while (1) {
+ RECT r;
+ int ret = Wasabi::Std::enumViewports(monitor++, &r, 1);
+ if (ret == 0) break;
+
+ if (Wasabi::Std::rectEqual(&primary, &r)) continue;
+
+ DebugStringW(L"secondary screen = %d,%d -> %d,%d (%dx%d)\n", r.left, r.top, r.right, r.bottom, r.right-r.left, r.bottom-r.top);
+ if (r.right <= primary.left && side == APPBAR_LEFT) return 0;
+ if (r.bottom <= primary.top && side == APPBAR_TOP) return 0;
+ if (r.left >= primary.right && side == APPBAR_RIGHT) return 0;
+ if (r.top >= primary.bottom && side == APPBAR_BOTTOM) return 0;
+ }
+ }
+ else
+ return 0;
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+OSWINDOWHANDLE AppBarWnd::getCurAutoHide(int side) {
+ APPBARDATA abd;
+ abd.cbSize = sizeof(APPBARDATA);
+ abd.hWnd = getOsWindowHandle();
+ abd.uEdge = side;
+ return (OSWINDOWHANDLE)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd);
+}
+
+// -----------------------------------------------------------------------
+int AppBarWnd::appbar_testDock(int x, int y, RECT *dockrect) {
+ POINT ptCursor = {x, y};
+ LONG cxScreen, cyScreen;
+ int dx=999999, dy=999999;
+ int horiz=-1, vert=-1;
+ RECT viewRect = {0};
+
+ Wasabi::Std::getViewport(&viewRect, hwnd, 1);
+
+ // Find out which edge of the screen we're closest to
+ cxScreen = viewRect.right;
+ cyScreen = viewRect.bottom;
+
+ if (x < viewRect.left || x > cxScreen || y < viewRect.top || y > cyScreen) return APPBAR_NOTDOCKED;
+
+ if (ptCursor.x < (cxScreen / 2)) {
+ if (m_enabled & APPBAR_LEFT_ENABLED) {
+ dx = ptCursor.x;
+ horiz = APPBAR_LEFT;
+ }
+ }
+ else {
+ if (m_enabled & APPBAR_RIGHT_ENABLED) {
+ dx = cxScreen - ptCursor.x;
+ horiz = APPBAR_RIGHT;
+ }
+ }
+
+ if (ptCursor.y < (cyScreen / 2)) {
+ if (m_enabled & APPBAR_TOP_ENABLED) {
+ dy = ptCursor.y;
+ vert = APPBAR_TOP;
+ }
+ }
+ else {
+ if (m_enabled & APPBAR_BOTTOM_ENABLED) {
+ dy = cyScreen - ptCursor.y;
+ vert = APPBAR_BOTTOM;
+ }
+ }
+
+ int ret = -1;
+ #ifdef GEN_FF
+ int dockdist = cfg_options_appbardockingdistance;
+ #else
+ // TODO: do a config lookup, but make it not so slow
+ /*
+ const GUID options_guid =
+ { 0x280876cf, 0x48c0, 0x40bc, { 0x8e, 0x86, 0x73, 0xce, 0x6b, 0xb4, 0x62, 0xe5 } };
+ int dockdist = _intVal(WASABI_API_CONFIG->config_getCfgItemByGuid(options_guid), L"Appbars Docking Distance", 5);*/
+ int dockdist = 5;
+ #endif
+ if ((cxScreen * dy) > (cyScreen * dx))
+ if (dx <= dockdist)
+ ret = horiz;
+ if (dy <= dockdist)
+ ret = vert;
+
+ if (dockrect && ret != -1) {
+ getDockRect(ret, dockrect);
+ }
+
+ return ret;
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::getDockRect(int side, RECT *rect) {
+ LONG cxScreen, cyScreen;
+ RECT viewRect = {0};
+ Wasabi::Std::getViewport(&viewRect, hwnd, 1);
+
+ cxScreen = viewRect.right;
+ cyScreen = viewRect.bottom;
+
+ if (isMaximized()) {
+ getRestoredRect(rect);
+ if (renderRatioActive()) multRatio(rect);
+ }
+ else getWindowRect(rect);
+
+ Layout *l = (Layout *)getInterface(layoutGuid);
+ if (l) {
+ RECT adj;
+ l->getSnapAdjust(&adj);
+ if (renderRatioActive()) {
+ multRatio((int *)&adj.left, (int *)&adj.top);
+ multRatio((int *)&adj.right, (int *)&adj.bottom);
+ }
+ int h = rect->bottom - rect->top;
+ int w = rect->right - rect->left;
+ h -= adj.top + adj.bottom;
+ w -= adj.left + adj.right;
+ rect->left += adj.left;
+ rect->top += adj.top;
+ rect->bottom = rect->top + h;
+ rect->right = rect->left + w;
+ }
+
+ switch (side) {
+ case APPBAR_TOP:
+ case APPBAR_LEFT:
+ OffsetRect(rect, -rect->left, -rect->top);
+ break;
+ case APPBAR_BOTTOM:
+ case APPBAR_RIGHT:
+ OffsetRect(rect, cxScreen-rect->right, cyScreen-rect->bottom);
+ break;
+ }
+
+ switch (side) {
+ case APPBAR_TOP:
+ case APPBAR_BOTTOM:
+ rect->left = viewRect.left;
+ rect->right = cxScreen;
+ break;
+ case APPBAR_LEFT:
+ case APPBAR_RIGHT:
+ rect->top = viewRect.top;
+ rect->bottom = cyScreen;
+ break;
+ }
+
+ OSWINDOWHANDLE cur = getCurAutoHide(side);
+ int safeah = appbar_isSideAutoHideSafe(side);
+
+ if (!safeah || !(appbar_wantAutoHide() && (!cur || cur == getOsWindowHandle()))) {
+ straightenRect(side, rect);
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::updateDocking() {
+ if (!isVisible()) {
+ m_suspended = 1;
+ return;
+ }
+ updateSide();
+ appbar_updateAutoHide();
+ appbar_updateAlwaysOnTop();
+ updateTimers();
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::updateTimers() {
+ if (m_cur_autohide) {
+ if (m_cur_hiding) {
+ resetAutoHideTimer();
+ setAutoUnHideTimer();
+ }
+ else {
+ resetAutoUnHideTimer();
+ setAutoHideTimer();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+int AppBarWnd::appbar_updateAlwaysOnTop() {
+ if (m_side == APPBAR_NOTDOCKED) return 0;
+ SetWindowPos(getOsWindowHandle(), appbar_wantAlwaysOnTop() ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+int AppBarWnd::appbar_updateAutoHide() {
+ int autohide = appbar_wantAutoHide();
+ if (m_cur_autohide == autohide) return 0;
+
+ if (autohide && !appbar_isSideAutoHideSafe(m_cur_side)) autohide = 0;
+
+ if (m_cur_autohide == autohide) return 0;
+
+ if (autohide) {
+ // cur_autohide is off, turn it on
+ m_cur_hiding = 0;
+ setAutoHideTimer();
+ }
+ else {
+ // cur_autohide is on, turn it off
+ if (m_cur_hiding) resetAutoUnHideTimer();
+ else resetAutoHideTimer();
+ }
+
+ m_cur_autohide = autohide;
+ dock(m_cur_side);
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::onAfterReinit() {
+ APPBARWND_PARENT::onAfterReinit();
+ m_autohide_timer_set = 0;
+ m_autounhide_timer_set = 0;
+ updateTimers();
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::setAutoHideTimer(){
+ if (!m_autohide_timer_set) {
+ SetTimer(getOsWindowHandle(), IDT_AUTOHIDE, cfg_uioptions_appbarshidetime, NULL);
+ m_autohide_timer_set = 1;
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::setAutoUnHideTimer(){
+ if (!m_autounhide_timer_set) {
+ SetTimer(getOsWindowHandle(), IDT_AUTOUNHIDE, cfg_uioptions_appbarsshowtime, NULL);
+ m_autounhide_timer_set = 1;
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::resetAutoHideTimer(){
+ if (m_autohide_timer_set) {
+ KillTimer(getOsWindowHandle(), IDT_AUTOHIDE);
+ m_autohide_timer_set = 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::resetAutoUnHideTimer() {
+ if (m_autounhide_timer_set) {
+ KillTimer(getOsWindowHandle(), IDT_AUTOUNHIDE);
+ m_autounhide_timer_set = 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::updateSide() {
+ if (m_cur_side == m_side) return;
+ if (m_side != m_cur_side && m_cur_side != APPBAR_NOTDOCKED && m_side != APPBAR_NOTDOCKED && m_cur_autohide) {
+ resetAutoHideSide(m_cur_side);
+ }
+ if (m_side == APPBAR_NOTDOCKED) unDock();
+ else dock(m_side);
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::resetAutoHideSide(int side) {
+ HWND cur = getCurAutoHide(side);
+ if (cur == getOsWindowHandle()) {
+ APPBARDATA abd;
+ abd.cbSize = sizeof(APPBARDATA);
+ abd.hWnd = cur;
+ abd.uEdge = side;
+ abd.lParam = FALSE;
+ SHAppBarMessage(ABM_SETAUTOHIDEBAR, &abd);
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::setAutoHideSide(int side) {
+ APPBARDATA abd;
+ abd.cbSize = sizeof(APPBARDATA);
+ abd.hWnd = getOsWindowHandle();
+ abd.uEdge = side;
+ abd.lParam = TRUE;
+ SHAppBarMessage(ABM_SETAUTOHIDEBAR, &abd);
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::dock(int side) {
+ unOwn();
+
+ if (!registerWinAppBar()) {
+ reOwn();
+ m_side = APPBAR_NOTDOCKED;
+ m_cur_side = APPBAR_NOTDOCKED;
+ m_cur_autohide = 0;
+ }
+
+ maximize(0);
+
+ RECT rect;
+ getDockRect(side, &rect);
+
+ {
+ RECT adj = rect;
+ if (ABS(getRenderRatio() - 1.0) > 0.01f) {
+ int _w = adj.right-adj.left;
+ int _h = adj.bottom-adj.top;
+ double rr = getRenderRatio();
+ _w = (int)((double)(_w) / rr + 0.5);
+ _h = (int)((double)(_h) / rr + 0.5);
+ adj.right = adj.left + _w;
+ adj.bottom = adj.top + _h;
+ }
+ snapAdjust(&adj, 1);
+ resizeToRect(&adj);
+ }
+
+ if (!appbar_wantAutoHide() || !appbar_isSideAutoHideSafe(side)) {
+ notifyWinAppBarPosition(side, rect);
+ }
+ else {
+ getEdge(side, &rect);
+ notifyWinAppBarPosition(side, rect);
+ setAutoHideSide(side);
+ m_cur_hiding = 0;
+ }
+
+ if (!m_suspended) appbar_onDock(side);
+
+ #ifdef WASABI_APPBAR_ONDOCKCHANGED
+ WASABI_APPBAR_ONDOCKCHANGED(this)
+ #endif
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::unDock() {
+ if (m_cur_side != APPBAR_NOTDOCKED) {
+
+ resetAutoHideSide(m_cur_side);
+ unregisterWinAppBar();
+
+ if (!m_destroying) {
+ reOwn();
+ if (!m_norestore) restore();
+ #ifdef WASABI_APPBAR_ONDOCKCHANGED
+ WASABI_APPBAR_ONDOCKCHANGED(this)
+ #endif
+ }
+
+ m_cur_side = APPBAR_NOTDOCKED;
+
+ if (!m_suspended) appbar_onUnDock();
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::notifyWinAppBarPosition(int side, RECT rect) {
+ APPBARDATA abd;
+
+ abd.cbSize = sizeof(APPBARDATA);
+ abd.hWnd = getOsWindowHandle();
+ abd.rc = rect;
+ abd.uEdge = side;
+
+ SHAppBarMessage(ABM_SETPOS, &abd);
+ m_cur_side = side;
+}
+
+// -----------------------------------------------------------------------
+int AppBarWnd::appbar_isHiding() {
+ return m_cur_hiding;
+}
+
+// -----------------------------------------------------------------------
+int AppBarWnd::appbar_isAutoHiding() {
+ return m_cur_autohide;
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::appbar_posChanged() {
+ if (m_side == APPBAR_NOTDOCKED) return;
+ RECT wr;
+ getWindowRect(&wr);
+ int w = wr.right-wr.left;
+ int h = wr.bottom-wr.top;
+
+ if (m_cur_autohide && m_cur_side != APPBAR_NOTDOCKED && !appbar_isSideAutoHideSafe(m_cur_side))
+ m_cur_autohide = 0;
+
+ RECT rc;
+ getDockRect(m_cur_side, &rc);
+
+ if (!m_cur_autohide) {
+ {
+ RECT adj = rc;
+ if (ABS(getRenderRatio() - 1.0) > 0.01f) {
+ int _w = adj.right-adj.left;
+ int _h = adj.bottom-adj.top;
+ double rr = getRenderRatio();
+ _w = (int)((double)(_w) / rr + 0.5);
+ _h = (int)((double)(_h) / rr + 0.5);
+ adj.right = adj.left + _w;
+ adj.bottom = adj.top + _h;
+ }
+ snapAdjust(&adj, 1);
+ resizeToRect(&adj);
+ }
+ notifyWinAppBarPosition(m_cur_side, rc);
+ }
+ else {
+ int aaw = appbar_getAutoHideWidthHeight();
+ RECT er;
+ getEdge(m_cur_side, &er);
+ notifyWinAppBarPosition(m_cur_side, er);
+ RECT adj = {0,0,0,0};
+ Layout *l = (Layout *)getInterface(layoutGuid);
+ if (l) l->getSnapAdjust(&adj);
+ if (renderRatioActive()) multRatio(&adj);
+ if (m_cur_hiding) {
+ switch (m_cur_side) {
+ case APPBAR_TOP:
+ rc.bottom = er.top + aaw + adj.bottom;
+ rc.top = rc.bottom - h;
+ break;
+ case APPBAR_BOTTOM:
+ rc.top = er.bottom - aaw - adj.top;
+ rc.bottom = rc.top + h;
+ break;
+ case APPBAR_LEFT:
+ rc.right = er.left + aaw + adj.right;
+ rc.left = rc.right - w;
+ break;
+ case APPBAR_RIGHT:
+ rc.left = er.right - aaw - adj.left;
+ rc.right = rc.left + w;
+ break;
+ }
+ }
+ if (ABS(getRenderRatio() - 1.0) > 0.01f) {
+ int _w = rc.right-rc.left;
+ int _h = rc.bottom-rc.top;
+ double rr = getRenderRatio();
+ _w = (int)((double)(_w) / rr + 0.5);
+ _h = (int)((double)(_h) / rr + 0.5);
+ rc.right = rc.left + _w;
+ rc.bottom = rc.top + _h;
+ }
+ resizeToRect(&rc);
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::getEdge(int side, RECT *rc) {
+ ASSERT(rc != NULL);
+ Wasabi::Std::getViewport(rc, hwnd, 1);
+ switch (side) {
+ case APPBAR_TOP:
+ rc->bottom = rc->top; break;
+ case APPBAR_BOTTOM:
+ rc->top = rc->bottom; break;
+ case APPBAR_LEFT:
+ rc->right = rc->left; break;
+ case APPBAR_RIGHT:
+ rc->left = rc->right; break;
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::appBarCallback(UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ APPBARDATA abd = {0};
+
+ if (m_registered) {
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = getOsWindowHandle();
+
+ switch (wParam)
+ {
+ // the taskbar's autohide or always-on-top state has changed.
+ case ABN_STATECHANGE:
+ DebugString("AppBarCallback: ABN_STATECHANGE\n");
+ break;
+
+ // a full screen application is opening or closing. we must drop
+ // to the bottom of the Z-Order and restore it later.
+ case ABN_FULLSCREENAPP:
+ DebugString("AppBarCallback: ABN_FULLSCREENAPP\n");
+ if (lParam && !m_fs) {
+ m_fs=1;
+ m_oldZOrder = GetWindow(getOsWindowHandle(), GW_HWNDPREV);
+ SetWindowPos(getOsWindowHandle(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ }
+ else if (!lParam && m_fs) {
+ m_fs = 0;
+ SetWindowPos(getOsWindowHandle(), appbar_wantAlwaysOnTop() ? HWND_TOPMOST : m_oldZOrder, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ m_oldZOrder = NULL;
+ }
+ break;
+
+ // something changed that may have modified the possible appbar's positions
+ case ABN_POSCHANGED:
+ DebugString("AppBarCallback: ABN_POSCHANGED\n");
+ appbar_posChanged();
+ break;
+
+ case ABN_WINDOWARRANGE:
+ if (lParam && !m_wahidden) {
+ m_wahidden = 1;
+ ShowWindow(getOsWindowHandle(), SW_HIDE);
+ }
+ else if (!lParam && m_wahidden) {
+ m_wahidden = 0;
+ ShowWindow(getOsWindowHandle(), SW_NORMAL);
+ }
+ break;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+LRESULT AppBarWnd::wndProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
+{
+ if ( m_registered )
+ {
+ switch ( msg )
+ {
+ case WM_MOVE:
+ {
+ //DebugString("WM_MOVE\n");
+ return 0;
+ }
+ case WM_WINDOWPOSCHANGED:
+ {
+ //DebugString("WM_WINDOWPOSCHANGED\n");
+ //LPWINDOWPOS lpwpos = (LPWINDOWPOS)lparam;
+ APPBARDATA abd = { 0 };
+ abd.cbSize = sizeof( APPBARDATA );
+ abd.hWnd = getOsWindowHandle();
+
+ SHAppBarMessage( ABM_WINDOWPOSCHANGED, &abd );
+ }
+ case APPBAR_CALLBACK:
+ {
+ if ( !m_destroying ) appBarCallback( msg, wparam, lparam );
+ return 0;
+ }
+ case WM_DISPLAYCHANGE:
+ {
+ DebugString( "WM_DISPLAYCHANGE\n" );
+ appbar_posChanged();
+ }
+ case WM_TIMER:
+ { // // not using multiplexed timer for independent speed
+ switch ( wparam )
+ {
+ case IDT_AUTOHIDE:
+ onAutoHideTimer();
+ break;
+ case IDT_AUTOUNHIDE:
+ onAutoUnHideTimer();
+ break;
+ }
+ }
+ case WM_COMMAND:
+ {
+ // forward onto the main Winamp window and let it do it
+ if ( HIWORD( wparam ) == THBN_CLICKED )
+ {
+ SendMessageW( plugin.hwndParent, msg, wparam, lparam );
+ }
+ }
+ }
+ }
+
+ return APPBARWND_PARENT::wndProc( hwnd, msg, wparam, lparam );
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::onAutoHideTimer() {
+ HWND me = getOsWindowHandle();
+ POINT pt;
+ RECT rc;
+ HWND hact;
+ if (m_cur_autohide) {
+ if (!m_cur_hiding) {
+ GetCursorPos(&pt);
+ GetWindowRect(hwnd, &rc);
+ snapAdjust(&rc, -1);
+ hact = GetForegroundWindow();
+
+ if ((!PtInRect(&rc, pt) || screenCorner(&pt)) && (hact != me) && /*(hact!= NULL) && */(GetWindowOwner(hact) != me)) {
+ resetAutoHideTimer();
+ autoHide();
+ setAutoUnHideTimer();
+ }
+ }
+ else {
+ resetAutoHideTimer();
+ setAutoUnHideTimer();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::onAutoUnHideTimer() {
+ RECT rc;
+ POINT pt;
+ HWND me = getOsWindowHandle();
+
+ GetWindowRect(me, &rc);
+ snapAdjust(&rc, -1);
+ if (m_cur_autohide) {
+ if (m_cur_hiding) {
+ GetCursorPos(&pt);
+ if (PtInRect(&rc, pt) && !screenCorner(&pt)) {
+ resetAutoUnHideTimer();
+ autoUnHide();
+ setAutoHideTimer();
+ }
+ }
+ else {
+ resetAutoUnHideTimer();
+ setAutoHideTimer();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::autoHide() {
+ if (m_cur_autohide) {
+ if (!m_cur_hiding) {
+ RECT rc;
+
+ getWindowRect(&rc);
+
+ int h = rc.bottom-rc.top;
+ int w = rc.right-rc.left;
+
+ int aaw = appbar_getAutoHideWidthHeight();
+
+ RECT adj={0,0,0,0};
+ Layout *l = static_cast<Layout*>(getInterface(layoutGuid));
+ l->getSnapAdjust(&adj);
+ if (renderRatioActive()) multRatio(&adj);
+
+ RECT viewRect = {0};
+ Wasabi::Std::getViewport(&viewRect, hwnd, 1);
+
+ switch (m_side) {
+ case APPBAR_TOP:
+ rc.top = -(h - aaw + adj.top - adj.bottom);
+ break;
+ case APPBAR_BOTTOM:
+ rc.top = (viewRect.bottom - viewRect.top) - aaw - adj.top;
+ break;
+ case APPBAR_LEFT:
+ rc.left = -(w - aaw + adj.left - adj.right);
+ break;
+ case APPBAR_RIGHT:
+ rc.left = viewRect.right - aaw - adj.left;
+ break;
+ }
+
+ switch (m_side) {
+ case APPBAR_TOP:
+ case APPBAR_BOTTOM:
+ rc.bottom = rc.top + h;
+ break;
+ case APPBAR_LEFT:
+ case APPBAR_RIGHT:
+ rc.right = rc.left + w;
+ break;
+ }
+
+ slideWindow(&rc);
+ m_cur_hiding = 1;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::autoUnHide() {
+ if (m_cur_autohide) {
+ if (m_cur_hiding) {
+ m_cur_hiding = 0;
+
+ RECT rc;
+ getWindowRect(&rc);
+
+ int h = rc.bottom-rc.top;
+ int w = rc.right-rc.left;
+
+ int aaw = appbar_getAutoHideWidthHeight();
+
+ RECT adj={0,0,0,0};
+ Layout *l = static_cast<Layout*>(getInterface(layoutGuid));
+ l->getSnapAdjust(&adj);
+ if (renderRatioActive()) multRatio(&adj);
+
+ switch (m_side) {
+ case APPBAR_TOP:
+ rc.top += (h - aaw) - (adj.top + adj.bottom);
+ rc.bottom += (h - aaw) - (adj.top + adj.bottom);
+ break;
+ case APPBAR_BOTTOM:
+ rc.top -= (h - aaw) - (adj.top + adj.bottom);
+ rc.bottom -= (h - aaw) - (adj.top + adj.bottom);
+ break;
+ case APPBAR_LEFT:
+ rc.right += (w - aaw) - (adj.left + adj.right);
+ rc.left += (w - aaw) - (adj.left + adj.right);
+ break;
+ case APPBAR_RIGHT:
+ rc.left -= (w - aaw) - (adj.left + adj.right);
+ rc.right -= (w - aaw) - (adj.left + adj.right);
+ break;
+ }
+
+ slideWindow(&rc);
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const int g_dtSlideHide = 400;
+const int g_dtSlideShow = 200;
+
+// -----------------------------------------------------------------------
+void AppBarWnd::slideWindow(RECT *prc) {
+ if (m_cur_autohide) {
+ m_sliding = 1;
+ RECT rcOld;
+ RECT rcNew;
+ int x, y, dx, dy, dt, t, t0;
+ BOOL fShow;
+ HANDLE hThreadMe;
+ int priority;
+
+ HWND hwnd = getOsWindowHandle();
+
+ rcNew = *prc;
+
+ /*DebugString("rcNew : left=%d, top=%d, "
+ "right=%d, bottom=%d\n", rcNew.left,
+ rcNew.top, rcNew.right, rcNew.bottom);*/
+
+ if ((g_dtSlideShow > 0) && (g_dtSlideHide > 0)) {
+ GetWindowRect(hwnd, &rcOld);
+
+ fShow = TRUE;/*(rcNew.bottom - rcNew.top) > (rcOld.bottom - rcOld.top) ||
+ (rcNew.right - rcNew.left) > (rcOld.right - rcOld.left);*/
+
+ dx = (rcNew.left - rcOld.left);
+ dy = (rcNew.top - rcOld.top);
+
+ if (fShow) {
+ rcOld = rcNew;
+ OffsetRect(&rcOld, -dx, -dy);
+ //DebugString("appbar_slideWindow %d %d\n", rcOld.left, rcOld.top);
+ move(rcOld.left, rcOld.top);
+ dt = g_dtSlideShow;
+ }
+ else {
+ dt = g_dtSlideHide;
+ }
+
+ hThreadMe = GetCurrentThread();
+ priority = GetThreadPriority(hThreadMe);
+ SetThreadPriority(hThreadMe, THREAD_PRIORITY_HIGHEST);
+
+ t0 = GetTickCount();
+ while ((t = GetTickCount()) < t0 + dt) {
+ x = rcOld.left + dx * (t - t0) / dt;
+ y = rcOld.top + dy * (t - t0) / dt;
+
+ //DebugString("appbar_slideWindow(2) %d %d\n", x, y);
+ move(x, y);
+ //SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+ if (fShow) {
+ UpdateWindow(hwnd);
+ //invalidateWindowRegion();
+ //updateWindowRegion();
+ }
+ else UpdateWindow(GetDesktopWindow());
+ }
+
+ SetThreadPriority(hThreadMe, priority);
+ }
+
+ //DebugString("appbar_slideWindow(3) %d %d\n", rcNew.left, rcNew.top);
+ move(rcNew.left, rcNew.top);
+ appbar_onSlide();
+ }
+ WASABI_API_MAKI->vcpu_setComplete();
+ m_sliding = 0;
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::unOwn()
+{
+ // registration was successful, we should reparent the window to NULL so that minimizing the app or changing the main AOT flag does
+ // nothing to this window
+ Layout *l = static_cast<Layout*>(getInterface(layoutGuid));
+ if (l) {
+ if (!l->getNoParent()) {
+ l->setNoParent(2);
+ // whoaaah!
+ reinit();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::reOwn() {
+ OSWINDOWHANDLE mw = WASABI_API_WND->main_getRootWnd()->getOsWindowHandle();
+ if (IsIconic(mw)) ShowWindow(mw, SW_RESTORE);
+ // undock was successful, we should re-own the window to what it was previously. if the old owner is minimized, we should restore it first
+ OSWINDOWHANDLE oldparent = WASABI_API_WND->main_getRootWnd()->getOsWindowHandle();
+ if (IsIconic(oldparent)) ShowWindow(oldparent, SW_RESTORE);
+ Layout *l = static_cast<Layout *>(getInterface(layoutGuid));
+ if (l) {
+ int oldnp = l->getNoParent();
+ const wchar_t *np = l->getGuiObject()->guiobject_getXmlParam(L"noparent");
+ int newnp = WTOI(np);
+ if (oldnp != newnp)
+ {
+ l->setNoParent(newnp);
+ // whoaaah!
+ reinit();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::straightenRect(int side, RECT *r) {
+ int w=0, h=0;
+
+ int wasregistered = m_registered;
+ if (!m_registered) registerWinAppBar();
+
+ APPBARDATA abd;
+ abd.hWnd = hwnd;
+ abd.cbSize = sizeof(APPBARDATA);
+ abd.rc = *r;
+ abd.uEdge = side;
+
+ RECT viewRect = {0};
+ Wasabi::Std::getViewport(&viewRect, hwnd, 1);
+
+ switch (side) {
+ case APPBAR_LEFT:
+ case APPBAR_RIGHT:
+ w = abd.rc.right - abd.rc.left;
+ abd.rc.top = viewRect.top;
+ abd.rc.bottom = viewRect.bottom;
+ break;
+ case APPBAR_TOP:
+ case APPBAR_BOTTOM:
+ h = abd.rc.bottom - abd.rc.top;
+ abd.rc.left = viewRect.left;
+ abd.rc.right = viewRect.right;
+ break;
+ }
+
+ SHAppBarMessage(ABM_QUERYPOS, &abd);
+
+ switch (abd.uEdge) {
+ case APPBAR_LEFT:
+ abd.rc.right = abd.rc.left + w;
+ break;
+ case APPBAR_RIGHT:
+ abd.rc.left = abd.rc.right - w;
+ break;
+ case APPBAR_TOP:
+ abd.rc.bottom = abd.rc.top + h;
+ break;
+ case APPBAR_BOTTOM:
+ abd.rc.top = abd.rc.bottom - h;
+ break;
+ }
+
+ if (!wasregistered) unregisterWinAppBar();
+
+ *r = abd.rc;
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::appbar_setNoRestore(int no) {
+ m_norestore = no;
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::onSetVisible( int show )
+{
+ if ( !show && m_side != APPBAR_NOTDOCKED && !m_suspended )
+ {
+ if ( m_cur_autohide )
+ {
+ resetAutoHideSide( m_cur_side );
+ if ( m_cur_hiding )
+ resetAutoUnHideTimer();
+ else
+ resetAutoHideTimer();
+ }
+
+ m_suspended = 1;
+ unDock();
+ APPBARWND_PARENT::onSetVisible( show );
+ return;
+ }
+ else if ( show && m_suspended )
+ {
+ APPBARWND_PARENT::onSetVisible( show );
+ m_suspended = 0;
+ updateDocking();
+ return;
+ }
+
+ APPBARWND_PARENT::onSetVisible( show );
+}
+
+// -----------------------------------------------------------------------
+int AppBarWnd::screenCorner(POINT *pt) {
+ RECT primary = {0};
+ Wasabi::Std::getViewport(&primary, hwnd, 1);
+ if (pt->x > primary.right-2 && pt->x <= primary.right) {
+ if (pt->y > primary.bottom-2 && pt->y <= primary.bottom) {
+ // bottom right corner
+ return 1;
+ }
+ else if (pt->y < primary.top+2 && pt->y >= primary.top) {
+ // top right corner
+ return 1;
+ }
+ }
+ else if (pt->x < primary.left+2 && pt->x >= primary.left) {
+ if (pt->y > primary.bottom-2 && pt->y <= primary.bottom) {
+ // bottom left corner
+ return 1;
+ }
+ else if (pt->y < primary.top+2 && pt->y >= primary.top) {
+ // top left corner
+ return 1;
+ }
+ }
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::snapAdjust(RECT *r, int way)
+{
+ RECT s;
+ Layout *l = static_cast<Layout*>(getInterface(layoutGuid));
+ if (!l) return;
+ l->getSnapAdjust(&s);
+ int h = r->bottom - r->top;
+ int w = r->right - r->left;
+ if (way == 1) {
+ h += s.top + s.bottom;
+ w += s.left + s.right;
+ r->left -= s.left;
+ r->top -= s.top;
+ r->bottom = r->top + h;
+ r->right = r->left + w;
+ }
+ else if (way == -1) {
+ h -= s.top + s.bottom;
+ w -= s.left + s.right;
+ r->left += s.left;
+ r->top += s.top;
+ r->bottom = r->top + h;
+ r->right = r->left + w;
+ }
+}
+
+// -----------------------------------------------------------------------
+void AppBarWnd::onRatioChanged()
+{
+ APPBARWND_PARENT::onRatioChanged();
+ if (m_side != APPBAR_NOTDOCKED) appbar_posChanged();
+} \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/wndclass/appbarwnd.h b/Src/Wasabi/api/wnd/wndclass/appbarwnd.h
new file mode 100644
index 00000000..7b8fba35
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/appbarwnd.h
@@ -0,0 +1,155 @@
+#ifndef _APPBARWND_H
+#define _APPBARWND_H
+
+#include <bfc/common.h>
+#include <shellapi.h>
+#include <api/wnd/wndclass/clickwnd.h>
+
+#define APPBARWND_PARENT ClickWnd
+
+#define APPBAR_TOP_ENABLED 1
+#define APPBAR_LEFT_ENABLED 2
+#define APPBAR_BOTTOM_ENABLED 4
+#define APPBAR_RIGHT_ENABLED 8
+
+#define APPABR_ALL_ENABLED (APPBAR_TOP_ENABLED|APPBAR_LEFT_ENABLED|APPBAR_BOTTOM_ENABLED|APPBAR_RIGHT_ENABLED)
+
+#define APPBAR_CALLBACK WM_USER + 1010
+
+#define IDT_AUTOHIDE 0x10000
+#define IDT_AUTOUNHIDE 0x10001
+
+#ifdef WIN32
+#define APPBAR_NOTDOCKED -1
+#define APPBAR_LEFT ABE_LEFT
+#define APPBAR_TOP ABE_TOP
+#define APPBAR_RIGHT ABE_RIGHT
+#define APPBAR_BOTTOM ABE_BOTTOM
+#else
+#error port me
+#endif
+
+// todo : dispatch
+class AppBar {
+public:
+ virtual void appbar_dock(int side)=0;
+ virtual int appbar_isDocked()=0;
+ virtual int appbar_getSide()=0;
+ virtual void appbar_setEnabledSides(int mask)=0;
+ virtual int appbar_getEnabledSides()=0;
+ virtual int appbar_isSideEnabled(int side)=0;
+ virtual int appbar_testDock(int x, int y, RECT *dockrect=NULL)=0;
+ virtual int appbar_updateAutoHide()=0;
+ virtual int appbar_updateAlwaysOnTop()=0;
+ virtual int appbar_isHiding()=0;
+ virtual int appbar_wantAutoHide()=0;
+ virtual int appbar_wantAlwaysOnTop()=0;
+ virtual int appbar_isAutoHiding()=0;
+ virtual void appbar_onDock(int side) {}
+ virtual void appbar_onUnDock() {}
+ virtual void appbar_onSlide() {}
+ virtual void appbar_posChanged()=0;
+ virtual int appbar_isSideAutoHideSafe(int side)=0;
+ virtual int appbar_getAutoHideWidthHeight()=0;
+ virtual void appbar_setNoRestore(int no)=0;
+};
+
+// {242CFAA4-31B3-4b01-97C8-2F0A9FFDEF79}
+static const GUID appBarGuid =
+{ 0x242cfaa4, 0x31b3, 0x4b01, { 0x97, 0xc8, 0x2f, 0xa, 0x9f, 0xfd, 0xef, 0x79 } };
+
+class api_region;
+
+// TODO: benski> only class making active use of being derived from this seems to be Layout and GuiObjectWnd
+// maybe just layout ...
+
+class AppBarWnd : public APPBARWND_PARENT, public AppBar {
+ public:
+ AppBarWnd();
+ virtual ~AppBarWnd();
+
+ void appbar_dock(int side);
+ int appbar_isDocked();
+ int appbar_getSide();
+
+ void appbar_setEnabledSides(int mask);
+ int appbar_getEnabledSides();
+ int appbar_isSideEnabled(int side);
+
+ int appbar_testDock(int x, int y, RECT *dockrect=NULL);
+
+ int appbar_updateAutoHide();
+ int appbar_updateAlwaysOnTop();
+
+ int appbar_isSideAutoHideSafe(int side);
+
+ virtual int appbar_wantAutoHide() { return 1; }
+ virtual int appbar_wantAlwaysOnTop() { return 1; }
+
+ int appbar_isHiding();
+ int appbar_isAutoHiding();
+
+ void appbar_posChanged();
+ void appbar_setNoRestore(int no);
+ virtual int appbar_getAutoHideWidthHeight() { return 2; }
+
+ virtual LRESULT wndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+ virtual void onAfterReinit();
+ virtual void onSetVisible(int show);
+
+ virtual void onRatioChanged();
+
+ private:
+
+ void appBarCallback(UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ int registerWinAppBar();
+ void unregisterWinAppBar();
+ void notifyWinAppBarPosition(int side, RECT rect);
+
+ OSWINDOWHANDLE getCurAutoHide(int side);
+
+ void getDockRect(int side, RECT *rc);
+ void getEdge(int side, RECT *rc);
+ void straightenRect(int side, RECT *r);
+ void updateDocking();
+ void updateSide();
+ void updateTimers();
+ void resetAutoHideSide(int side);
+ void setAutoHideSide(int side);
+ void setAutoHideTimer();
+ void setAutoUnHideTimer();
+ void resetAutoHideTimer();
+ void resetAutoUnHideTimer();
+ void onAutoHideTimer();
+ void onAutoUnHideTimer();
+ void autoHide();
+ void autoUnHide();
+ void slideWindow(RECT *prc);
+ int screenCorner(POINT *pt);
+ void snapAdjust(RECT *r, int way);
+
+ void dock(int side);
+ void unDock();
+
+ void unOwn();
+ void reOwn();
+
+ int m_registered;
+ int m_side;
+ int m_enabled;
+ int m_cur_autohide;
+ int m_cur_side;
+ int m_cur_hiding;
+ OSWINDOWHANDLE m_oldZOrder;
+ int m_destroying;
+ int m_norestore;
+ int m_autohide_timer_set;
+ int m_autounhide_timer_set;
+ int m_sliding;
+ int m_suspended;
+ int m_fs;
+ int m_wahidden;
+};
+
+#endif //_APPBARWND_H \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/wndclass/backbufferwnd.cpp b/Src/Wasabi/api/wnd/wndclass/backbufferwnd.cpp
new file mode 100644
index 00000000..10e0a04a
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/backbufferwnd.cpp
@@ -0,0 +1,86 @@
+#include <precomp.h>
+#include "backbufferwnd.h"
+#include <tataki/canvas/bltcanvas.h>
+#include <api/api.h>
+#include <tataki/region/region.h>
+
+// -----------------------------------------------------------------------
+BackBufferWnd::BackBufferWnd() {
+ backbuffer = 0;
+ canvas_w = -1;
+ canvas_h = -1;
+ back_buffer = NULL;
+}
+
+// -----------------------------------------------------------------------
+BackBufferWnd::~BackBufferWnd() {
+ delete back_buffer;
+}
+
+//------------------------------------------------------------------------
+BltCanvas *BackBufferWnd::getBackBuffer() {
+ return back_buffer;
+}
+
+// -----------------------------------------------------------------------
+int BackBufferWnd::onPaint(Canvas *canvas) {
+
+ BBWND_PARENT::onPaint(canvas);
+
+ if (!canvas) return 1;
+
+ RECT r;
+ getClientRect(&r);
+
+ if (back_buffer && r.right-r.left > 0 && r.bottom -r.top > 0) {
+
+ int w = r.right-r.left;
+ int h = r.bottom-r.top;
+
+ if (canvas_w != w || canvas_h != h) {
+ delete back_buffer;
+ back_buffer = new BltCanvas(w, h, getOsWindowHandle());
+ canvas_w = w;
+ canvas_h = h;
+ }
+
+#ifdef _WIN32
+ RegionI reg;
+ canvas->getClipRgn(&reg);
+ back_buffer->selectClipRgn(&reg);
+#else
+#warning port me
+#endif
+ canvas->blit(r.left, r.top, back_buffer, 0, 0, w, h);
+ back_buffer->selectClipRgn(NULL);
+ }
+
+ return 1;
+}
+
+int BackBufferWnd::onSiblingInvalidateRgn(api_region *r, ifc_window *who, int who_idx, int my_idx) {
+ if (who_idx >= my_idx || !wantBackBuffer()) return 0;
+
+ RECT rr;
+ getClientRect(&rr);
+
+ api_region *_r = getRegion();
+ RegionI *__r=NULL;
+
+ if (!_r) {
+ __r = new RegionI();
+ _r = __r;
+ _r->setRect(&rr);
+ } else {
+ _r->offset(rr.left, rr.top);
+ }
+
+ int intersect = _r->doesIntersectRgn(r);
+ if (intersect)
+ r->addRegion(_r);
+
+ delete __r;
+
+ return intersect;
+}
+
diff --git a/Src/Wasabi/api/wnd/wndclass/backbufferwnd.h b/Src/Wasabi/api/wnd/wndclass/backbufferwnd.h
new file mode 100644
index 00000000..1f536ba1
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/backbufferwnd.h
@@ -0,0 +1,53 @@
+#ifndef __BBWND_H
+#define __BBWND_H
+
+#include <api/wnd/wndclass/abstractwndhold.h>
+
+#ifdef WASABI_COMPILE_SKIN
+#define BBWND_PARENT AbstractWndHolder
+#else
+#define BBWND_PARENT ServiceWndHolder
+#endif
+
+/**
+ class BackBufferWnd
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see
+*/
+class BackBufferWnd : public BBWND_PARENT {
+
+ public:
+
+ BackBufferWnd();
+ virtual ~BackBufferWnd();
+
+ virtual int onPaint(Canvas *c);
+
+ /**
+ BackBufferWnd method wantBackBuffer .
+
+ @ret 0
+ @param None
+ */
+ virtual int wantBackBuffer() { return 0; }
+ virtual BltCanvas *getBackBuffer();
+ virtual int onSiblingInvalidateRgn(api_region *r, ifc_window *who, int who_idx, int my_idx);
+
+ /**
+ BackBufferWnd method wantSiblingInvalidations .
+
+ @ret 0
+ @param None
+ */
+ virtual int wantSiblingInvalidations() { return wantBackBuffer(); }
+
+ private:
+
+ int backbuffer;
+ BltCanvas *back_buffer;
+ int canvas_w, canvas_h;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/blankwnd.cpp b/Src/Wasabi/api/wnd/wndclass/blankwnd.cpp
new file mode 100644
index 00000000..beeddfd5
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/blankwnd.cpp
@@ -0,0 +1,24 @@
+#include "precomp.h"
+
+#include "blankwnd.h"
+#include <tataki/canvas/canvas.h>
+#include <api/wnd/PaintCanvas.h>
+
+BlankWnd::BlankWnd(RGB32 _color) : color(_color)
+{
+}
+
+int BlankWnd::onPaint(Canvas *canvas)
+{
+ PaintCanvas pc;
+ if (canvas == NULL)
+ {
+ if (!pc.beginPaint(this)) return 0;
+ canvas = &pc;
+ }
+
+ canvas->fillRect(&clientRect(), color);
+
+ return 1;
+}
+
diff --git a/Src/Wasabi/api/wnd/wndclass/blankwnd.h b/Src/Wasabi/api/wnd/wndclass/blankwnd.h
new file mode 100644
index 00000000..56f44139
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/blankwnd.h
@@ -0,0 +1,41 @@
+#ifndef _BLANKWND_H
+#define _BLANKWND_H
+
+#include <bfc/common.h>
+#include <api/wnd/virtualwnd.h>
+
+#define BLANKWND_PARENT VirtualWnd
+
+/**
+ Class BlankWnd provides blank windows. The initial color can be set in the
+ constructor, with a default of black. There is a method for painting the window from a Canvas.
+
+ @short Blank Window with background color.
+ @author Nullsoft
+ @ver 1.0
+ @see VirtualWnd
+*/
+class BlankWnd : public BLANKWND_PARENT {
+public:
+ /**
+ You can set the background color for the window via an RGB value.
+ The RGB value is contructed using RGB(), like so RGB(Red, Green, Blue);
+
+ @param color The RGB value of the background color to use.
+ */
+ BlankWnd(RGB32 color=RGB(0,0,0));
+
+ /**
+ This event is triggered when the window needs to be repainted.
+ Override it to implement your own handling of this event.
+
+ @ret 1, If you handle the event;
+ @param canvas A pointer to the canvas on which will we paint.
+ */
+ virtual int onPaint(Canvas *canvas);
+
+private:
+ RGB32 color;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/bufferpaintwnd.cpp b/Src/Wasabi/api/wnd/wndclass/bufferpaintwnd.cpp
new file mode 100644
index 00000000..a32d29c5
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/bufferpaintwnd.cpp
@@ -0,0 +1,113 @@
+#include <precomp.h>
+#include "bufferpaintwnd.h"
+#include <tataki/canvas/bltcanvas.h>
+
+// -----------------------------------------------------------------------
+BufferPaintWnd::BufferPaintWnd() {
+ canvas_w = -1;
+ canvas_h = -1;
+ render_canvas = NULL;
+ invalidated = 1;
+}
+
+// -----------------------------------------------------------------------
+BufferPaintWnd::~BufferPaintWnd() {
+ delete render_canvas;
+}
+
+// -----------------------------------------------------------------------
+int BufferPaintWnd::onInit() {
+ BUFFERPAINTWND_PARENT::onInit();
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+void BufferPaintWnd::bufferPaint() {
+ updateCanvas();
+ if (render_canvas != NULL)
+ onBufferPaint(render_canvas, canvas_w, canvas_h);
+}
+
+void BufferPaintWnd::invalidateBuffer() {
+ invalidated = 1;
+ invalidate();
+}
+
+// -----------------------------------------------------------------------
+void BufferPaintWnd::getBufferPaintSize(int *w, int *h) {
+ RECT r;
+ getClientRect(&r);
+ if (w) *w = r.right-r.left;
+ if (h) *h = r.bottom-r.top;
+}
+
+// -----------------------------------------------------------------------
+void BufferPaintWnd::getBufferPaintSource(RECT *r) {
+ ASSERT(r != NULL);
+ r->left = 0;
+ r->right = canvas_w;
+ r->top = 0;
+ r->bottom = canvas_h;
+}
+
+// -----------------------------------------------------------------------
+void BufferPaintWnd::getBufferPaintDest(RECT *r) {
+ ASSERT(r != NULL);
+ getClientRect(r);
+}
+
+// -----------------------------------------------------------------------
+int BufferPaintWnd::onPaint(Canvas *canvas) {
+
+ BUFFERPAINTWND_PARENT::onPaint(canvas);
+
+ if (invalidated) bufferPaint();
+ invalidated = 0;
+
+ RECT r;
+ getBufferPaintDest(&r);
+ RECT sr;
+ getBufferPaintSource(&sr);
+
+ render_canvas->/*getSkinBitmap()->*/stretchToRectAlpha(canvas, &sr, &r, getPaintingAlpha());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+int BufferPaintWnd::onResize() {
+ if (!BUFFERPAINTWND_PARENT::onResize()) return 0;
+ if (updateCanvas()) {
+ invalidated = 1;
+ invalidate();
+ }
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+int BufferPaintWnd::updateCanvas() {
+ int w, h;
+ getBufferPaintSize(&w, &h);
+
+ if (wantEvenAlignment()) {
+ if (w & 1) w++;
+ if (h & 1) h++;
+ }
+
+ if (w == 0 || h == 0) return 0;
+
+ int newone = 0;
+
+ if (canvas_w != w || canvas_h != h) {
+ if (render_canvas)
+ render_canvas->DestructiveResize(w, wantNegativeHeight() ? -h : h);
+ else
+ render_canvas = new BltCanvas(w, wantNegativeHeight() ? -h : h, getOsWindowHandle());
+ canvas_w = w;
+ canvas_h = h;
+ newone = 1;
+ onNewBuffer(canvas_w, canvas_h);
+ }
+
+ return newone;
+}
diff --git a/Src/Wasabi/api/wnd/wndclass/bufferpaintwnd.h b/Src/Wasabi/api/wnd/wndclass/bufferpaintwnd.h
new file mode 100644
index 00000000..778fb751
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/bufferpaintwnd.h
@@ -0,0 +1,40 @@
+#ifndef __BPAINTWND_H
+#define __BPAINTWND_H
+
+#include <api/wnd/wndclass/guiobjwnd.h>
+
+#define BUFFERPAINTWND_PARENT GuiObjectWnd
+
+class BufferPaintWnd : public BUFFERPAINTWND_PARENT {
+
+ public:
+ BufferPaintWnd();
+ virtual ~BufferPaintWnd();
+
+ virtual int onInit();
+ virtual int onPaint(Canvas *c);
+
+ virtual int onBufferPaint(BltCanvas *c, int w, int h) { return 1; }
+ virtual int wantEvenAlignment() { return 0; } // if you need even coordinates for your framebuffer, return 1 here
+ virtual void getBufferPaintSize(int *w, int *h); // by default returns client width/height
+ virtual void getBufferPaintSource(RECT *r); // by default returns the size of the quickpaint canvas
+ virtual void getBufferPaintDest(RECT *r); // by default returns the size of client area
+ virtual int wantNegativeHeight() { return 0; }
+ virtual void invalidateBuffer();
+ virtual int onResize();
+ virtual void onNewBuffer(int w, int h) {}
+
+ protected:
+ BltCanvas *render_canvas;
+
+ private:
+ void bufferPaint();
+ int updateCanvas();
+
+ int canvas_w, canvas_h;
+
+ int invalidated;
+};
+
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/buttbar.cpp b/Src/Wasabi/api/wnd/wndclass/buttbar.cpp
new file mode 100644
index 00000000..ffb491cf
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/buttbar.cpp
@@ -0,0 +1,208 @@
+#include "precomp.h"
+//PORTABLE
+#include <bfc/wasabi_std.h>
+#include <api/wnd/wndclass/buttbar.h>
+#include <api/wnd/notifmsg.h>
+#include <api/wnd/wndclass/buttwnd.h>
+#include <api/wnd/popup.h>
+#include <api/script/objects/c_script/c_text.h>
+#include <api/script/objects/c_script/h_button.h>
+
+
+class ButtHooker : public H_Button {
+public:
+ ButtHooker(ButtBar *hangout, ScriptObject *butt) : bb(hangout), H_Button(butt) { }
+
+ void hook_onLeftClick() {
+ bb->onLeftPush(0, 0);
+ }
+
+private:
+ ButtBar *bb;
+};
+
+ButtBar::ButtBar(int resizemode) {
+ spacer = 0;
+ resize_mode = resizemode;
+ hooker = NULL;
+ if (resize_mode == STACK) {
+ setContent(L"wasabi.buttonbar.stack");
+ }
+}
+
+ButtBar::~ButtBar() {
+ buttons.deleteAll();
+ delete hooker;
+}
+
+void ButtBar::setResizeMode(int resizemode) {
+ if (resize_mode == resizemode) return;
+ resize_mode = resizemode;
+ if (isPostOnInit()) onResize();
+}
+
+int ButtBar::onInit() {
+ int i;
+
+ BUTTBAR_PARENT::onInit();
+
+ // create the buttons
+ for (i = 0; i < buttons.getNumItems(); i++) {
+ buttons[i]->init(this);
+ if (resize_mode == STACK) {
+ if (i != 0) buttons[i]->setVisible(FALSE);
+ if (i == 0) setGroupLabel(buttons[i]->getButtonText());
+ }
+ }
+
+ return 1;
+}
+
+int ButtBar::addChild(ButtonWnd *child) {
+ buttons.addItem(child);
+ if (isInited()) {
+ child->init(this);
+ child->setParent(this);
+ onResize();
+ if (buttons.getNumItems() == 1)
+ setGroupLabel(child->getButtonText());
+ }
+ return 1;
+}
+
+int ButtBar::removeChild(ButtonWnd *child) {
+ if (!buttons.haveItem(child)) return 0;
+ if (isInited()) onResize();
+ return 1;
+}
+
+int ButtBar::getNumChildren() {
+ return buttons.getNumItems();
+}
+
+ButtonWnd *ButtBar::enumChild(int n) {
+ return buttons[n];
+}
+
+int ButtBar::getWidth() {
+ int w = 0;
+ for (int i = 0; i < buttons.getNumItems(); i++) {
+ w += buttons[i]->getWidth()+spacer;
+ }
+ return w;
+}
+
+int ButtBar::getHeight() {
+ if (resize_mode == STACK) {
+ ifc_window *rw = getContentRootWnd();
+ return rw->getPreferences(SUGGESTED_H);
+ } else {
+ int h = 0;
+ for (int i = 0; i < buttons.getNumItems(); i++) {
+ h = MAX(h, buttons[i]->getHeight()+1);
+ }
+ return h;
+ }
+}
+
+void ButtBar::onLeftPush(int x, int y)
+{
+ if (resize_mode == STACK)
+ {
+ PopupMenu pop(this);
+ foreach(buttons)
+ pop.addCommand(buttons.getfor()->getButtonText(), foreach_index);
+ endfor
+ int r = pop.popAnchored();
+ if (r >= 0) {
+ buttons[r]->onLeftPush(0, 0);
+ setGroupLabel(buttons[r]->getButtonText());
+ }
+ }
+}
+
+int ButtBar::childNotify(ifc_window *child, int msg, intptr_t p1, intptr_t p2) {
+ switch (msg) {
+ case ChildNotify::BUTTON_LEFTPUSH: {
+ int ret;
+ if (ret = onLeftPush(child->getNotifyId())) {
+ return ret;
+ } else {
+// This won't fit the current notification schema.
+// We _must_ change it -- too many interfaces assume that the
+// button notification is called back through the parent.
+// return notifyParent(msg, p1, p2);
+
+// So, I made a new basewnd method passNotifyUp() to defer a notification
+// to the current object's notification target.
+ return passNotifyUp(child, msg, p1, p2);
+ }
+ }
+ break;
+ }
+ return BUTTBAR_PARENT::childNotify(child, msg, p1, p2);
+}
+
+int ButtBar::onResize() {
+ BUTTBAR_PARENT::onResize(); // calling your parent is good(tm) =)
+ if (!isPostOnInit()) return 0; // that's just an optim, in case someone's dumb and calling us directly when it shouldnt
+ switch (resize_mode) {
+ case NORMAL: {
+ RECT r = clientRect();
+ int height = r.bottom - r.top;
+ int x = r.left;
+ for (int i = 0; i < buttons.getNumItems(); i++) {
+ int w = buttons[i]->getWidth()+spacer;
+ buttons[i]->resize(x, r.top, w, height);
+ x += w;
+ if (x > r.right) break;
+ }
+ }
+ break;
+ case STRETCH: {
+ if (buttons.getNumItems() > 0) {
+ RECT r = clientRect();
+ int height = r.bottom - r.top;
+ int w = (r.right - r.left) / buttons.getNumItems();
+ int x = r.left;
+ for (int i = 0; i < buttons.getNumItems(); i++) {
+ if (i == buttons.getNumItems()-1) w = (r.right - r.left) - x;
+ buttons[i]->resize(x, r.top, w, height);
+ x += w;
+ }
+ }
+ }
+ break;
+ case STACK: // no point
+ break;
+ }
+
+ return 1;
+}
+
+int ButtBar::onPaint(Canvas *canvas) {
+ ASSERT(canvas != NULL);
+ if (resize_mode != STACK) {
+ BUTTBAR_PARENT::onPaint(canvas);
+ renderBaseTexture(canvas, clientRect());
+ }
+ return 1;
+}
+
+void ButtBar::setGroupLabel(const wchar_t *l) {
+ setName(l);
+ onNewContent();
+}
+
+void ButtBar::onNewContent()
+{
+ if (resize_mode != STACK) return;
+ ScriptObject *text = findScriptObject(L"buttonbar.text");
+ if (text == NULL) return;
+ C_Text(text).setText(getNameSafe(L"no tabs"));
+
+ // hook the clicks
+ delete hooker;
+ ScriptObject *mousetrap = findScriptObject(L"mousetrap");
+ hooker = new ButtHooker(this, mousetrap);
+}
diff --git a/Src/Wasabi/api/wnd/wndclass/buttbar.h b/Src/Wasabi/api/wnd/wndclass/buttbar.h
new file mode 100644
index 00000000..473ddd58
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/buttbar.h
@@ -0,0 +1,168 @@
+#ifndef _BUTTBAR_H
+#define _BUTTBAR_H
+
+#include <bfc/common.h>
+#include <api/wnd/wndclass/guiobjwnd.h>
+#include <bfc/ptrlist.h>
+
+class ButtonWnd;
+class ButtHooker;
+
+#define BUTTBAR_PARENT GuiObjectWnd
+/**
+ A resizable button bar control.
+
+ @short A resizable button bar
+ @author Nullsoft
+ @ver 1.0
+ @see ButtonWnd
+*/
+class ButtBar : public BUTTBAR_PARENT {
+public:
+ // resize modes
+ /**
+ Resize modes for the button bar.
+ */
+ enum { NORMAL, STRETCH, STACK };
+
+ /**
+ You can set the resize mode for the button bar by specifying it
+ via the contructor.
+
+ @see ~ButtBar() setResizeMode()
+ @param resizemode The default resize mode.
+ */
+ ButtBar(int resizemode=NORMAL);
+
+ /**
+ Deletes all the buttons present in the button bar.
+
+ @see ButtBar()
+ */
+ virtual ~ButtBar();
+
+ /**
+ This event is triggered when the button bar is being initialized.
+ If you override this, please call up the parent chain first, then
+ do your initialization.
+
+ @ret 1
+ */
+ virtual int onInit();
+
+ /**
+ This event is triggered when the button bar is being resized.
+ If you override this, please call up the parent chain first, then
+ do your own resize handling.
+
+ @ret 1
+ */
+ virtual int onResize();
+
+ /**
+ This event is triggered when the button bar is being painted.
+ If you override this, please call up the parent chain first, then
+ do your painting.
+
+ @ret 1
+ @param canvas The canvas upon which we will paint ourself.
+ */
+ virtual int onPaint(Canvas *canvas);
+
+ /**
+ Sets the resize mode for the button bar.
+
+ @param resizemode NORMAL, Normal Resize; STRETCH, Stretch the button bar to window width; STACK, ?;
+ */
+ virtual void setResizeMode(int resizemode);
+
+ /**
+ Enables you to add a child window to your button bar.
+ Since this is a button bar, the windows you can add must be
+ derived or be ButtonWnd's.
+
+ @see removeChild()
+ @see getNumChildren()
+ @see enumChild()
+ @see ButtonWnd
+ @ret 1
+ @param child A pointer to the child window to add.
+ */
+ int addChild(ButtonWnd *child);
+
+ /**
+ */
+ int removeChild(ButtonWnd *child); // does not delete, just removes
+
+ /**
+ Get the number of children (buttons) that the button bar has.
+
+ @ret The number of children (buttons).
+ */
+ int getNumChildren();
+
+ /**
+ Get a pointer to a child (button) in the button bar, by button index number.
+ The first button added is at index 0.
+
+ @ret !NULL, a pointer the requested button; NULL, The button does not exist;
+ */
+ ButtonWnd *enumChild(int n);
+
+ /**
+ Get the width of the button bar (in pixels).
+
+ @see getHeight()
+ @ret Width of the button bar (in pixels).
+ */
+ int getWidth();
+
+ /**
+ Get the height of the button bar (in pixels).
+
+ @see getWidth()
+ @ret Height of the button bar (in pixels).
+ */
+ int getHeight();
+
+ /**
+ Event is triggered when the left mouse button is used to click on the
+ button bar. Override this to implement your own handling of the event.
+ If you override this method, call up the parent chain.
+
+ @param x The x coordinate of the mouse cursor in the button bar.
+ @param y The y coordinate of the mouse cursor in the button bar.
+ */
+ virtual void onLeftPush(int x, int y);
+
+ /**
+ Notify a child window via a generic message system.
+
+ @see addChild()
+ @ret
+ @param child A pointer to the child window which will receive the notify.
+ @param msg The message you want to send to the child.
+ @param p1 A user parameter.
+ @param p2 A user parameter.
+ */
+ virtual int childNotify(ifc_window *child, int msg,
+ intptr_t param1=0, intptr_t param2=0);
+
+ // GuiObjectWnd
+ virtual void onNewContent();
+
+ void setSpacer(int sp) { spacer = sp; }
+
+ void setGroupLabel(const wchar_t *l);
+
+protected:
+ virtual int onLeftPush(int id) { return 0; }
+
+ PtrList<ButtonWnd> buttons;
+private:
+ int resize_mode;
+ int spacer;
+ ButtHooker *hooker;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/buttwnd.cpp b/Src/Wasabi/api/wnd/wndclass/buttwnd.cpp
new file mode 100644
index 00000000..ddd500e5
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/buttwnd.cpp
@@ -0,0 +1,761 @@
+#include <precomp.h>
+// bitmap-style buttons
+
+#include "buttwnd.h"
+#include <bfc/wasabi_std.h>
+#include <tataki/canvas/bltcanvas.h>
+#include <tataki/region/region.h>
+#include <api/wnd/notifmsg.h>
+
+
+#include <api/wndmgr/msgbox.h>
+#include <api/wnd/PaintCanvas.h>
+#define DEFAULT_BUTTON_HEIGHT 20
+
+ButtonWnd::ButtonWnd(const wchar_t *button_text)
+{
+ if (button_text != NULL)
+ setName(button_text);
+ currgn = NULL;
+ hirgn = NULL;
+ normalrgn = NULL;
+ pushedrgn = NULL;
+ activatedrgn = NULL;
+ base_texture = NULL;
+ xShift=0;
+ yShift=0;
+ textsize = DEFAULT_BUTTON_TEXT_SIZE;
+ alignment = TEXTALIGN_CENTER;
+ activated = 0;
+ userhilite = 0;
+ userdown = 0;
+ use_base_texture = 0;
+ center_bitmap = 0;
+ enabled = 1;
+ checked=0;
+ autodim=0;
+ borders = 1;
+ borderstyle = 0;
+ setBorderStyle(L"button_normal");
+ iwantfocus = 1;
+ color_text = L"wasabi.button.text";
+ color_hilite = L"wasabi.button.hiliteText";
+ color_dimmed = L"wasabi.button.dimmedText";
+ checkbmp = L"wasabi.popup.menu.check";
+ inactivealpha = 255;
+ activealpha = 255;
+ setRectRgn(1);
+ retcode = MSGBOX_ABORTED;
+ forcedown=0;
+}
+
+ButtonWnd::~ButtonWnd() {
+ delete normalrgn;
+ delete pushedrgn;
+ delete hirgn;
+ delete activatedrgn;
+}
+
+void ButtonWnd::checkState(POINT *pt) {
+ POINT pt2;
+ if (pt == NULL) {
+ pt = &pt2;
+ Wasabi::Std::getMousePos(pt);
+ }
+
+ api_region *old = currgn;
+
+ if (getDown()) { // button is down
+ if (pushedrgn)
+ currgn = pushedrgn;
+ else
+ currgn = normalrgn;
+ } else { // button is not down
+ if (hirgn && getHilite())
+ currgn = hirgn;
+ else
+ currgn = normalrgn;
+ }
+
+ if (old != currgn) invalidateWindowRegion();
+}
+
+void ButtonWnd::onCancelCapture() {
+ BUTTONWND_PARENT::onCancelCapture();
+ checkState();
+}
+
+int ButtonWnd::onMouseMove(int x, int y) {
+ POINT pt;
+ checkState(&pt);
+ return BUTTONWND_PARENT::onMouseMove(x, y);
+}
+
+api_region *ButtonWnd::getRegion() {
+ if (borders) return NULL;
+ return currgn;
+}
+
+void ButtonWnd::setModalRetCode(int r) { retcode = r; }
+int ButtonWnd::getModalRetCode() const { return retcode; }
+
+void ButtonWnd::onLeaveArea() {
+ BUTTONWND_PARENT::onLeaveArea();
+ if (hirgn || getDown()) invalidate();
+}
+
+void ButtonWnd::onEnterArea() {
+ BUTTONWND_PARENT::onEnterArea();
+ if (hirgn) invalidate();
+}
+
+/*BOOL ButtonWnd::mouseInRegion(int x, int y) {
+ POINT pos={x,y};
+ POINT p2=pos;
+
+ RECT r;
+ getClientRect(&r);
+ pos.x-=r.left;
+ pos.y-=r.top;
+
+ return (((!currgn || rectrgn) && PtInRect(&r, p2)) || (currgn && currgn->ptInRegion(&pos)));
+}*/
+
+int ButtonWnd::setBitmaps(const wchar_t *_normal, const wchar_t *_pushed, const wchar_t *_hilited, const wchar_t *_activated) {
+
+ if (_normal) { delete normalrgn; normalrgn = NULL; }
+ if (_pushed) { delete pushedrgn; pushedrgn = NULL; }
+ if (_hilited) { delete hirgn; hirgn = NULL; }
+ if (_activated) { delete activatedrgn; activatedrgn = NULL; }
+
+ if (_normal) {
+ normalbmp = _normal;
+ normalrgn = new RegionI(normalbmp.getBitmap());
+ currgn = normalrgn;
+ }
+
+ if (_pushed) {
+ pushedbmp = _pushed;
+ pushedrgn = new RegionI(pushedbmp.getBitmap());
+ }
+
+ if (_hilited) {
+ hilitebmp = _hilited;
+ hirgn = new RegionI(hilitebmp.getBitmap());
+ }
+
+ if (_activated) {
+ activatedbmp = _activated;
+ activatedrgn = new RegionI(activatedbmp.getBitmap());
+ }
+
+ if (isPostOnInit())
+ invalidate();
+
+ return 1;
+}
+
+SkinBitmap *ButtonWnd::getNormalBitmap() {
+ return normalbmp.getBitmap();
+}
+
+void ButtonWnd::freeResources() {
+ BUTTONWND_PARENT::freeResources();
+ delete normalrgn;
+ delete pushedrgn;
+ delete hirgn;
+ delete activatedrgn;
+ pushedrgn=NULL;
+ normalrgn=NULL;
+ hirgn=NULL;
+ activatedrgn=NULL;
+ currgn=NULL;
+}
+
+void ButtonWnd::reloadResources() {
+ BUTTONWND_PARENT::reloadResources();
+ if (normalbmp.getBitmap())
+ normalrgn = new RegionI(normalbmp.getBitmap());
+ if (pushedbmp.getBitmap())
+ pushedrgn = new RegionI(pushedbmp.getBitmap());
+ if (hilitebmp.getBitmap())
+ hirgn = new RegionI(hilitebmp.getBitmap());
+ if (activatedbmp.getBitmap())
+ activatedrgn = new RegionI(activatedbmp.getBitmap());
+ currgn = normalrgn;
+}
+
+int ButtonWnd::setBitmapCenter(int centerit) {
+ return center_bitmap = !!centerit;
+}
+
+int ButtonWnd::setBitmaps(OSMODULEHANDLE hInst, int _normal, int _pushed, int _hilited, int _activated, const wchar_t *_colorgroup)
+{
+ if (_normal) { delete normalrgn; normalrgn = NULL; }
+ if (_pushed) { delete pushedrgn; pushedrgn = NULL; }
+ if (_hilited) { delete hirgn; hirgn = NULL; }
+ if (_activated) { delete activatedrgn; activatedrgn = NULL; }
+
+ if (_colorgroup == NULL)
+ _colorgroup = colorgroup;
+
+ if (_normal)
+ {
+ normalbmp.setHInstanceBitmapColorGroup(_colorgroup);
+#ifdef _WIN32
+ normalbmp.setHInstance(hInst);
+#else
+#warning port me?
+#endif
+ normalbmp = _normal;
+ normalrgn = new RegionI(normalbmp.getBitmap());
+ }
+
+ if (_pushed) {
+ pushedbmp.setHInstanceBitmapColorGroup(_colorgroup);
+#ifdef _WIN32
+ pushedbmp.setHInstance(hInst);
+#else
+#warning port me?
+#endif
+ pushedbmp = _pushed;
+ pushedrgn = new RegionI(pushedbmp.getBitmap());
+ }
+
+ if (_hilited) {
+ hilitebmp.setHInstanceBitmapColorGroup(_colorgroup);
+#ifdef _WIN32
+ hilitebmp.setHInstance(hInst);
+#else
+#warning port me?
+#endif
+ hilitebmp = _hilited;
+ hirgn = new RegionI(hilitebmp.getBitmap());
+ }
+
+ if (_activated) {
+ activatedbmp.setHInstanceBitmapColorGroup(_colorgroup);
+ #ifdef _WIN32
+ activatedbmp.setHInstance(hInst);
+#else
+#warning port me?
+#endif
+ activatedbmp = _activated;
+ activatedrgn = new RegionI(activatedbmp.getBitmap());
+ }
+
+ return 1;
+}
+
+void ButtonWnd::setUseBaseTexture(int useit)
+{
+ if (use_base_texture == useit) return;
+ use_base_texture = useit;
+ invalidate();
+}
+
+void ButtonWnd::setBaseTexture(SkinBitmap *bmp, int x, int y, int tile)
+{
+ base_texture = bmp;
+ use_base_texture = TRUE;
+ tile_base_texture=tile;
+ xShift=x;
+ yShift=y;
+ invalidate();
+}
+
+int ButtonWnd::setButtonText(const wchar_t *text, int size)
+{
+ textsize = size;
+ ASSERT(textsize > 0);
+ setName(text);
+ invalidate();
+ return 1;
+}
+
+const wchar_t * ButtonWnd::getButtonText()
+{
+ return getName();
+}
+
+void ButtonWnd::setTextAlign(TextAlign align)
+{
+ alignment = align;
+ invalidate();
+}
+
+int ButtonWnd::getWidth()
+{
+ int addl=0;
+ if (checked) {
+ addl=checkbmp.getWidth()+3;
+ }
+ if (rightbmp.getBitmap())
+ addl+=rightbmp.getWidth()+3;
+ if (normalbmp == NULL)
+ {
+ TextInfoCanvas blt(this);
+ Wasabi::FontInfo fontInfo;
+ fontInfo.pointSize = textsize;
+ StringPrintfW lstr(L"j%sj", getNameSafe(L""));
+ if (wcschr(lstr, '\t')) lstr.cat(L" ");
+ int a=MAX((blt.getTextWidth(lstr, &fontInfo)*11)/10,8)+addl;
+ return a;
+ }
+ return normalbmp.getWidth()+addl;
+}
+
+int ButtonWnd::getHeight()
+{
+ int minh=0;
+ if (checked>0)
+ minh=checkbmp.getHeight();
+ if (rightbmp.getBitmap())
+ minh=MAX(rightbmp.getHeight(),minh);
+ if (normalbmp == NULL)
+ {
+ TextInfoCanvas blt(this);
+ Wasabi::FontInfo fontInfo;
+ fontInfo.pointSize = textsize;
+ int r = MAX(MAX((blt.getTextHeight(getName(), &fontInfo)*11)/10,minh),4);
+ return r;
+ }
+ return MAX(normalbmp.getHeight(),minh);
+}
+
+void ButtonWnd::enableButton(int _enabled) {
+ _enabled = !!_enabled;
+ if (enabled != _enabled) invalidate();
+ enabled = _enabled;
+ onEnable(enabled);
+}
+
+int ButtonWnd::getEnabled() const {
+ return enabled;
+}
+
+int ButtonWnd::onPaint(Canvas *canvas)
+{
+ PaintBltCanvas paintcanvas;
+ SkinBitmap *bmp;
+ RECT r;
+ int labelxoffs=0;
+ int offset = (enabled&&(getPushed()||getDown())) ? 1 : 0;
+
+ if (checked) labelxoffs+=3+checkbmp.getWidth();
+
+ if (canvas == NULL) {
+ if (!paintcanvas.beginPaint(this)) return 0;
+ canvas = &paintcanvas;
+ }
+ BUTTONWND_PARENT::onPaint(canvas);
+
+ bmp = normalbmp;
+ if (pushedbmp && (getDown() || getPushed())) bmp = pushedbmp;
+ else if ((getHilite() || userhilite) && hilitebmp) bmp = hilitebmp;
+ else if (activatedbmp && getActivatedButton()) bmp = activatedbmp;
+
+ getClientRect(&r);
+
+ RECT nr = r;
+// RECT fcr = r;
+ if (use_base_texture)
+ {
+ if (!base_texture)
+ renderBaseTexture(canvas, r);
+ else {
+ RECT cr;
+ cr.left = xShift;
+ cr.top = yShift;
+ cr.right = cr.left + (r.right-r.left);
+ cr.bottom = cr.top + (r.bottom-r.top);
+ if (tile_base_texture) base_texture->blitTile(canvas, &r,xShift,yShift);
+ else base_texture->stretchToRectAlpha(canvas, &cr, &r, getPaintingAlpha());
+ }
+ }
+ else
+ {
+ if (borders)
+ {
+ int sysobj = -1;
+ if (!enabled)
+ sysobj = dsoDisabled;
+ else
+ sysobj = (getPushed() || getDown()) ? dsoPushed : dsoNormal;
+ if (sysobj != -1) canvas->drawSysObject(&nr, sysobj, getPaintingAlpha());
+ }
+ }
+
+ if (checked>0)
+ {
+ RECT ar;
+ int c=(r.top+r.bottom)/2;
+ ar.left=r.left;
+ ar.top=c-checkbmp.getHeight()/2;
+ ar.bottom=ar.top+checkbmp.getHeight();
+ ar.right=r.left+checkbmp.getWidth();
+ checkbmp.getBitmap()->stretchToRectAlpha(canvas,&ar,getPaintingAlpha());
+ }
+ if (rightbmp.getBitmap()) {
+ RECT ar;
+ int c=(r.top+r.bottom)/2;
+ ar.top=c-rightbmp.getHeight()/2;
+ ar.bottom=ar.top+rightbmp.getHeight();
+ ar.right=r.right;
+ ar.left=ar.right-rightbmp.getWidth();
+
+ int alpha = getPaintingAlpha();
+ if (!getEnabled()) alpha /= 2;
+ rightbmp.getBitmap()->stretchToRectAlpha(canvas, &ar, alpha);
+ }
+
+ if (bmp != NULL) {
+ RECT br = r;
+ if (center_bitmap) {
+ int w = (r.right - r.left) - getWidth() - labelxoffs;
+ int h = (r.bottom - r.top) - getHeight();
+ br.top = r.top + h/2 + offset;
+ br.bottom = br.top + getHeight();
+ br.left = r.left + w/2 + labelxoffs + offset;
+ br.right = br.left + getWidth() - (rightbmp.getBitmap()?rightbmp.getWidth()+3:0);
+ } else {
+ br.left += labelxoffs;
+ br.right -= (rightbmp.getBitmap()?rightbmp.getWidth()+3:0);
+ }
+ int alpha2;
+ if (!hilitebmp && enabled && autodim) {
+ alpha2=128;
+ if (getHilite() || userhilite) alpha2=255;
+ } else alpha2 = enabled ? 255 : 64;
+ bmp->stretchToRectAlpha(canvas, &br,autodim ? (getPaintingAlpha()+alpha2)>>1 : getPaintingAlpha());
+ }
+
+ if (getName() != NULL)
+ {
+ Wasabi::FontInfo fontInfo;
+ fontInfo.opaque = false;
+ fontInfo.pointSize = textsize;;
+
+ int textw, texth;
+ canvas->getTextExtent(getName(), &textw, &texth, &fontInfo);
+
+ if (!enabled)
+ fontInfo.color = color_dimmed;
+ else if (userhilite)
+ fontInfo.color = color_hilite;
+ else
+ fontInfo.color = color_text;
+ int h=(r.bottom-r.top-texth)/2;
+ if (h<0) h=0;
+
+ r.left += offset + labelxoffs;
+ r.right += offset - (rightbmp.getBitmap()?rightbmp.getWidth()+3:0);
+ r.top += offset+h;
+ r.bottom = r.top+texth;
+
+ switch (alignment)
+ {
+ case TEXTALIGN_CENTER:
+ canvas->textOutCentered(&r, getName(), &fontInfo);
+ break;
+
+ case TEXTALIGN_RIGHT:
+ canvas->textOut(r.right-textw, r.top, textw, texth, getName(), &fontInfo);
+ break;
+
+ case TEXTALIGN_LEFT:
+ if (!wcsstr(getName(), L"\t"))
+ {
+ canvas->textOut(r.left, r.top, r.right-r.left, r.bottom-r.top, getName(), &fontInfo);
+ }
+ else
+ {
+ StringW lstr(getName());
+ wchar_t *p=wcsstr(lstr.getNonConstVal(),L"\t");
+ if (p) *p++=0;
+ else p=L"";
+ int tw=canvas->getTextWidth(p, &fontInfo);
+ canvas->textOut(r.left, r.top, r.right-r.left-tw, r.bottom-r.top, lstr, &fontInfo);
+ canvas->textOut(r.right-tw, r.top, tw, r.bottom-r.top, p, &fontInfo);
+ }
+ break;
+
+ case TEXTALIGN_LEFT_ELLIPSIS:
+ if (!wcsstr(getName(),L"\t"))
+ {
+ canvas->textOutEllipsed(r.left, r.top, r.right-r.left, r.bottom-r.top, getName(), &fontInfo);
+ }
+ else
+ {
+ StringW lstr(getName());
+ wchar_t *p=wcsstr(lstr.getNonConstVal(),L"\t");
+ if (p) *p++=0;
+ else p=L"";
+ int tw=canvas->getTextWidth(p, &fontInfo);
+ canvas->textOutEllipsed(r.left, r.top, r.right-r.left-tw, r.bottom-r.top, lstr, &fontInfo);
+ canvas->textOutEllipsed(r.right-tw, r.top, tw, r.bottom-r.top, p, &fontInfo);
+ }
+ break;
+ }
+/*
+ if (textjustify == BUTTONJUSTIFY_CENTER)
+ canvas->textOutCentered(&r, getName());
+ else if (textjustify == BUTTONJUSTIFY_LEFT)
+ {
+ if (!STRSTR(getName(),"\t"))
+ canvas->textOutEllipsed(r.left, r.top, r.right-r.left, r.bottom-r.top, getName());
+ else
+ {
+ char *lstr=STRDUP(getName());
+ char *p=STRSTR(lstr,"\t");
+ if (p) *p++=0;
+ else p="";
+ int tw=canvas->getTextWidth(p);
+ canvas->textOutEllipsed(r.left, r.top, r.right-r.left-tw, r.bottom-r.top, lstr);
+ canvas->textOutEllipsed(r.right-tw, r.top, tw, r.bottom-r.top, p);
+ FREE(lstr);
+ }
+ }
+*/
+ }
+
+
+/* if (enabled && gotFocus() && wantFocus()) { // SKIN ME
+ fcr.left+=3;
+ fcr.right-=3;
+ fcr.top+=3;
+ fcr.bottom-=3;
+ DrawFocusRect(canvas->getHDC(), &fcr);
+ }*/
+
+ return 1;
+}
+
+void ButtonWnd::onLeftPush(int x, int y)
+{
+ notifyParent(ChildNotify::BUTTON_LEFTPUSH);
+ invalidate();
+}
+void ButtonWnd::onRightPush(int x, int y) {
+ notifyParent(ChildNotify::BUTTON_RIGHTPUSH);
+ invalidate();
+}
+void ButtonWnd::onLeftDoubleClick(int x, int y) {
+ notifyParent(ChildNotify::BUTTON_LEFTDOUBLECLICK);
+}
+void ButtonWnd::onRightDoubleClick(int x, int y) {
+ notifyParent(ChildNotify::BUTTON_RIGHTDOUBLECLICK);
+}
+
+void ButtonWnd::setHilite(int h) {
+ h = !!h;
+ if (userhilite != h) {
+ userhilite = h;
+ invalidate();
+ }
+}
+
+int ButtonWnd::getHilite() {
+ return userhilite || BUTTONWND_PARENT::getHilite();
+}
+
+int ButtonWnd::getPushed() const {
+ return userdown || forcedown;
+}
+
+void ButtonWnd::setPushed(int p) {
+ p = !!p;
+ if (userdown != p)
+ {
+ userdown=p;
+ invalidate();
+ }
+}
+
+int ButtonWnd::onResize() {
+ BUTTONWND_PARENT::onResize();
+// invalidate();
+ return 1;
+}
+
+void ButtonWnd::setCheckBitmap(const wchar_t *checkbm) {
+ checkbmp = checkbm;
+}
+
+int ButtonWnd::setRightBitmap(const wchar_t *bitmap) {
+ rightbmp=bitmap;
+ return 1;
+}
+
+void ButtonWnd::setActivatedButton(int a) {
+ if (activated != a) {
+ activated = a;
+ invalidate();
+ onActivateButton(activated);
+ }
+}
+
+void ButtonWnd::setActivatedNoCallback(int a) {
+ // also force invalidate.
+ activated = a;
+ invalidate();
+}
+
+int ButtonWnd::onActivateButton(int active) {
+ return 1;
+}
+
+int ButtonWnd::getActivatedButton() {
+ return activated;
+}
+
+void ButtonWnd::setBorders(int b) {
+ b = !!b;
+ if (borders != b) {
+ borders = b;
+ setRectRgn(borders);
+ invalidate();
+ }
+}
+
+void ButtonWnd::setBorderStyle(const wchar_t *style) {
+ if (style == NULL) style = L"";
+ if (borderstyle && !WCSICMP(borderstyle, style)) return;
+
+// borderstyle = style;
+
+ using namespace DrawSysObj;
+ static struct {
+ const wchar_t *style;
+ int normal, pushed, disabled;
+ } chart[] = {
+ { L"button_normal", BUTTON, BUTTON_PUSHED, BUTTON_DISABLED },
+ { L"osbutton_normal", OSBUTTON, OSBUTTON_PUSHED, OSBUTTON_DISABLED },
+ { L"osbutton_close", OSBUTTON_CLOSE, OSBUTTON_CLOSE_PUSHED, OSBUTTON_CLOSE_DISABLED },
+ { L"osbutton_minimize", OSBUTTON_MINIMIZE, OSBUTTON_MINIMIZE_PUSHED, OSBUTTON_MINIMIZE_DISABLED },
+ { L"osbutton_maximize", OSBUTTON_MAXIMIZE, OSBUTTON_MAXIMIZE_PUSHED, OSBUTTON_MAXIMIZE_DISABLED },
+ { NULL, BUTTON, BUTTON_PUSHED, BUTTON_DISABLED },
+ };
+ dsoNormal = dsoPushed = dsoDisabled = -1;
+ for (int i = 0; ; i++) {
+ if (chart[i].style == NULL) return;
+ if (!WCSICMP(chart[i].style, style)) {
+ borderstyle = chart[i].style;
+ dsoNormal = chart[i].normal;
+ dsoPushed = chart[i].pushed;
+ dsoDisabled = chart[i].disabled;
+ }
+ }
+
+ invalidate();
+}
+
+const wchar_t *ButtonWnd::getBorderStyle() {
+ return borderstyle;
+}
+
+void ButtonWnd::setInactiveAlpha(int a) {
+ inactivealpha=a;
+}
+
+void ButtonWnd::setActiveAlpha(int a) {
+ activealpha=a;
+}
+
+int ButtonWnd::onGetFocus() {
+ BUTTONWND_PARENT::onGetFocus();
+// invalidate();
+ return 1;
+}
+
+int ButtonWnd::onKillFocus() {
+ BUTTONWND_PARENT::onKillFocus();
+// invalidate();
+ return 1;
+}
+
+void ButtonWnd::setColors(const wchar_t *text, const wchar_t *hilite, const wchar_t *dimmed) {
+ color_text=text;
+ color_hilite=hilite;
+ color_dimmed=dimmed;
+ invalidate();
+}
+
+void ButtonWnd::setTextColor(const wchar_t *text) {
+ color_text=text;
+ invalidate();
+}
+
+void ButtonWnd::setTextHoverColor(const wchar_t *hilite) {
+ color_hilite=hilite;
+ invalidate();
+}
+
+void ButtonWnd::setTextDimmedColor(const wchar_t *dimmed) {
+ color_dimmed=dimmed;
+ invalidate();
+}
+
+int ButtonWnd::onEnable(int is) {
+ return BUTTONWND_PARENT::onEnable(is);
+}
+
+int ButtonWnd::getPreferences(int what) {
+ switch (what) {
+ case SUGGESTED_W: {
+ if (!normalBmpStr.isempty()) return normalbmp.getWidth();
+ return getWidth();
+ }
+ case SUGGESTED_H: {
+ if (!normalBmpStr.isempty()) return normalbmp.getHeight();
+ return getHeight();
+ }
+ }
+ return BUTTONWND_PARENT::getPreferences(what);
+}
+
+int ButtonWnd::onInit() {
+ int r = BUTTONWND_PARENT::onInit();
+ currgn = normalrgn;
+ return r;
+}
+
+int ButtonWnd::onChar(unsigned int c)
+{
+ switch (c) {
+#ifdef _WIN32
+ case VK_RETURN:
+ case VK_SPACE:
+ postDeferredCallback(DEFEREDCB_DOWN, 0, 0);
+ postDeferredCallback(DEFEREDCB_UP, 0, 250);
+ //return BUTTONWND_PARENT::onChar(c);
+ break;
+#else
+#warning port me
+#endif
+ default:
+ return BUTTONWND_PARENT::onChar(c);
+ }
+ return 1;
+}
+
+
+int ButtonWnd::onDeferredCallback(intptr_t p1, intptr_t p2) {
+ switch (p1) {
+ case DEFEREDCB_DOWN:
+ forcedown = 1;
+ invalidate();
+ break;
+ case DEFEREDCB_UP:
+ forcedown = 0;
+ invalidate();
+ RECT r;
+ getClientRect(&r);
+ onLeftPush(r.left+(r.right-r.left)/2, r.top+(r.bottom-r.top)/2);
+ default:
+ return BUTTONWND_PARENT::onDeferredCallback(p1, p2);
+ }
+ return 1;
+}
+
+
diff --git a/Src/Wasabi/api/wnd/wndclass/buttwnd.h b/Src/Wasabi/api/wnd/wndclass/buttwnd.h
new file mode 100644
index 00000000..d0367573
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/buttwnd.h
@@ -0,0 +1,602 @@
+#ifndef _BUTTWND_H
+#define _BUTTWND_H
+
+#include <wasabicfg.h>
+
+#include <bfc/common.h>
+#include <tataki/canvas/canvas.h>
+#include <tataki/bitmap/autobitmap.h>
+#include <api/wnd/wndclass/guiobjwnd.h>
+#include <tataki/color/skinclr.h>
+#include <api/wnd/accessible.h>
+#include <api/wnd/textalign.h>
+
+class api_region;
+
+#define DEFAULT_BUTTON_TEXT_SIZE 14
+/**
+ Button Text Alignment
+ Darkain: this was changed to use TextAlign
+*/
+/*
+typedef enum {
+ BUTTONJUSTIFY_LEFT,
+ BUTTONJUSTIFY_CENTER
+} ButtonJustify;
+*/
+
+#define DEFEREDCB_DOWN 0x450
+#define DEFEREDCB_UP 0x451
+
+#define BUTTONWND_PARENT GuiObjectWnd
+
+/**
+ A fully skinnable button. Has images for normal, hilited, activated states.
+ Plus images for a checked state. It may also be used to draw OS style buttons.
+ See setBorderStyle() for more details.
+
+ @short Button control.
+ @author Nullsoft
+ @ver 1.0
+ @see ButtBar
+*/
+class ButtonWnd : public BUTTONWND_PARENT {
+public:
+ /**
+ Sets defaults for ButtonWnd objects.
+
+ @see ~ButtonWnd()
+ @param button_text The button's caption.
+ */
+ ButtonWnd(const wchar_t *button_text=NULL);
+
+ /**
+ Deletes components of ButtonWnd.
+
+ @see ButtonWnd()
+ */
+ virtual ~ButtonWnd();
+
+ /**
+ Paints the bitmap on canvas according
+ to current options (centering, tiling, stretching, title).
+
+ @ret 0 for failure, 1 for success
+ @param canvas The canvas on which to paint.
+ */
+ virtual int onPaint(Canvas *canvas);
+
+ /**
+ Sets the bitmaps that will be used to render the button.
+ This includes bitmaps for various button states. Also enables
+ you to set the colorgroup (gammagroup) for the bitmaps.
+
+ @ret 1
+ @param _normal Bitmap for normal state.
+ @param _pushed Bitmap for pushed state.
+ @param _hilited Bitmap for hilited state.
+ @param _activated Bitmap for activated state.
+ @param colorgroup The colorgroup for the bitmaps (gammagroup).
+ */
+ int setBitmaps(const wchar_t *normal, const wchar_t *pushed=NULL, const wchar_t *hilited=NULL, const wchar_t *activated=NULL);
+
+ SkinBitmap *getNormalBitmap();
+
+ /**
+ Sets the bitmaps that will be used to render the button.
+ This includes bitmaps for various button states. Also enables
+ you to set the colorgroup (gammagroup) for the bitmaps.
+
+ @ret 1
+ @param hInst The parent window's instance handle.
+ @param _normal Bitmap for normal state.
+ @param _pushed Bitmap for pushed state.
+ @param _hilited Bitmap for hilited state.
+ @param _activated Bitmap for activated state.
+ @param colorgroup The colorgroup for the bitmaps (gammagroup).
+ */
+ int setBitmaps(OSMODULEHANDLE hInst, int normal, int pushed, int hilited, int activated, const wchar_t *colorgroup=NULL);
+
+ /**
+ Set the right bitmap to be used.
+
+ @see setBitmaps()
+ @ret 1
+ @param bitmap The name of the bitmap to use.
+ */
+ int setRightBitmap(const wchar_t *bitmap);
+
+ /**
+ Center the bitmap?
+
+ @see setBitmaps()
+ @ret Normalized flag
+ @param centerit A non zero value will center the bitmap.
+ */
+ int setBitmapCenter(int centerit);
+
+ /**
+ Sets base texture and causes rerendering.
+
+ @see setBaseTexture()
+ @param useit A non zero value will use the base texture.
+ */
+ void setUseBaseTexture(int useit);
+
+ /**
+ Sets bitmap for button, sets position for button, flags whether to tile the bitmap
+
+ @see setUseBaseTexture()
+ @param bmp Skin bitmap for button
+ @param x Button position on x-coordinate
+ @param yButton position on y-coordinate
+ @param tile Flag
+ */
+ void setBaseTexture(SkinBitmap *bmp, int x, int y, int tile=0);
+
+ /**
+ Sets the colorgroup (gammagroup) for all the bitmaps associated with
+ this button.
+
+ @param _colorgroup The colorgroup for the bitmaps.
+ */
+ void setHInstanceColorGroup(const wchar_t *_colorgroup) { colorgroup = _colorgroup; }
+
+ /**
+ Writes given text to button in given size and triggers rendering.
+
+ @see getButtonText()
+ @assert Text string is not empty
+ @ret 1
+ @param text Label text
+ @param size Size to render label text
+ */
+ int setButtonText(const wchar_t *text, int size=DEFAULT_BUTTON_TEXT_SIZE);
+
+ /**
+ Gets text from button.
+
+ @see setButtonText()
+ @ret Button text string
+ */
+ const wchar_t * getButtonText();
+
+ /**
+ Sets text to render at left, in center, or at right.
+
+ @see setButtonText()
+ @see getButtonText()
+ @see ButtonJustify
+ @param jus BUTTONJUSTIFY_LEFT, left justified; BUTTONJUSTIFY_CENTER, centered;
+ */
+// void setTextJustification(ButtonJustify jus);
+ void setTextAlign(TextAlign align);
+
+ TextAlign getTextAlign() { return alignment; }
+
+ /**
+ Enables and disables wantfocus for the button. When disabled, the button can
+ never receive focus.
+
+ @param want !0, enable focus; 0, disable focus;
+ */
+ void setWantFocus(int want) { iwantfocus = !!want; }
+
+ /**
+ Return the wantfocus
+ */
+ virtual int wantFocus() const { return iwantfocus; }
+
+ /**
+ Event is triggered when the mouse leaves the button's region.
+ Override this event to implement your own behavior.
+ */
+ virtual void onLeaveArea();
+ virtual void onEnterArea();
+
+ /**
+ Gets width of button, allowing for length of text plus button margin, if any.
+
+ @see getHeight()
+ @ret Button width (in pixels).
+ */
+ int getWidth(); // our preferred width and height (from bitmaps)
+
+ /**
+ Gets height of button, allowing for height of text plus button margin, if any.
+
+ @see getWidth()
+ @ret Button height (in pixels).
+ */
+ int getHeight();
+
+ /**
+ Event is triggered when focus is given to the button.
+ Override this event to implement your own behavior.
+
+ @see onKillFocus()
+ @ret 1
+ */
+ virtual int onGetFocus();
+
+ /**
+ Event is triggered when the button focus is lost.
+ Override this event to implement your own behavior.
+
+ @see onGetFocus()
+ @ret 1
+ */
+ virtual int onKillFocus();
+
+ /**
+ Event is triggered when a key is pressed and the button
+ has focus.
+
+ @ret 1, if you handle the event;
+ @param c The value of the key that was pressed.
+ */
+ virtual int onChar(unsigned int c);
+
+ /**
+ Saves new status and rerenders, if button enabled status changes.
+
+ @see getEnabled()
+ @see onEnable()
+ @param _enabled 0, disabled; !0 enabled;
+ */
+ void enableButton(int enabled); // can be pushed
+
+ /**
+ Tells parent to handle left button click.
+
+ @see onRightPush()
+ @param x Mouse click x-coordinate
+ @param y Mouse click y-coordinate
+ */
+ virtual void onLeftPush(int x, int y);
+
+ /**
+ Passes right mouse clicks to the parent.
+
+ @see onLeftPush()
+ @param x Mouse click x-coordinate
+ @param y Mouse click y-coordinate
+ */
+ virtual void onRightPush(int x, int y);
+
+ /**
+ Passes left double click to parent.
+
+ @see onRightDoubleClick()
+ @param x Mouse click x-coordinate
+ @param y Mouse click y-coordinate
+ */
+ virtual void onLeftDoubleClick(int x, int y);
+
+ /**
+ Passes right double click to parent
+
+ @see onLeftDoubleClick()
+ @param x Mouse click x-coordinate
+ @param y Mouse click y-coordinate
+ */
+ virtual void onRightDoubleClick(int x, int y);
+
+ /**
+ Event is triggered when the button will be resized.
+ Override this event to implement your own behavior.
+
+ The default behavior is to cause a repaint.
+
+ @ret 1
+ */
+ virtual int onResize();
+
+ /**
+ Sets the region pointed at after each mouse move.
+ If the region has changed, it invalidate the region
+ so that it will be updated on the screen.
+
+ @ret Status from parent class
+ @param x New x-coordinate of mouse cursor
+ @param y New y-coordinate of mouse cursor
+ */
+ virtual int onMouseMove(int x, int y); // need to catch region changes
+
+ /**
+ Event is triggered when the button is enabled or disabled.
+ Override this event to implement your own behavior.
+
+ @see getEnabled()
+ @ret 1
+ @param is The enable state (nonzero is enabled).
+ */
+ virtual int onEnable(int is);
+
+ /**
+ Returns the value of the enabled flag.
+
+ @see enableButton()
+ @see onEnable()
+ @ret enabled
+ */
+ virtual int getEnabled() const;
+
+ /**
+ Get the preferences for this button.
+ This will enable you to read the suggested width and height
+ for the button.
+
+ @ret Width or height of the normal bitmap, as requested, or a property from the parent class.
+ @param what SUGGESTED_W, will return the width; SUGGESTED_H, will return the height;
+ */
+ virtual int getPreferences(int what);
+
+ /**
+ Get the button state. This is the state caused by user interaction.
+
+ @ret !0, pushed; 0, not pushed;
+ */
+ virtual int userDown() { return userdown; }
+
+ /**
+
+ */
+ virtual int wantClicks() { return getEnabled(); }
+
+ /**
+ Set the bitmap to use when the button will be "checked".
+ This enables you to have checked buttons and menu items.
+
+ @see setChecked()
+ @see getChecked()
+ @param checkbm The name of the bitmap to use.
+ */
+ void setCheckBitmap(const wchar_t *checkbm);
+
+ /**
+ Set the checked state of the button.
+
+ @param c <0, not checked; 0, none, >0 checked;
+ */
+ void setChecked(int c) { checked=c; }; // <0=nocheck, 0=none, >0=checked
+
+ /**
+ Get the checked state of the button.
+
+ @ret <0, not checked; 0, none; >0 checked;
+ */
+ int getChecked() const { return checked; }
+
+ /**
+ Triggers rerendering in the opposite
+ highlight state if the hilighting flag is changed.
+
+ @see getHilite()
+ @param h
+ */
+ void setHilite(int h);
+
+ /**
+
+
+ @see setHilite()
+ @ret Is either highlighting flag set?
+ */
+ int getHilite();
+
+ /**
+ Simulate a button push. You can use this method to simulate
+ menu pushing also.
+
+ @see getPushed()
+ @param p A nonzero value will simulate a push.
+ */
+ void setPushed(int p); // used by menus to simulate pushing
+
+ /**
+ Get the pushed state of a button.
+
+ @see setPushed()
+ @ret 0, not pushed; !0, pushed;
+ */
+ int getPushed() const; // used by menus to simulate pushing
+
+ /**
+ Sets the auto dim state. Autodim will dim the normal
+ bitmap if no hilite bitmap is provided.
+
+ @param ad !0, autodim on; 0, autodim off;
+ */
+ void setAutoDim(int ad) { autodim=!!ad; } // nonzero makes it dim if there's no hilite bitmap
+
+ /**
+ Get the autodim state.
+
+ @see setAutoDim()
+ @ret 0, autodim off; !0 autodim on;
+ */
+ int getAutoDim() const { return autodim; } // nonzero makes it dim if there's no hilite bitmap
+
+ /**
+ Set the active state of the button.
+
+ @see getActivatedButton()
+ @see setActivatedNoCallback()
+ @param a !0, activate the button; 0, deactivate the button;
+ */
+ virtual void setActivatedButton(int a);
+
+ /**
+ Set the active state of the button, without generating a callback.
+ This means that the onActivated event will not fire for this button.
+
+ @see getActivatedButton()
+ @see setActivatedButton()
+ @param a !0, activate the button; 0, deactivate the button;
+ */
+ virtual void setActivatedNoCallback(int a);
+
+ /**
+ Get the active state of the button.
+
+ @see setActivatedButton()
+ @ret activated !0, active; 0, inactive;
+ */
+ virtual int getActivatedButton();
+
+ /**
+ Render borders around the button?
+
+ @param b !0, borders; 0, no borders;
+ */
+ void setBorders(int b);
+
+ /**
+ Sets the border style for the button. This
+ has no effect if no borders are being drawn.
+
+ "button_normal" A normal button.
+ "osbutton_normal" A normal OS button (if in Windows, will show a std win32 button).
+ "osbutton_close" An OS close button.
+ "osbutton_minimize" An OS minimize button.
+ "osbutton_maximize" An OS maximize button.
+
+ @see getBorderStyle()
+ @param style The style of button you want.
+ */
+ void setBorderStyle(const wchar_t *style);
+
+ /**
+ Get the border style of the button (if there is one).
+ If no border is drawn, this method always returns NULL.
+
+ @see setBorderStyle()
+ @ret The border style.
+ */
+ const wchar_t *getBorderStyle();
+
+ /**
+ Set the inactive alpha blending value. This is the alpha blending
+ value that will be used for blending when the button does NOT have focus.
+
+ @param a The alpha value, range is from 0 (fully transparent) to 255 (fully opaque).
+ */
+ void setInactiveAlpha(int a);
+
+ /**
+ Set the active alpha blending value. This is the alpha blending value
+ that will be used for blending when the button HAS focus.
+
+ @param a The alpha value, range is from 0 (fully transparent) to 255 (fully opaque).
+ */
+ void setActiveAlpha(int a);
+
+ /**
+ Sets the colors for various states of our button. This is
+ done via element id's which are in the skin xml or registered
+ as seperate xml.
+
+ @param text Normal text color (window has focus but button is not active).
+ @param hilite Hilited text color (button has focus).
+ @param dimmed Dimmed text color (parent window doesn't even have focus).
+ */
+ void setColors(const wchar_t *text=L"studio.button.text", const wchar_t *hilite=L"studio.button.hiliteText", const wchar_t *dimmed=L"studio.button.dimmedText");
+
+ /**
+ Deletes the regions and resets them to NULL.
+
+ @see reloadResources()
+ */
+ virtual void freeResources();
+
+ /**
+ Reinitializes regions for which there are bitmaps available.
+
+ @see freeResources()
+ */
+ virtual void reloadResources();
+
+ /**
+ Event is triggered when the is being activated.
+ Override this event to implement your own behavior.
+
+ @see setActivatedButton()
+ @ret 1
+ @param active The button's state (nonzero is active).
+ */
+ virtual int onActivateButton(int active);
+
+ /**
+ Returns the current region of the button.
+
+ @see api_region
+ @ret The region of the button.
+ */
+ virtual api_region *getRegion();
+
+ /**
+ Set the modal return. This is what will be returned
+ when the window is closed and the window is set to modal.
+
+ @param r The return code you wish to set.
+ */
+ virtual void setModalRetCode(int r);
+
+ /**
+ Get the modal return code for the window.
+
+ @ret The modal return code.
+ */
+ virtual int getModalRetCode() const;
+
+ /**
+ Event is triggered when the button is about to be initialized.
+ Override this event to implement your own behavior.
+
+ @ret 1
+ */
+ virtual int onInit();
+ virtual int onDeferredCallback(intptr_t p1, intptr_t p2);
+
+ virtual void setTextColor(const wchar_t *text);
+ virtual void setTextHoverColor(const wchar_t *text);
+ virtual void setTextDimmedColor(const wchar_t *text);
+
+ virtual void checkState(POINT *pt=NULL);
+ virtual void onCancelCapture();
+
+private:
+ AutoSkinBitmap normalbmp, pushedbmp, hilitebmp, checkbmp, rightbmp, activatedbmp;
+ SkinBitmap *base_texture;
+ RegionI *normalrgn, *pushedrgn, *hirgn, *currgn, *activatedrgn;
+ int textsize;
+ TextAlign alignment;
+ SkinColor color_text, color_hilite, color_dimmed;
+ int retcode;
+
+ StringW normalBmpStr, pushedBmpStr, hilitedBmpStr, activatedBmpStr;
+
+ int folderstyle;
+ int autodim;
+ int userhilite;
+ int userdown;
+ int activated;
+ int enabled;
+ int borders;
+ const wchar_t *borderstyle;
+ int dsoNormal, dsoPushed, dsoDisabled;
+
+ int iwantfocus;
+ int center_bitmap;
+ int use_base_texture;
+
+ int checked;
+ int xShift, yShift, tile_base_texture;
+
+ int inactivealpha, activealpha;
+ StringW colorgroup;
+ int forcedown;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/clickwnd.cpp b/Src/Wasabi/api/wnd/wndclass/clickwnd.cpp
new file mode 100644
index 00000000..054915a2
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/clickwnd.cpp
@@ -0,0 +1,319 @@
+#include "precomp.h"
+#include <api/wnd/api_wnd.h>
+
+#include "clickwnd.h"
+#include <api/wnd/notifmsg.h>
+#include <api/wnd/wndclass/guiobjwnd.h>
+
+
+enum
+{
+ CLICKWND_LBUTTONDOWN = 0,
+ CLICKWND_LBUTTONUP,
+ CLICKWND_RBUTTONDOWN,
+ CLICKWND_RBUTTONUP,
+};
+
+ClickWnd::ClickWnd()
+{
+ handleRight = TRUE;
+ button = -1;
+ mousedown = 0;
+ mcaptured = 0;
+ hilite = 0;
+ down = 0;
+ areacheck = 0;
+}
+
+ClickWnd::~ClickWnd()
+{
+ BaseWnd::hintDestroying(); // so basewnd doesn't call onCancelCapture
+ if (getCapture()) endCapture();
+}
+
+void ClickWnd::setHandleRightClick(int tf)
+{
+ handleRight=tf;
+}
+
+int ClickWnd::getHandleRightClick()
+{
+ return handleRight;
+}
+
+int ClickWnd::onLeftButtonDown(int x, int y)
+{
+ notifyParent(ChildNotify::CLICKWND_LEFTDOWN, x, y);
+ CLICKWND_PARENT::onLeftButtonDown(x, y);
+ abortTip();
+#ifdef _WIN32
+ ifc_window *dp = getDesktopParent();
+ if (dp != NULL)
+ {
+ if (dp->wantActivation())
+ {
+ SetActiveWindow(getRootParent()->gethWnd());
+ SetFocus(getRootParent()->gethWnd());
+ }
+ else
+ {
+ HWND w = dp->gethWnd();
+ HWND owner = GetWindow(w, GW_OWNER);
+ if (owner != NULL) {
+ SetActiveWindow(owner);
+ SetFocus(owner);
+ }
+ }
+ }
+ else
+ {
+ SetActiveWindow(getRootParent()->gethWnd());
+ }
+#else
+#warning port me or remove me
+#endif
+ if (ptInRegion(x, y))
+ return onButtonDown(CLICKWND_LBUTTONDOWN, x, y);
+ else
+ return 1;
+}
+
+int ClickWnd::onRightButtonDown(int x, int y)
+{
+ notifyParent(ChildNotify::CLICKWND_RIGHTDOWN, x, y);
+ CLICKWND_PARENT::onRightButtonDown(x, y);
+ abortTip();
+ if (!handleRight) return 1;
+ if (ptInRegion(x, y))
+ return onButtonDown(CLICKWND_RBUTTONDOWN, x, y);
+ else
+ return 1;
+}
+
+int ClickWnd::onLeftButtonUp(int x, int y)
+{
+ notifyParent(ChildNotify::CLICKWND_LEFTUP, x, y);
+ CLICKWND_PARENT::onLeftButtonUp(x, y);
+//jf
+// if (ptInRegion())
+ return onButtonUp(CLICKWND_LBUTTONUP, x, y);
+// else
+// return 1;
+}
+
+int ClickWnd::onRightButtonUp(int x, int y)
+{
+ notifyParent(ChildNotify::CLICKWND_RIGHTUP, x, y);
+ CLICKWND_PARENT::onRightButtonUp(x, y);
+ //jf
+ //if (ptInRegion())
+ if (!handleRight) {
+ onRightPush(x, y);
+ return 1;
+ }
+ return onButtonUp(CLICKWND_RBUTTONUP, x, y);
+// else
+// return 1;
+}
+
+int ClickWnd::onMouseMove(int x, int y)
+{
+ POINT pos, rpos={x,y};
+ int mouseover;
+
+ CLICKWND_PARENT::onMouseMove(x, y);
+
+ pos=rpos;
+ clientToScreen(&pos);
+
+ int lasthilite = hilite;
+
+ mouseover = (WASABI_API_WND->rootWndFromPoint(&pos) == static_cast<ifc_window *>(this) && ptInRegion(x, y));
+ if (!mouseover && (!mousedown
+#ifdef _WIN32
+ || !Std::keyDown(button?MK_RBUTTON:MK_LBUTTON)
+#else
+#warning port me
+#endif
+ )) {
+ if (mcaptured || getCapture()) {
+ endCapture();
+ mcaptured = 0;
+ }
+ mousedown = 0;
+ down = 0;
+ if (wantClickWndAutoInvalidate()) invalidate();
+ if (hilite) _onLeaveArea();
+ hilite = 0;
+ return 1;
+ } else if (!mouseover && hilite) {
+ hilite = 0;
+ _onLeaveArea();
+ } else if (mouseover && !hilite) {
+ hilite = 1;
+ _onEnterArea();
+ }
+
+ if (!getCapture() && mouseover) { // capture to see when leave
+ _enterCapture();
+ }
+
+ int lastdown = down;
+ hilite = mouseover;
+#ifdef WASABI_COMPILE_WNDMGR
+ int m = getGuiObject() ? getGuiObject()->guiobject_getMover() : 0;
+#else
+ int m = 0;
+#endif
+ if (!m) {
+ down = userDown() || (mouseover && mousedown);
+ } else
+ down = userDown() || mousedown;
+
+ // FG> note to self now that i finally fixed this... :
+ // there is a potential bottleneck here, if for some reason this test is always true when moving the windows around like crazy.
+ if (down != lastdown || (hilite != lasthilite && !m)) {
+ if (wantClickWndAutoInvalidate()) invalidate();
+ }
+
+//invalidate();
+ return 1;
+}
+
+void ClickWnd::_enterCapture()
+{
+ //gee!! if (!hilite) _onEnterArea();
+ if (!getCapture()) beginCapture();
+ mcaptured = 1;
+}
+
+int ClickWnd::onButtonDown(int which, int x, int y)
+{
+ if (!wantClicks()) return 1;
+
+ if (!getCapture()) {
+ _enterCapture();
+ }
+ mousedown = 1;
+ down = 1;
+ button = -1;
+ if (which == CLICKWND_LBUTTONDOWN) button = 0;
+ else if (which == CLICKWND_RBUTTONDOWN) button = 1;
+ if (wantClickWndAutoInvalidate()) invalidate();
+
+ return 1;
+}
+
+int ClickWnd::onButtonUp(int which, int x, int y)
+{
+ // make sure same button
+ if (button == 0 && which == CLICKWND_RBUTTONUP) return 1;
+ if (button == 1 && which == CLICKWND_LBUTTONUP) return 1;
+
+ if (!down) {
+ if (mcaptured) {
+ endCapture();
+ mcaptured = 0;
+ }
+ if (hilite) _onLeaveArea();
+ hilite = 0;
+ mousedown = 0;
+ return 1;
+ }
+
+ POINT pos={x,y};
+ clientToScreen(&pos);
+
+ int mouseover = (WASABI_API_WND->rootWndFromPoint(&pos) == (ifc_window *)this && ptInRegion(x, y));
+ if (!mouseover) {
+ if (mcaptured) {
+ endCapture();
+ mcaptured = 0;
+ }
+ if (hilite) _onLeaveArea();
+ hilite = 0;
+ }
+
+ // it was down, process the event
+ int a = down;
+ down = 0;
+ mousedown = 0;
+ if (wantClickWndAutoInvalidate()) invalidate();
+
+ if (a) {
+ if (button == 0) onLeftPush(x, y);
+ else if (button == 1) onRightPush(x, y);
+ }
+
+ // we need to do this again (and get the new mouse pos) because onLeft/RightPush may have called a
+ // message loop and let the mouse leave without us being aware of it
+ Wasabi::Std::getMousePos(&x, &y);
+ pos.x = x;
+ pos.y = y;
+ screenToClient(&x, &y);
+ mouseover = (WASABI_API_WND->rootWndFromPoint(&pos) == (ifc_window *)this && ptInRegion(x, y));
+ if (!mouseover && hilite) _onLeaveArea();
+ else if (mouseover && !hilite) _onEnterArea();
+ hilite = mouseover;
+
+ return 1;
+}
+
+void ClickWnd::onSetVisible( int show )
+{
+ CLICKWND_PARENT::onSetVisible( show );
+ if ( !show )
+ {
+ if ( getCapture() )
+ {
+ mcaptured = 0;
+ endCapture();
+ }
+ down = 0;
+ mousedown = 0;
+
+ if ( hilite )
+ _onLeaveArea();
+
+ hilite = 0;
+ }
+}
+
+void ClickWnd::_onEnterArea()
+{
+ if (areacheck == 0) {
+ areacheck++;
+ onEnterArea();
+ } else
+ DebugString("onEnterArea check failed %08X \n", this);
+}
+
+void ClickWnd::_onLeaveArea()
+{
+ if (areacheck == 1) {
+ areacheck--;
+ onLeaveArea();
+ } else
+ DebugString("onLeaveArea check failed %08X\n", this);
+}
+
+void ClickWnd::onEnterArea()
+{
+// DebugString("onEnterArea %08X\n", this);
+}
+
+void ClickWnd::onLeaveArea()
+{
+// DebugString("onLeaveArea %08X\n", this);
+}
+
+void ClickWnd::onCancelCapture()
+{
+ CLICKWND_PARENT::onCancelCapture();
+ mcaptured=0;
+ down = 0;
+ mousedown = 0;
+ if (hilite) _onLeaveArea();
+ hilite = 0;
+}
+
diff --git a/Src/Wasabi/api/wnd/wndclass/clickwnd.h b/Src/Wasabi/api/wnd/wndclass/clickwnd.h
new file mode 100644
index 00000000..101e8445
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/clickwnd.h
@@ -0,0 +1,74 @@
+#ifndef _CLICKWND_H
+#define _CLICKWND_H
+
+// this class defines clicking behavior, i.e. detecting mouse downs and ups
+// and doing captures to determine clicks
+
+#include <bfc/common.h>
+// benski> CUT: #include <api/wnd/wndclass/backbufferwnd.h>
+#include <api/wnd/wndclass/abstractwndhold.h>
+
+#ifdef WASABI_COMPILE_SKIN
+#define CLICKWND_PARENT AbstractWndHolder
+#else
+#define CLICKWND_PARENT ServiceWndHolder
+#endif
+// benski> CUT: #define CLICKWND_PARENT BackBufferWnd
+
+class NOVTABLE ClickWnd : public CLICKWND_PARENT {
+
+public:
+ ClickWnd();
+ virtual ~ClickWnd();
+
+ void setHandleRightClick(int tf);
+ int getHandleRightClick();
+
+ // override these to get clicks!
+ virtual void onLeftPush(int x, int y) {}
+ virtual void onRightPush(int x, int y) {}
+ virtual void onLeftDoubleClick(int x, int y) {}
+ virtual void onRightDoubleClick(int x, int y) {}
+
+ virtual void onEnterArea();
+ virtual void onLeaveArea();
+
+ virtual void onSetVisible(int show);
+ virtual void onCancelCapture();
+ virtual int isInClick() { return mousedown; }
+
+protected:
+ virtual int onLeftButtonDown(int x, int y);
+ virtual int onRightButtonDown(int x, int y);
+ virtual int onLeftButtonUp(int x, int y);
+ virtual int onRightButtonUp(int x, int y);
+ virtual int onMouseMove(int x, int y);
+
+ // override this and return 0 to ignore clicks
+ virtual int wantClicks() { return 1; }
+ // override this and return 1 to force down-ness
+ virtual int userDown() { return 0; }
+
+ virtual int getHilite() { return hilite; } // mouse is over, period
+ virtual int getDown() { return down; } // mouse is over and pushing down
+
+ int onButtonDown(int which, int x, int y);
+ int onButtonUp(int which, int x, int y);
+ void _enterCapture();
+
+ virtual int wantClickWndAutoInvalidate() { return 1; }
+
+private:
+ void _onEnterArea();
+ void _onLeaveArea();
+
+ int button; // 0 == left, 1 == right, which button was pushed
+ int handleRight:1;
+ int mousedown:1;
+ int mcaptured:1; // we are capturing the mouse
+ int hilite:1; // mouse is over but not down
+ int down:1;
+ int areacheck;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/ddrawwnd.cpp b/Src/Wasabi/api/wnd/wndclass/ddrawwnd.cpp
new file mode 100644
index 00000000..d095da03
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/ddrawwnd.cpp
@@ -0,0 +1,219 @@
+#include "precomp.h"
+#include <process.h>
+
+#include "ddrawwnd.h"
+#include "../bfc/canvas.h"
+#include "../bfc/region.h"
+
+DDrawWnd::DDrawWnd() {
+ m_lpDD = NULL;
+ lpClipper = NULL;
+ m_lpRenderSurf = NULL;
+ m_lpPrimSurf = NULL;
+}
+
+DDrawWnd::~DDrawWnd() {
+ deleteFrameBuffer(NULL);
+}
+
+void DDrawWnd::deleteFrameBuffer(Canvas *canvas) {
+ if (m_lpRenderSurf) m_lpRenderSurf->Release();
+ if (m_lpPrimSurf) m_lpPrimSurf->Release();
+ if (lpClipper) lpClipper->Release();
+ if (m_lpDD) m_lpDD->Release();
+ m_lpRenderSurf = NULL;
+ m_lpPrimSurf = NULL;
+ m_lpDD = NULL;
+ lpClipper = NULL;
+ ddlist.removeItem(this);
+}
+
+int DDrawWnd::onInit() {
+ DDRAWWND_PARENT::onInit();
+ if (!allow_dd) return 1;
+ return 1;
+}
+
+Canvas *DDrawWnd::createFrameBuffer(int _w, int _h) {
+
+ if (!allow_dd) return DDRAWWND_PARENT::createFrameBuffer(_w, _h);
+
+ if (virtualCanvas && !m_lpPrimSurf)
+ DDRAWWND_PARENT::deleteFrameBuffer(virtualCanvas);
+
+ deleteFrameBuffer(NULL);
+
+ int resize_h = 8;
+ int resize_w = 8;
+
+ w = _w;
+ h = _h;
+
+ if (DirectDrawCreate(NULL,&m_lpDD,NULL) != DD_OK) {
+ m_lpDD=NULL;
+ MessageBox(gethWnd(),"Error creating ddraw object","DDraw",0);
+ return NULL;
+ }
+
+ int dbl=0;
+
+ m_lpDD->SetCooperativeLevel(gethWnd(), DDSCL_NORMAL);
+ resize_w=(((w>>dbl)+3)&~3);
+// g_noshoww=resize_w-(w>>dbl);
+ resize_h=h>>dbl;
+
+ DDSURFACEDESC DDsd={sizeof(DDsd),};
+
+ DDsd.dwFlags = DDSD_CAPS;
+ DDsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+ if (m_lpDD->CreateSurface(&DDsd, &m_lpPrimSurf, NULL) != DD_OK) {
+ m_lpPrimSurf=0;
+ return NULL;
+ }
+
+ if (m_lpDD->CreateClipper(0, &lpClipper, NULL) != DD_OK ) {
+ m_lpPrimSurf->Release();
+ m_lpPrimSurf=0;
+ return NULL;
+ }
+
+ lpClipper->SetHWnd(0, gethWnd());
+ m_lpPrimSurf->SetClipper(lpClipper);
+
+ DDsd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_PITCH|DDSD_PIXELFORMAT;
+ DDsd.dwWidth=resize_w;
+ DDsd.dwHeight=resize_h;
+ DDsd.lPitch=resize_w*sizeof(int);
+ DDsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY;
+ DDsd.ddpfPixelFormat.dwSize = sizeof(DDsd.ddpfPixelFormat);
+ DDsd.ddpfPixelFormat.dwFlags=DDPF_RGB;
+ DDsd.ddpfPixelFormat.dwRGBBitCount = 32;
+ DDsd.ddpfPixelFormat.dwRBitMask=0xff0000;
+ DDsd.ddpfPixelFormat.dwGBitMask=0x00ff00;
+ DDsd.ddpfPixelFormat.dwBBitMask=0x0000ff;
+ if (m_lpDD->CreateSurface(&DDsd, &m_lpRenderSurf, NULL) != DD_OK) {
+ m_lpRenderSurf->Release();
+ m_lpPrimSurf->Release();
+ lpClipper->Release();
+ m_lpRenderSurf=0;
+ m_lpPrimSurf=0;
+ lpClipper=0;
+ return NULL;
+ }
+ fb_canvas = new DDSurfaceCanvas(m_lpRenderSurf, w, h);
+
+ ddlist.addItem(this);
+
+ if (!thread)
+ startThread();
+
+ return fb_canvas;
+}
+
+int DDrawWnd::virtualBeforePaint(api_region *r) {
+ if (!allow_dd) return DDRAWWND_PARENT::virtualBeforePaint(r);
+ EnterCriticalSection(&DDrawWnd::cs);
+ fb_canvas->enter();
+ return 1;
+}
+
+int DDrawWnd::virtualAfterPaint(api_region *r) {
+ if (!allow_dd) return DDRAWWND_PARENT::virtualAfterPaint(r);
+ fb_canvas->exit();
+ LeaveCriticalSection(&DDrawWnd::cs);
+ return 1;
+}
+
+void DDrawWnd::virtualCanvasCommit(Canvas *canvas, RECT *internalrect, double ra) {
+ if (!allow_dd) { DDRAWWND_PARENT::commitFrameBuffer(canvas, internalrect, ra); return; }
+
+ internalrect->left = MAX(0, (int)internalrect->left);
+ internalrect->top = MAX(0, (int)internalrect->top);
+ internalrect->right = MAX(w, (int)internalrect->right);
+ internalrect->bottom = MAX(h, (int)internalrect->bottom);
+
+ RECT wr;
+ RECT screenrect = *internalrect;
+
+ getWindowRect(&wr);
+ screenrect.left += wr.left;
+ screenrect.top += wr.top;
+ screenrect.right += wr.left;
+ screenrect.bottom += wr.top;
+
+ if (ra == 1.0) {
+ if (m_lpPrimSurf->Blt(&screenrect,m_lpRenderSurf,internalrect,DDBLT_WAIT,NULL) == DDERR_SURFACELOST) {
+ m_lpPrimSurf->Restore();
+ }
+ } else {
+ RECT rcr=screenrect;
+ rcr.left = wr.left + (int)((double)internalrect->left*ra);
+ rcr.top = wr.top + (int)((double)internalrect->top*ra);
+ rcr.right = rcr.left + (int)((double)(internalrect->right-internalrect->left)*ra);
+ rcr.bottom = rcr.top + (int)((double)(internalrect->bottom-internalrect->top)*ra);
+
+ if (m_lpPrimSurf->Blt(&rcr,m_lpRenderSurf,internalrect,DDBLT_WAIT,NULL) == DDERR_SURFACELOST)
+ m_lpPrimSurf->Restore();
+ }
+}
+
+void DDrawWnd::startThread() {
+ DWORD id;
+ quitthread=0;
+ InitializeCriticalSection(&cs);
+ thread = (HANDLE)_beginthreadex(NULL,0,renderThread,0,0,(unsigned int *)&id);
+}
+
+void DDrawWnd::stopThread() {
+ quitthread = 1;
+}
+
+unsigned int WINAPI DDrawWnd::renderThread(void *) {
+ while (!quitthread) {
+ for (int i=0;i<ddlist.getNumItems();i++)
+ ddlist.enumItem(i)->flushPaint();
+ Sleep(MIN(MAX(sleep_val,1),100));
+ }
+ _endthreadex(0);
+ return 1;
+}
+
+void DDrawWnd::invalidate() {
+ if (!allow_dd) { DDRAWWND_PARENT::invalidate(); return; }
+ DDRAWWND_PARENT::deferedInvalidate();
+}
+
+void DDrawWnd::invalidateRect(RECT *r) {
+ if (!allow_dd) { DDRAWWND_PARENT::invalidateRect(r); return; }
+ DDRAWWND_PARENT::deferedInvalidateRect(r);
+}
+
+void DDrawWnd::invalidateRgn(api_region *rgn) {
+ if (!allow_dd) { DDRAWWND_PARENT::invalidateRgn(rgn); return; }
+ DDRAWWND_PARENT::deferedInvalidateRgn(rgn);
+}
+
+void DDrawWnd::validate() {
+ if (!allow_dd) { DDRAWWND_PARENT::validate(); return; }
+ DDRAWWND_PARENT::deferedValidate();
+}
+
+void DDrawWnd::validateRect(RECT *r) {
+ if (!allow_dd) { DDRAWWND_PARENT::validateRect(r); return; }
+ DDRAWWND_PARENT::deferedValidateRect(r);
+}
+
+void DDrawWnd::validateRgn(api_region *rgn) {
+ if (!allow_dd) { DDRAWWND_PARENT::validateRgn(rgn); return; }
+ DDRAWWND_PARENT::deferedValidateRgn(rgn);
+}
+
+
+CRITICAL_SECTION DDrawWnd::cs;
+HANDLE DDrawWnd::thread=NULL;
+int DDrawWnd::quitthread=0;
+PtrList<DDrawWnd> DDrawWnd::ddlist;
+int DDrawWnd::allow_dd = 1;
+int DDrawWnd::sleep_val = 10;
+
+
diff --git a/Src/Wasabi/api/wnd/wndclass/ddrawwnd.h b/Src/Wasabi/api/wnd/wndclass/ddrawwnd.h
new file mode 100644
index 00000000..3863131c
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/ddrawwnd.h
@@ -0,0 +1,60 @@
+#ifndef __DDRAWWND_H
+#define __DDRAWWND_H
+
+#include <ddraw.h>
+#include "../bfc/basewnd.h"
+
+class DDSurfaceCanvas;
+class DDrawWnd;
+class api_region;
+
+#define DDRAWWND_PARENT BaseWnd
+
+class NOVTABLE DDrawWnd : public DDRAWWND_PARENT {
+
+public:
+
+ DDrawWnd();
+ virtual ~DDrawWnd();
+
+ virtual int virtualBeforePaint(api_region *r);
+ virtual int virtualAfterPaint(api_region *r);
+
+ virtual void virtualCanvasCommit(Canvas *canvas, RECT *r, double ratio);
+
+ virtual Canvas *createFrameBuffer(int w, int h);
+ virtual void deleteFrameBuffer(Canvas *canvas);
+
+ virtual int onInit();
+
+ virtual void invalidate();
+ virtual void invalidateRect(RECT *r);
+ virtual void invalidateRgn(api_region *rgn);
+ virtual void validate();
+ virtual void validateRect(RECT *r);
+ virtual void validateRgn(api_region *rgn);
+
+private:
+
+ void initDDraw();
+ void startThread();
+ void stopThread();
+
+ LPDIRECTDRAW m_lpDD;
+ LPDIRECTDRAWSURFACE m_lpRenderSurf, m_lpPrimSurf;
+
+ DDSurfaceCanvas *fb_canvas;
+ int w, h;
+ LPDIRECTDRAWCLIPPER lpClipper;
+ static int allow_dd;
+ static int sleep_val;
+ static CRITICAL_SECTION cs;
+ static HANDLE thread;
+ static int quitthread;
+ static PtrList<DDrawWnd> ddlist;
+
+ static unsigned int WINAPI renderThread(void *);
+};
+
+#endif
+
diff --git a/Src/Wasabi/api/wnd/wndclass/editwnd.cpp b/Src/Wasabi/api/wnd/wndclass/editwnd.cpp
new file mode 100644
index 00000000..8bde39d8
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/editwnd.cpp
@@ -0,0 +1,1001 @@
+#include <precomp.h>
+#include "editwnd.h"
+
+#include <tataki/canvas/canvas.h>
+#include <api/wnd/notifmsg.h>
+
+#include <bfc/assert.h>
+
+#define ID_EDITCHILD 12
+
+enum { IDLETIMER = 8, DELETETIMER = 10 };
+#define IDLETIME 350 // comprimises suck ;)
+
+
+#if UTF8
+#ifdef WANT_UTF8_WARNINGS
+#pragma CHAT("mig", "all", "UTF8 is enabled in editwnd.cpp -- Things might be screwy till it's all debugged?")
+#endif
+# include <bfc/string/encodedstr.h>
+#endif
+
+#ifdef WIN32
+#include <commctrl.h>
+#endif
+
+
+#ifdef WIN32
+static LRESULT CALLBACK static_editWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ EditWnd *editwnd = (EditWnd *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
+ if (editwnd == NULL) return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+ return editwnd->editWndProc(hWnd, uMsg, wParam, lParam);
+}
+#endif
+
+EditWnd::EditWnd(wchar_t *buffer, int buflen)
+{
+ wantfocus = 1;
+ nextenterfaked = 0;
+ idleenabled = 1;
+ beforefirstresize = 1;
+ editWnd = NULL;
+ prevWndProc = NULL;
+ setBuffer(buffer, buflen);
+ maxlen = 0;
+ retcode = EDITWND_RETURN_NOTHING;
+ modal = 0;
+ autoenter = 0;
+ autoselect = 0;
+ outbuf = NULL;
+ // bordered = 0;
+ idletimelen = IDLETIME;
+ multiline = 0;
+ readonly = 0;
+ password = 0;
+ autohscroll = 1;
+ autovscroll = 1;
+ vscroll = 0;
+#ifdef WIN32
+ oldbrush = NULL;
+#endif
+#ifdef LINUX
+ selstart = selend = 0;
+ cursorpos = 0;
+ selectmode = 0;
+ viewstart = 0;
+#endif
+#ifdef WASABI_EDITWND_LISTCOLORS
+ if (WASABI_API_SKIN->skin_getColorElementRef(L"wasabi.list.text"))
+ textcolor = L"wasabi.list.text";
+ else
+ textcolor = L"wasabi.edit.text";
+ if (WASABI_API_SKIN->skin_getColorElementRef(L"wasabi.list.background"))
+ backgroundcolor = L"wasabi.list.background";
+ else
+ textcolor.setColor(WASABI_API_SKIN->skin_getBitmapColor(L"wasabi.list.background"));
+#else
+ backgroundcolor = "wasabi.edit.background";
+ textcolor = "wasabi.edit.text";
+#endif
+ selectioncolor = L"wasabi.edit.selection";
+ setVirtual(0);
+}
+
+EditWnd::~EditWnd()
+{
+ killTimer(IDLETIMER);
+#ifdef WIN32
+ if (oldbrush != NULL)
+ DeleteObject(oldbrush);
+ oldbrush = NULL;
+ if (editWnd != NULL)
+ {
+ SetWindowLong(editWnd, GWLP_USERDATA, (LONG_PTR)0);
+ SetWindowLongPtrW(editWnd, GWLP_WNDPROC, (LONG_PTR)prevWndProc);
+ DestroyWindow(editWnd);
+ }
+#endif
+ notifyParent(ChildNotify::RETURN_CODE, retcode);
+}
+
+int EditWnd::onInit()
+{
+ EDITWND_PARENT::onInit();
+
+#ifdef WIN32
+ RECT r = clientRect();
+
+ editWnd = CreateWindowW(L"EDIT", NULL,
+ WS_CHILD
+ | (autohscroll ? ES_AUTOHSCROLL : 0)
+ | (readonly ? ES_READONLY : 0)
+ | (multiline ? ES_MULTILINE : 0)
+ | (password ? ES_PASSWORD : 0)
+ | (autovscroll ? ES_AUTOVSCROLL : 0)
+ | (vscroll ? WS_VSCROLL : 0),
+ r.left, r.top, r.right - r.left, r.bottom - r.top,
+ gethWnd(), (HMENU)ID_EDITCHILD,
+ getOsModuleHandle(), NULL);
+ ASSERT(editWnd != NULL);
+
+ if ((maxlen != 0) && (outbuf != NULL))
+ {
+ setBuffer(outbuf, maxlen);
+ }
+
+ // stash a pointer to us
+ SetWindowLongPtrW(editWnd, GWLP_USERDATA, (LONG_PTR)this);
+ // subclass the edit control -- either by 8 or by 16
+
+ prevWndProc = (WNDPROC)SetWindowLongPtrW(editWnd, GWLP_WNDPROC, (LONG_PTR)static_editWndProc);
+
+
+ SendMessageW(editWnd, WM_SETFONT, (WPARAM)GetStockObject(ANSI_VAR_FONT), FALSE);
+ ShowWindow(editWnd, !getStartHidden() ? SW_NORMAL : SW_HIDE);
+#endif
+
+ return 1;
+}
+
+void EditWnd::onSetVisible(int show)
+{
+ EDITWND_PARENT::onSetVisible(show);
+ if (editWnd == NULL) return ;
+#ifdef WIN32
+ ShowWindow(editWnd, show ? SW_NORMAL : SW_HIDE);
+#endif
+}
+
+int EditWnd::onPaint(Canvas *canvas)
+{
+ // if (!bordered) return EDITWND_PARENT::onPaint(canvas);
+
+ PaintCanvas paintcanvas;
+ if (canvas == NULL)
+ {
+ if (!paintcanvas.beginPaint(this)) return 0;
+ canvas = &paintcanvas;
+ }
+ EDITWND_PARENT::onPaint(canvas);
+
+ RECT r;
+ getClientRect(&r);
+ canvas->fillRect(&r, backgroundcolor); //SKIN
+
+#ifdef LINUX
+ char *str = STRDUP((const char *)inbuf + viewstart);
+ canvas->setTextColor(textcolor);
+ canvas->setTextSize(r.bottom - r.top);
+ canvas->setTextOpaque(FALSE);
+ char save;
+ if (selstart != selend)
+ {
+ RECT selrect = r;
+ int start = MAX(MIN(selstart, selend) - viewstart, 0);
+ int end = MAX(MAX(selstart, selend) - viewstart, 0);
+
+ save = str[ start ];
+ str[start] = '\0';
+ selrect.left = r.left + canvas->getTextWidth(str);
+ str[start] = save;
+
+ save = str[ end ];
+ str[end] = '\0';
+ selrect.right = r.left + canvas->getTextWidth(str);
+ str[end] = save;
+
+ canvas->fillRect(&selrect, selectioncolor);
+ }
+
+ save = str[cursorpos - viewstart];
+ str[cursorpos - viewstart] = '\0';
+ RECT cursor = r;
+ cursor.left = cursor.right = r.left + canvas->getTextWidth(str);
+ str[cursorpos - viewstart] = save;
+ canvas->drawRect(&cursor, TRUE, 0xffffff);
+
+ canvas->textOut(r.left, r.top, r.right - r.left, r.bottom - r.top, str);
+
+ FREE(str);
+#endif
+
+ return 1;
+}
+
+int EditWnd::onResize()
+{
+ EDITWND_PARENT::onResize();
+#ifdef WIN32
+ RECT r = clientRect();
+ if (1 /*bordered*/)
+ {
+ r.top++;
+ r.bottom--;
+ r.left++;
+ r.right--;
+ }
+ MoveWindow(editWnd, r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE);
+
+ if (beforefirstresize)
+ {
+ ShowWindow(editWnd, SW_NORMAL); beforefirstresize = 0;
+ if (modal)
+ {
+ SetFocus(editWnd);
+ if (getAutoSelect())
+ SendMessageW(editWnd, EM_SETSEL, 0, -1);
+ }
+ }
+#endif
+
+ return TRUE;
+}
+
+#ifdef WIN32
+LRESULT EditWnd::wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_CTLCOLOREDIT:
+ {
+ HDC hdc = (HDC)wParam;
+ SetTextColor(hdc, textcolor);
+ SetBkColor(hdc, backgroundcolor);
+ if (oldbrush != NULL)
+ {
+ DeleteObject(oldbrush);
+ oldbrush = NULL;
+ }
+ oldbrush = CreateSolidBrush(backgroundcolor);
+ return (LRESULT)oldbrush;
+ }
+
+ case WM_MOUSEACTIVATE:
+ WASABI_API_WND->popupexit_check(this);
+ break;
+
+ case WM_COMMAND:
+ {
+ switch (HIWORD(wParam))
+ {
+ case EN_CHANGE:
+ {
+ if (maxlen > 0)
+ {
+ GetWindowTextW(editWnd, outbuf, maxlen);
+ onEditUpdate();
+ }
+ }
+ break;
+ case EN_SETFOCUS:
+ if (getAutoSelect())
+ SendMessageW(editWnd, EM_SETSEL, (WPARAM)0, (LPARAM) - 1);
+ break;
+ case EN_KILLFOCUS:
+ onLoseFocus();
+ break;
+ }
+ }
+ break;
+ }
+
+ return EDITWND_PARENT::wndProc(hWnd, uMsg, wParam, lParam);
+}
+#endif
+
+void EditWnd::setBuffer(wchar_t *buffer, int len)
+{
+#ifdef LINUX
+ if (buffer == NULL || len <= 1)
+ {
+ inbuf = "";
+ return ;
+ }
+#endif
+ if (buffer == NULL || len <= 1) return ;
+ ASSERT(len > 1);
+ ASSERT(len < 0x7ffe);
+ ASSERT((int)wcslen(buffer) <= len);
+
+#ifdef WIN32
+#define USE_INTERNAL_BUFFER 0
+
+#if USE_INTERNAL_BUFFER
+ buffer8.setSize(len + 1);
+ outbuf = buffer8.getMemory();
+ if (len)
+ {
+ STRNCPY(outbuf, buffer, len);
+ }
+ outbuf[len] = 0;
+#else
+ outbuf = buffer;
+#endif
+
+ if (editWnd != NULL)
+ {
+ SetWindowTextW(editWnd, buffer);
+
+ // This is going to be problematic. This is where utf8 sucks.
+ // Just how many characters CAN we save in our buffer, eh?
+ // (shrug) Oh well. Can't be helped. At most this many.
+ SendMessageW(editWnd, EM_LIMITTEXT, (WPARAM)len - 1, (LPARAM)0);
+ // hooray for halcyon7
+
+ /* if (getAutoSelect()) {
+ SetFocus(editWnd);
+ SendMessageW(editWnd, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
+ }*/
+ }
+
+ maxlen = len;
+#else
+ outbuf = buffer;
+ maxlen = len;
+ inbuf = buffer;
+ cursorpos = len;
+ invalidate();
+#endif
+}
+
+void EditWnd::selectAll()
+{
+#ifdef WIN32
+ PostMessage(editWnd, EM_SETSEL, 0, -1);
+#else
+ selstart = 0; selend = inbuf.len();
+#endif
+}
+
+void EditWnd::enter()
+{
+ onEnter();
+}
+
+void EditWnd::getBuffer(wchar_t *buf, int _len)
+{
+ if (_len > maxlen) _len = maxlen;
+ // SendMessageW(editWnd, WM_GETTEXT, (WPARAM)_len, (LPARAM)buf);
+ WCSCPYN(buf, outbuf, _len);
+}
+
+void EditWnd::setModal(int _modal)
+{
+ modal = _modal;
+}
+
+void setBorder(int border)
+{
+ // bordered = border;
+}
+
+int EditWnd::isEditorKey(int vk)
+{
+ if (vk >= VK_F1) return 0;
+ if ((vk == VK_UP || vk == VK_DOWN) || ((Std::keyDown(VK_CONTROL) || Std::keyDown(VK_MENU)) && (vk == VK_LEFT || vk == VK_RIGHT)))
+ return 0;
+ if (vk == VK_RETURN && Std::keyDown(VK_CONTROL)) return 0;
+ if (vk == VK_CONTROL || vk == VK_MENU) return 0;
+ return 1;
+}
+
+LRESULT EditWnd::editWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_KEYDOWN:
+ if (!isEditorKey((int)wParam) && !onKeyDown((int)wParam))
+ {
+#ifdef WASABI_COMPILE_WND
+ WASABI_API_WND->forwardOnKeyDown(this, (int) wParam, (int)lParam);
+#endif
+
+ }
+ break;
+ case WM_KEYUP:
+ if (!isEditorKey((int)wParam) && !onKeyUp((int)wParam))
+ {
+#ifdef WASABI_COMPILE_WND
+ WASABI_API_WND->forwardOnKeyUp(this, (int) wParam, (int)lParam);
+#endif
+
+ }
+ break;
+ case WM_CHAR:
+ if (!(wParam == VK_RETURN && nextenterfaked && !autoenter))
+ {
+ notifyParent(ChildNotify::EDITWND_KEY_PRESSED, wParam);
+ onChar((TCHAR)wParam);
+ }
+ if (wParam == VK_RETURN)
+ {
+ if (!(nextenterfaked && !autoenter))
+ if (onEnter()) return 0;
+ nextenterfaked = 0;
+ return 0;
+ }
+ else if (wParam == VK_ESCAPE)
+ {
+ if (onAbort()) return 0;
+ }
+ else if (wParam == VK_TAB && multiline)
+ {
+ return 0;
+ }
+ break;
+ case WM_SETFOCUS:
+ onSetRootFocus(this);
+ // fall thru
+ case WM_KILLFOCUS:
+ invalidate();
+ break;
+ }
+#ifdef WIN32
+ return CallWindowProc(prevWndProc, hWnd, uMsg, wParam, lParam);
+#else
+ DebugString("portme -- EditWnd::editWndProc\n");
+ return 0;
+#endif
+}
+
+void EditWnd::timerCallback(int id)
+{
+ switch (id)
+ {
+ case IDLETIMER:
+ killTimer(IDLETIMER);
+ if (idleenabled) onIdleEditUpdate();
+ break;
+ case DELETETIMER:
+ killTimer(DELETETIMER);
+ delete this;
+ break;
+ default:
+ EDITWND_PARENT::timerCallback(id);
+ }
+}
+
+void EditWnd::onEditUpdate()
+{
+#ifdef LINUX
+ STRNCPY(outbuf, inbuf, maxlen);
+ outbuf[maxlen] = '\0';
+
+ RECT r;
+ getClientRect(&r);
+
+ SysCanvas sysc;
+ sysc.setTextSize(r.bottom - r.top);
+ sysc.getTextWidth(inbuf);
+
+ char *str = STRDUP(inbuf);
+
+ if (cursorpos < viewstart)
+ viewstart = cursorpos;
+
+ char save = str[cursorpos];
+ str[cursorpos] = '\0';
+ while (sysc.getTextWidth(str + viewstart) > r.right - r.left)
+ {
+ viewstart++;
+ }
+ str[cursorpos] = save;
+
+ invalidate();
+#endif
+ killTimer(IDLETIMER);
+ setTimer(IDLETIMER, idletimelen);
+ notifyParent(ChildNotify::EDITWND_DATA_MODIFIED);
+}
+
+void EditWnd::onIdleEditUpdate()
+{
+ notifyParent(ChildNotify::EDITWND_DATA_MODIFIED_ONIDLE);
+}
+
+int EditWnd::onEnter()
+{
+ notifyParent(ChildNotify::EDITWND_ENTER_PRESSED);
+ if (modal)
+ {
+ retcode = EDITWND_RETURN_OK;
+ delete this;
+ //CUT setTimer(DELETETIMER, 1);
+ return 1;
+ }
+ return 0;
+}
+
+int EditWnd::onAbort()
+{
+ notifyParent(ChildNotify::EDITWND_CANCEL_PRESSED);
+ if (modal)
+ {
+ retcode = EDITWND_RETURN_CANCEL;
+ delete this;
+ //CUT setTimer(DELETETIMER, 1);
+ return 1;
+ }
+ return 0;
+}
+
+int EditWnd::onLoseFocus()
+{ // fake an onEnter()
+#ifdef WIN32
+ if (autoenter)
+ {
+ nextenterfaked = 1;
+ PostMessage(editWnd, WM_CHAR, VK_RETURN, 0);
+ }
+#else
+ invalidate();
+ selstart = selend = 0;
+#endif
+ return 0;
+}
+
+void EditWnd::setAutoEnter(int a)
+{
+ autoenter = a;
+}
+
+void EditWnd::setAutoSelect(int a)
+{
+ autoselect = a;
+};
+
+void EditWnd::setIdleTimerLen(int ms)
+{
+ if (ms < 0) ms = 0;
+ idletimelen = ms;
+}
+
+int EditWnd::getTextLength()
+{ // TOTALLY NONPORTABLE AND TOTALLY DIRTY
+#ifdef WIN32
+ HFONT font = (HFONT)SendMessageW(editWnd, WM_GETFONT, 0, 0);
+
+ HDC sdc = GetDC(NULL);
+ HDC dc = CreateCompatibleDC(sdc);
+ ReleaseDC(NULL, sdc);
+
+ HFONT oldfont = (HFONT)SelectObject(dc, font);
+
+ SIZE s;
+ GetTextExtentPoint32W(dc, outbuf, wcslen(outbuf), &s);
+ SelectObject(dc, oldfont);
+ DeleteDC(dc);
+ return s.cx + SendMessageW(editWnd, EM_GETMARGINS, 0, 0)*2 + 2;
+#else
+ if (inbuf.isempty())
+ return 0;
+
+ RECT r;
+ getClientRect(&r);
+
+ SysCanvas sysc;
+ sysc.setTextSize(r.bottom - r.top);
+ return sysc.getTextWidth(inbuf);
+#endif
+}
+
+HWND EditWnd::getEditWnd()
+{
+ return editWnd;
+}
+
+#ifndef WIN32
+enum {
+ ES_MULTILINE,
+ ES_WANTRETURN,
+ ES_AUTOHSCROLL,
+ ES_AUTOVSCROLL,
+ WS_VSCROLL,
+};
+#endif
+
+void EditWnd::setMultiline(int ml)
+{
+ multiline = ml;
+ setStyle(ES_MULTILINE | ES_WANTRETURN, ml);
+}
+
+void EditWnd::setReadOnly(int ro)
+{
+ readonly = ro;
+ setStyle(ES_READONLY, ro);
+}
+
+void EditWnd::setPassword(int pw)
+{
+ password = pw;
+ setStyle(ES_PASSWORD, pw);
+}
+
+void EditWnd::setAutoHScroll(int hs)
+{
+ autohscroll = hs;
+ setStyle(ES_AUTOHSCROLL, hs);
+}
+
+void EditWnd::setAutoVScroll(int vs)
+{
+ autovscroll = vs;
+ setStyle(ES_AUTOVSCROLL, vs);
+}
+
+void EditWnd::setVScroll(int vs)
+{
+ vscroll = vs;
+ setStyle(WS_VSCROLL, vs);
+}
+
+void EditWnd::setStyle(LONG style, int set)
+{
+#ifdef WIN32
+ if (editWnd)
+ {
+ LONG s = GetWindowLong(editWnd, GWL_STYLE);
+ if (set) s |= style;
+ else s &= ~style;
+ SetWindowLong(editWnd, GWL_STYLE, s);
+ }
+#else
+ DebugString("portme -- EditWnd::setStyle\n");
+#endif
+}
+
+int EditWnd::onGetFocus()
+{
+ int r = EDITWND_PARENT::onGetFocus();
+#ifdef WIN32
+ if (editWnd != NULL)
+ SetFocus(editWnd);
+#endif
+ return r;
+}
+
+int EditWnd::wantFocus()
+{
+ return wantfocus;
+}
+
+int EditWnd::gotFocus()
+{
+ return (GetFocus() == editWnd);
+}
+
+void EditWnd::setBackgroundColor(COLORREF c)
+{
+ backgroundcolor.setColor(c);
+}
+
+void EditWnd::setTextColor(COLORREF c)
+{
+ textcolor.setColor(c);
+}
+
+void EditWnd::invalidate()
+{
+ EDITWND_PARENT::invalidate();
+ InvalidateRect(editWnd, NULL, TRUE);
+}
+
+#ifdef LINUX
+int EditWnd::textposFromCoord(int x, int y)
+{
+ RECT r;
+ getClientRect(&r);
+
+ SysCanvas canvas;
+
+ canvas.setTextColor(textcolor);
+ canvas.setTextSize(r.bottom - r.top);
+ canvas.setTextOpaque(FALSE);
+
+ x -= r.left;
+
+ int i;
+
+ char *str = STRDUP(inbuf);
+
+ if (x > canvas.getTextWidth(str + viewstart))
+ return inbuf.len();
+
+ for (i = viewstart + 1; str[i]; i++)
+ {
+ char save = str[i];
+ str[i] = '\0';
+ if (x < canvas.getTextWidth(str + viewstart))
+ {
+ str[i] = save;
+ break;
+ }
+ str[i] = save;
+ }
+
+ FREE(str);
+
+ return i - 1;
+}
+
+int EditWnd::onLeftButtonDown(int x, int y)
+{
+ EDITWND_PARENT::onLeftButtonDown(x, y);
+
+ // Add check for double/triple click...
+
+ cursorpos = textposFromCoord(x, y);
+ selstart = selend = cursorpos;
+
+ selectmode = 1;
+
+ return 1;
+}
+
+int EditWnd::onLeftButtonUp(int x, int y)
+{
+ EDITWND_PARENT::onLeftButtonUp(x, y);
+
+ selectmode = 0;
+
+ return 1;
+}
+
+int EditWnd::onMouseMove(int x, int y)
+{
+ EDITWND_PARENT::onMouseMove(x, y);
+
+ switch (selectmode)
+ {
+ case 0:
+ // Do nothing
+ break;
+ case 1:
+ selend = textposFromCoord(x, y);
+ cursorpos = selend;
+ onEditUpdate();
+ break;
+ default:
+ DebugString("selectmode %d not available\n", selectmode);
+ break;
+ }
+
+ return selectmode;
+}
+
+int EditWnd::onKeyDown(int key)
+{
+ EDITWND_PARENT::onKeyDown(key);
+
+ if (Std::keyDown(VK_CONTROL))
+ {
+ switch (key)
+ {
+ case 'a':
+ case 'A':
+ selectAll();
+ break;
+
+ default:
+ return 0;
+ }
+ }
+ else
+ {
+ switch (key)
+ {
+ case XK_Home:
+ if (Std::keyDown(VK_SHIFT))
+ {
+ if (selstart == selend)
+ {
+ selstart = selend = cursorpos;
+ }
+ selend = 0;
+ }
+ else
+ {
+ selstart = selend = 0;
+ }
+ cursorpos = 0;
+ break;
+
+ case XK_End:
+ if (Std::keyDown(VK_SHIFT))
+ {
+ if (selstart == selend)
+ {
+ selstart = selend = cursorpos;
+ }
+ selend = inbuf.len();
+ }
+ else
+ {
+ selstart = selend = 0;
+ }
+ cursorpos = inbuf.len();
+ break;
+
+ case XK_Right:
+ if (Std::keyDown(VK_SHIFT))
+ {
+ if (selstart == selend)
+ {
+ selstart = selend = cursorpos;
+ }
+ selend++;
+ if (selend > inbuf.len()) selend = inbuf.len();
+ }
+ else
+ {
+ selstart = selend = 0;
+ }
+ cursorpos++;
+ if (cursorpos > inbuf.len()) cursorpos = inbuf.len();
+ break;
+
+ case XK_Left:
+ if (Std::keyDown(VK_SHIFT))
+ {
+ if (selstart == selend)
+ {
+ selstart = selend = cursorpos;
+ }
+ selend--;
+ if (selend < 0) selend = 0;
+ }
+ else
+ {
+ selstart = selend = 0;
+ }
+ cursorpos--;
+ if (cursorpos < 0) cursorpos = 0;
+ break;
+
+ case XK_Escape:
+ onAbort();
+ break;
+
+ case XK_Return:
+ onEnter();
+ break;
+
+ case XK_Delete:
+ if (selstart != selend)
+ {
+ int start = MIN(selstart, selend);
+ int end = MAX(selstart, selend);
+
+ String add;
+
+ if (end < inbuf.len())
+ {
+ add = (const char *)inbuf + end;
+ }
+ else
+ {
+ add = "";
+ }
+
+ inbuf.trunc(start);
+ inbuf += add;
+
+ cursorpos = start;
+ selstart = selend = 0;
+
+ }
+ else
+ {
+ if (cursorpos >= 0)
+ {
+ if (cursorpos < inbuf.len() - 1)
+ {
+ String tmp = inbuf;
+ tmp.trunc(cursorpos);
+ inbuf = tmp + ((const char *)inbuf + cursorpos + 1);
+ }
+ else if (cursorpos == inbuf.len() - 1)
+ {
+ inbuf.trunc(cursorpos);
+ }
+ }
+ }
+ break;
+
+ case VK_BACK:
+ if (selstart != selend)
+ {
+ int start = MIN(selstart, selend);
+ int end = MAX(selstart, selend);
+
+ String add;
+
+ if (end < inbuf.len())
+ {
+ add = (const char *)inbuf + end;
+ }
+ else
+ {
+ add = "";
+ }
+
+ inbuf.trunc(start);
+ inbuf += add;
+
+ cursorpos = start;
+ selstart = selend = 0;
+ }
+ else
+ {
+ if (cursorpos > 0)
+ {
+ if (cursorpos >= inbuf.len())
+ {
+ inbuf.trunc(cursorpos - 1);
+ cursorpos--;
+ }
+ else
+ {
+ String tmp = inbuf;
+ tmp.trunc(cursorpos - 1);
+ inbuf = tmp + ((const char *)inbuf + cursorpos);
+ cursorpos--;
+ }
+ }
+ }
+ break;
+
+ default:
+ if (key < 0x20 || key > 0x7e)
+ return 0;
+
+ if (selstart != selend)
+ {
+ int start = MIN(selstart, selend);
+ int end = MAX(selstart, selend);
+
+ String add;
+
+ if (end < inbuf.len())
+ {
+ add = (const char *)inbuf + end;
+ }
+ else
+ {
+ add = "";
+ }
+
+ inbuf.trunc(start);
+ inbuf += add;
+
+ cursorpos = start;
+ selstart = selend = 0;
+ }
+
+ String tmp;
+
+ if (cursorpos >= inbuf.len())
+ {
+ tmp = "";
+ }
+ else
+ {
+ tmp = (const char *)inbuf + cursorpos;
+ }
+
+ inbuf.trunc(cursorpos);
+
+ inbuf += (char)key;
+ inbuf += tmp;
+
+ cursorpos++;
+ }
+ }
+
+ onEditUpdate();
+
+ return 1;
+}
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/editwnd.h b/Src/Wasabi/api/wnd/wndclass/editwnd.h
new file mode 100644
index 00000000..735debc2
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/editwnd.h
@@ -0,0 +1,134 @@
+//NONPORTABLE
+#ifndef _EDITWND_H
+#define _EDITWND_H
+
+#include <api/wnd/wndclass/guiobjwnd.h>
+#include <tataki/color/skinclr.h>
+#include <api/wnd/usermsg.h>
+#include <bfc/common.h>
+
+#define EDITWND_PARENT GuiObjectWnd
+class EditWnd : public EDITWND_PARENT {
+public:
+ EditWnd(wchar_t *buffer=NULL, int buflen=0);
+ virtual ~EditWnd();
+
+ virtual int onInit();
+ virtual int onPaint(Canvas *canvas);
+ virtual int onResize();
+#ifdef WIN32
+ virtual LRESULT wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+#endif
+
+ // mig: Made these virtual to allow to be accessed by
+ // EditWndString object in editwndstring.h
+ virtual void setBuffer(wchar_t *buffer, int len);
+ virtual void getBuffer(wchar_t *outbuf, int len);
+
+ virtual const wchar_t *getBufferPtr() { return outbuf; }
+ virtual int getBufferLength() { return maxlen; }
+ virtual void setBackgroundColor(ARGB32 c);
+ virtual void setTextColor(ARGB32 c);
+
+ void setModal(int modal); //if modal, deletes self on enter
+ void setAutoEnter(int a); //fake an onEnter event when lose focus
+ int getAutoEnter() { return autoenter; }
+ void setAutoSelect(int a); //true==grab the focus on init
+ void setIdleTimerLen(int ms); // how many ms keys are idle before send msg
+ virtual void onSetVisible(int show);
+ virtual int onGetFocus();
+ virtual int wantFocus();
+ virtual void setWantFocus(int w) { wantfocus = w; }
+ virtual void selectAll();
+ virtual void enter();
+ virtual void setIdleEnabled(int i) { idleenabled = i; }
+ virtual int getIdleEnabled() { return idleenabled; }
+
+ void setBorder(int border);
+ int getTextLength();
+
+ HWND getEditWnd();
+ virtual int handleRatio() { return 0; }
+ virtual int getAutoSelect() { return autoselect; }
+
+ void setMultiline(int ml);
+ void setReadOnly(int ro);
+ void setPassword(int pw);
+ void setAutoHScroll(int hs);
+ void setAutoVScroll(int vs);
+ void setVScroll(int vs);
+ int isEditorKey(int vk);
+ virtual void invalidate();
+
+ virtual int gotFocus();
+
+ // the wndproc for the edit box
+ virtual LRESULT editWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+protected:
+ virtual void timerCallback(int id);
+
+ // call down on these if you override them
+ virtual void onEditUpdate();
+ virtual void onIdleEditUpdate();
+ virtual int onEnter(); // user hit enter.. return 1 to close window
+ virtual int onAbort(); // user hit escape.. return 1 to close window
+ virtual int onLoseFocus(); // different from onKillFocus() from BaseWnd!
+
+ void setStyle(LONG style, int set);
+
+#ifdef LINUX
+ virtual int onLeftButtonDown( int x, int y );
+ virtual int onLeftButtonUp( int x, int y );
+ virtual int onMouseMove( int x, int y );
+ virtual int onKeyDown(int key);
+#endif
+
+private:
+#ifdef LINUX
+ int textposFromCoord( int x, int y );
+#endif
+
+ HWND editWnd;
+ WNDPROC prevWndProc;
+ int maxlen;
+ int retcode;
+ int idletimelen;
+ int modal;
+ int bordered;
+ int autoenter;
+ int beforefirstresize;
+ int autoselect;
+ int multiline;
+ int readonly;
+ int password;
+ int idleenabled;
+ int autohscroll,autovscroll,vscroll;
+ int nextenterfaked;
+ SkinColor backgroundcolor, textcolor, selectioncolor;
+#ifdef LINUX
+ int selstart, selend;
+ int cursorpos;
+ int selectmode;
+ int viewstart;
+#endif
+#ifdef WIN32
+ HBRUSH oldbrush;
+#endif
+
+ // Basically, we're redoing the functionality of EditWndString
+ // (the bigger version), so we'll probably erase EditWndString
+ // completely as an object.
+ MemBlock<wchar_t> buffer8;
+ wchar_t *outbuf;
+ int wantfocus;
+#ifdef LINUX
+ StringW inbuf;
+#endif
+};
+
+#define EDITWND_RETURN_NOTHING 0 // user didn't do nothing
+#define EDITWND_RETURN_OK 1 // user hit return
+#define EDITWND_RETURN_CANCEL 2 // user hit escape or something
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/editwndstring.cpp b/Src/Wasabi/api/wnd/wndclass/editwndstring.cpp
new file mode 100644
index 00000000..f296bda8
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/editwndstring.cpp
@@ -0,0 +1,17 @@
+#include <precomp.h>
+#include "editwndstring.h"
+
+// ===========================================================================
+//
+// NULLSOFT WASABI SDK MODULE & EXAMPLE CODE
+//
+// File: editwndstring.cpp
+//
+//!## Purpose: The EditWndString object both extends the EditWnd object to
+//!## simplify and streamline the use of an EditWnd in your wasabi
+//!## components. In addition, this module serves as a tutorial
+//!## to instruct wasabi developers on how to properly extend our
+//!## current objects to provide new functionality.
+//
+//
+
diff --git a/Src/Wasabi/api/wnd/wndclass/editwndstring.h b/Src/Wasabi/api/wnd/wndclass/editwndstring.h
new file mode 100644
index 00000000..843524bf
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/editwndstring.h
@@ -0,0 +1,24 @@
+#ifndef _EDITWNDSTRING_H
+#define _EDITWNDSTRING_H
+
+#include <api/wnd/wndclass/editwnd.h>
+#include <bfc/memblock.h>
+
+class EditWndString : public EditWnd
+{
+public:
+ void setBuffer(wchar_t *buffer, int len=0)
+ {
+ b.setSize(len+1);
+ wchar_t *bufmem=b.getMemory();
+ if(len)
+ wcsncpy(bufmem,buffer,len);
+ bufmem[len]=0;
+ EditWnd::setBuffer(bufmem,len);
+ }
+ const wchar_t *getBuffer() { return b.getMemory(); }
+private:
+ MemBlock<wchar_t> b;
+};
+
+#endif//_EDITWNDSTRING_H \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/wndclass/embeddedxui.cpp b/Src/Wasabi/api/wnd/wndclass/embeddedxui.cpp
new file mode 100644
index 00000000..8e47f29e
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/embeddedxui.cpp
@@ -0,0 +1,143 @@
+#include "precomp.h"
+#include "embeddedxui.h"
+
+EmbeddedXuiObject::EmbeddedXuiObject() {
+ embedded = NULL;
+ myxuihandle = newXuiHandle();
+ getScriptObject()->vcpu_setInterface(embeddedXuiGuid, (void *)static_cast<EmbeddedXuiObject *>(this));
+ getScriptObject()->vcpu_setClassName(L"ObjectEmbedded"); // this is the script class name
+ getScriptObject()->vcpu_setController(embeddedXuiController);
+}
+
+EmbeddedXuiObject::~EmbeddedXuiObject() {
+ paramlist.deleteAll();
+}
+
+void EmbeddedXuiObject::onNewContent() {
+ embeddedxui_onNewEmbeddedContent();
+}
+
+void EmbeddedXuiObject::embeddedxui_onNewEmbeddedContent() {
+ embedded = NULL;
+ const wchar_t *id = embeddedxui_getEmbeddedObjectId();
+ if (id != NULL && *id) {
+ GuiObject *myself = getGuiObject();
+ embedded = myself->guiobject_findObject(id);
+ if (embedded != NULL && embedded != myself) {
+ foreach(paramlist)
+ EmbeddedXuiObjectParam *p = paramlist.getfor();
+ embedded->guiobject_setXmlParam(p->param, p->value);
+ endfor;
+#ifdef WASABI_COMPILE_CONFIG
+ syncCfgAttrib();
+#endif
+ }
+ }
+}
+
+int EmbeddedXuiObject::onUnknownXuiParam(const wchar_t *xmlattributename, const wchar_t *value) {
+ int r = EMBEDDEDXUIOBJECT_PARENT::onUnknownXuiParam(xmlattributename, value);
+ paramlist.addItem(new EmbeddedXuiObjectParam(xmlattributename, value));
+ if (embedded)
+ r = embedded->guiobject_setXmlParam(xmlattributename, value);
+ return r;
+}
+
+int EmbeddedXuiObject::onInit()
+{
+ int r = EMBEDDEDXUIOBJECT_PARENT::onInit();
+ const wchar_t *id = embeddedxui_getContentId();
+ if (id != NULL && *id)
+ setContent(id);
+ return r;
+}
+
+#ifdef WASABI_COMPILE_CONFIG
+int EmbeddedXuiObject::onReloadConfig() {
+ int r = EMBEDDEDXUIOBJECT_PARENT::onReloadConfig();
+ syncCfgAttrib();
+ return r;
+}
+#endif
+
+#ifdef WASABI_COMPILE_CONFIG
+void EmbeddedXuiObject::syncCfgAttrib()
+{
+ if (embedded == NULL) return;
+ CfgItem *item = getGuiObject()->guiobject_getCfgItem();
+ const wchar_t *attrib = getGuiObject()->guiobject_getCfgAttrib();
+ if (item != embedded->guiobject_getCfgItem() ||
+ attrib != embedded->guiobject_getCfgAttrib()) {
+ embedded->guiobject_setCfgAttrib(item, attrib);
+ }
+}
+#endif
+
+// -----------------------------------------------------------------------
+// Script Object
+
+EmbeddedXuiScriptController _embeddedXuiController;
+EmbeddedXuiScriptController *embeddedXuiController = &_embeddedXuiController;
+
+// -- Functions table -------------------------------------
+function_descriptor_struct EmbeddedXuiScriptController::exportedFunction[] = {
+ {L"getEmbeddedObject", 0, (void*)EmbeddedXuiScriptController::EmbeddedXui_getEmbeddedObject},
+};
+
+ScriptObject *EmbeddedXuiScriptController::instantiate() {
+ EmbeddedXuiObject *ex = new EmbeddedXuiObject;
+ ASSERT(ex != NULL);
+ return ex->getScriptObject();
+}
+
+void EmbeddedXuiScriptController::destroy(ScriptObject *o) {
+ EmbeddedXuiObject *ex= static_cast<EmbeddedXuiObject *>(o->vcpu_getInterface(embeddedXuiGuid));
+ ASSERT(ex != NULL);
+ delete ex;
+}
+
+void *EmbeddedXuiScriptController::encapsulate(ScriptObject *o) {
+ return NULL; // no encapsulation for DropDownlist yet
+}
+
+void EmbeddedXuiScriptController::deencapsulate(void *o) {
+}
+
+int EmbeddedXuiScriptController::getNumFunctions() {
+ return sizeof(exportedFunction) / sizeof(function_descriptor_struct);
+}
+
+const function_descriptor_struct *EmbeddedXuiScriptController::getExportedFunctions() {
+ return exportedFunction;
+}
+
+
+scriptVar EmbeddedXuiScriptController::EmbeddedXui_getEmbeddedObject(SCRIPT_FUNCTION_PARAMS, ScriptObject *o) {
+ SCRIPT_FUNCTION_INIT
+ EmbeddedXuiObject *ex = static_cast<EmbeddedXuiObject*>(o->vcpu_getInterface(embeddedXuiGuid));
+ ScriptObject *_o = NULL;
+ if (ex) {
+ GuiObject *go = ex->embeddedxui_getEmbeddedObject();
+ if (go != NULL)
+ _o = go->guiobject_getScriptObject();
+ }
+ return MAKE_SCRIPT_OBJECT(_o);
+}
+
+ScriptObject *EmbeddedXuiScriptController::cast(ScriptObject *o, GUID g) {
+ EmbeddedXuiObject *exo = static_cast<EmbeddedXuiObject *>(o->vcpu_getInterface(embeddedXuiGuid));
+ if (!exo) return NULL;
+ GuiObject *go = exo->embeddedxui_getEmbeddedObject();
+ if (go != NULL) {
+ ScriptObject *eo = go->guiobject_getScriptObject();
+ if (eo != NULL) {
+ void *i = eo->vcpu_getInterface(g);
+ if (i != NULL)
+ return eo;
+ }
+ }
+ return NULL;
+}
+
+
+ScriptObjectController *EmbeddedXuiScriptController::getAncestorController() { return WASABI_API_MAKI->maki_getController(guiObjectGuid); } \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/wndclass/embeddedxui.h b/Src/Wasabi/api/wnd/wndclass/embeddedxui.h
new file mode 100644
index 00000000..38b187d5
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/embeddedxui.h
@@ -0,0 +1,88 @@
+#ifndef __EMBEDDEDXUIOBJECT_H
+#define __EMBEDDEDXUIOBJECT_H
+
+#include <wasabicfg.h>
+#include <api/script/api_maki.h>
+#include <api/wnd/wndclass/guiobjwnd.h>
+#include <api/script/scriptguid.h>
+#include <api/script/scriptobj.h>
+#include <api/script/objcontroller.h>
+
+#define EMBEDDEDXUIOBJECT_PARENT GuiObjectWnd
+
+
+class EmbeddedXuiObjectParam {
+ public:
+
+
+ EmbeddedXuiObjectParam(const wchar_t *p, const wchar_t *v) : param(p), value(v) {}
+
+ virtual ~EmbeddedXuiObjectParam() {}
+
+ StringW param;
+ StringW value;
+};
+
+
+class EmbeddedXuiObject : public EMBEDDEDXUIOBJECT_PARENT {
+ public:
+
+ EmbeddedXuiObject();
+
+
+ virtual ~EmbeddedXuiObject();
+
+ virtual void onNewContent();
+
+ virtual int onInit();
+
+
+ virtual void embeddedxui_onNewEmbeddedContent();
+ virtual const wchar_t *embeddedxui_getContentId() { return NULL; }
+ virtual const wchar_t *embeddedxui_getEmbeddedObjectId() { return NULL; }
+
+ virtual int onUnknownXuiParam(const wchar_t *xmlattributename, const wchar_t *value);
+
+
+#ifdef WASABI_COMPILE_CONFIG
+ virtual int onReloadConfig();
+#endif
+ virtual GuiObject *embeddedxui_getEmbeddedObject() { return embedded; }
+
+ private:
+
+#ifdef WASABI_COMPILE_CONFIG
+ void syncCfgAttrib();
+#endif
+
+ int myxuihandle;
+ PtrList<EmbeddedXuiObjectParam> paramlist;
+ GuiObject *embedded;
+};
+
+// -----------------------------------------------------------------------
+class EmbeddedXuiScriptController: public ScriptObjectControllerI
+{
+public:
+ virtual const wchar_t *getClassName() { return L"ObjectEmbedder"; }
+ virtual const wchar_t *getAncestorClassName() { return L"GuiObject"; }
+ virtual ScriptObjectController *getAncestorController();
+ virtual int getNumFunctions();
+ virtual const function_descriptor_struct *getExportedFunctions();
+ virtual GUID getClassGuid() { return embeddedXuiGuid; }
+ virtual ScriptObject *instantiate();
+ virtual void destroy(ScriptObject *o);
+ virtual void *encapsulate(ScriptObject *o);
+ virtual void deencapsulate(void *o);
+ virtual ScriptObject *cast(ScriptObject *o, GUID g);
+
+private:
+
+ static function_descriptor_struct exportedFunction[];
+ static scriptVar EmbeddedXui_getEmbeddedObject(SCRIPT_FUNCTION_PARAMS, ScriptObject *o);
+};
+
+extern COMEXP EmbeddedXuiScriptController *embeddedXuiController;
+
+
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/wndclass/foreignwnd.cpp b/Src/Wasabi/api/wnd/wndclass/foreignwnd.cpp
new file mode 100644
index 00000000..e6e490e3
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/foreignwnd.cpp
@@ -0,0 +1,60 @@
+#include "precomp.h"
+#include "foreignwnd.h"
+
+PtrListQuickSorted<ForeignWndProc, ForeignWndProcComparator> ForeignWnd::foreignwndprocs;
+
+LRESULT CALLBACK foreignWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ ForeignWndProc *wp = ForeignWnd::foreignwndprocs.findItem((const wchar_t *)hwnd);
+ if (wp)
+ {
+ if (uMsg == WM_SHOWWINDOW) // more ?
+ wp->wnd->wndProc(hwnd, uMsg, wParam, lParam);
+ return CallWindowProc(wp->oldWindowProc, hwnd, uMsg, wParam, lParam);
+ }
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+}
+
+ForeignWnd::ForeignWnd(OSWINDOWHANDLE wndhandle, OSMODULEHANDLE module, int subclass)
+{
+ thishwnd = wndhandle;
+ setOSModuleHandle(module);
+
+#ifdef EXPERIMENTAL_INDEPENDENT_AOT
+ DebugString("ForeignWnd::ForeignWnd(OSWINDOWHANDLE wndhandle): There might be problems with GWL_USERDATA assumptions when EXPERIMENTAL_INDEPENDENT_AOT is on, lone should audit\n");
+#endif
+
+ // access protected basewnd member
+ hwnd = wndhandle;
+
+ setForeignWnd(1);
+
+ if (subclass)
+ {
+ oldWindowProc = (WNDPROC) GetWindowLongPtrW(wndhandle, GWLP_WNDPROC);
+ wndprocentry = new ForeignWndProc;
+ wndprocentry->wnd = this;
+ wndprocentry->hwnd = thishwnd;
+ wndprocentry->oldWindowProc = oldWindowProc;
+ foreignwndprocs.addItem(wndprocentry);
+ SetWindowLongPtrW(thishwnd, GWLP_WNDPROC, (LONG_PTR)foreignWindowProc);
+ }
+ else
+ {
+ oldWindowProc = NULL;
+ wndprocentry = NULL;
+ }
+}
+
+ForeignWnd::~ForeignWnd()
+{
+ if (wndprocentry && oldWindowProc)
+ {
+ foreignwndprocs.removeItem(wndprocentry);
+ delete wndprocentry;
+ wndprocentry = NULL;
+ SetWindowLongPtrW(thishwnd, GWLP_WNDPROC, (LONG_PTR)oldWindowProc);
+ oldWindowProc = NULL;
+ }
+}
+
diff --git a/Src/Wasabi/api/wnd/wndclass/foreignwnd.h b/Src/Wasabi/api/wnd/wndclass/foreignwnd.h
new file mode 100644
index 00000000..023cb6b1
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/foreignwnd.h
@@ -0,0 +1,56 @@
+#ifndef __FOREIGNWND_H
+#define __FOREIGNWND_H
+
+#ifdef _WIN32
+#include <api/wnd/basewnd.h>
+
+class ForeignWnd;
+
+class ForeignWndProc
+{
+public:
+ ForeignWnd *wnd;
+ HWND hwnd;
+ WNDPROC oldWindowProc;
+};
+
+class ForeignWndProcComparator
+{
+public:
+ // comparator for sorting
+ static int compareItem(ForeignWndProc *p1, ForeignWndProc* p2)
+ {
+ return CMP3(p1->hwnd, p2->hwnd);
+ }
+ // comparator for searching
+ static int compareAttrib(const wchar_t *attrib, ForeignWndProc *item)
+ {
+ return CMP3((HWND)attrib, item->hwnd);
+ }
+};
+
+class ForeignWnd : public BaseWnd
+{
+public:
+ // takes over an existing OSWINDOWHANDLE and wraps a BaseWnd around it
+ // but does not changes the windowproc, nor does it inserts the wnd
+ // into the system list. It does not either (under windows anyway)
+ // sets the userdata windowlong to the object pointer.
+ // if subclass is true, we subclas the windowproc and process events
+ // as if the window was a real rootwnd
+
+ ForeignWnd(OSWINDOWHANDLE w, OSMODULEHANDLE m, int subclass = 0);
+
+ virtual ~ForeignWnd();
+
+ static PtrListQuickSorted<ForeignWndProc, ForeignWndProcComparator> foreignwndprocs;
+
+private:
+ WNDPROC oldWindowProc;
+ HWND thishwnd;
+ ForeignWndProc *wndprocentry;
+};
+#else
+#warning port me
+#endif
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/framewnd.cpp b/Src/Wasabi/api/wnd/wndclass/framewnd.cpp
new file mode 100644
index 00000000..26e56537
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/framewnd.cpp
@@ -0,0 +1,777 @@
+#include <precomp.h>
+
+#include "framewnd.h"
+#include <api/wnd/notifmsg.h>
+#include <bfc/bfc_assert.h>
+#include <tataki/canvas/canvas.h>
+#include <api/wnd/PaintCanvas.h>
+#include <bfc/wasabi_std_wnd.h>
+
+#define DC_FWFOCUS 0x5122
+
+FrameWnd::FrameWnd()
+{
+// sizer = NULL;
+ SNAP=1;
+ snapoffsety=0;
+ snapoffsetx=0;
+ nchild = 0;
+ for (int i = 0; i < MAXCHILD; i++) {
+ children[i] = NULL;
+ rwchildren[i] = NULL;
+ hidey[i] = 0;
+ windowshaded[i] = 0;
+ }
+ vert = DIVIDER_UNDEFINED;
+ divideside = SDP_FROMLEFT;
+ pullbarpos = PULLBAR_HALF;
+ minwidth = PULLBAR_QUARTER-PULLBAR_EIGHTH;
+ maxwidth = PULLBAR_HALF;
+ resizeable = 0;
+ slidemode = FRAMEWND_SQUISH;
+ prevpullbarpos = -1;
+ maxpixels=0;
+ minpixels=0;
+ noMaxRestriction = false;
+ ZERO(sizerRect);
+
+ h_bitmap = L"wasabi.framewnd.horizontaldivider";
+ v_bitmap = L"wasabi.framewnd.verticaldivider";
+ h_grabber = L"wasabi.framewnd.horizontalgrabber";
+ v_grabber = L"wasabi.framewnd.verticalgrabber";
+ ws_bitmap = L"wasabi.framewnd.windowshade";
+ resizing = 0;
+}
+
+void FrameWnd::Set_v_bitmap(const wchar_t *new_v_bitmap)
+{
+ v_bitmap=new_v_bitmap;
+ if (isInited())
+ {
+ invalidate();
+ onResize();
+ }
+}
+
+void FrameWnd::Set_v_grabber(const wchar_t *new_v_grabber)
+ {
+ v_grabber=new_v_grabber;
+ if (isInited())
+ {
+ invalidate();
+ onResize();
+ }
+}
+
+FrameWnd::~FrameWnd() {
+#ifdef WASABI_COMPILE_CONFIG
+ if (getId() != NULL) {
+ StringPrintfW buf(L"FrameWnd/ws,%s", getId());
+ WASABI_API_CONFIG->setIntPrivate(buf, windowshaded[0]);
+ }
+#endif
+
+ if (children[0]) // do we have any basewnd ?
+ for (int i = 0; i < nchild; i++) delete children[i];
+}
+
+int FrameWnd::onInit() {
+ int i;
+
+ FRAMEWND_PARENT::onInit();
+
+ ASSERT(vert != DIVIDER_UNDEFINED || nchild == 0);
+
+ // have to set children for frame windows
+
+ // fill in members
+ nchild = 0;
+
+ // make children create their windows
+ for (i = 0; i < MAXCHILD; i++) {
+ if (rwchildren[i] != NULL) {
+ if (rwchildren[i]->init(this) != 0) {
+ rwchildren[i]->setParent(this);
+ nchild++;
+ }
+ }
+ }
+ prevpullbarpos = pullbarpos;
+
+ if (nchild >= MAXCHILD) {
+ int which = (divideside == SDP_FROMLEFT) ? 0 : 1;
+ rwchildren[which]->bringToFront();
+ }
+
+#ifdef WASABI_COMPILE_CONFIG
+ if (getId() != NULL) {
+ StringPrintfW buf(L"FrameWnd/ws,%s", getId());
+ int ws = WASABI_API_CONFIG->getIntPrivate(buf, /*rwchildren[0] && rwchildren[0]->childNotify(NULL, CHILD_WINDOWSHADE_CAPABLE)*/ 0);
+ if (ws) {
+ windowshade(0, !ws);
+ windowshade(0, ws);
+ pullbarpos = 0;
+ }
+ }
+#endif
+
+ return 1;
+}
+
+int FrameWnd::getCursorType(int x, int y) {
+ RECT r;
+ getClientRect(&r);
+ POINT pt={x,y};
+ if (y > r.top + getLabelHeight() && Wasabi::Std::pointInRect(sizerRect, pt)) {
+ if (vert == DIVIDER_HORIZONTAL) return BASEWND_CURSOR_NORTHSOUTH;
+ else return BASEWND_CURSOR_EASTWEST;
+ }
+ return BASEWND_CURSOR_POINTER;
+}
+
+int FrameWnd::setChildren(BaseWnd *newchild1, BaseWnd *newchild2) {
+ return _setChildren(newchild1, newchild2, newchild1, newchild2);
+}
+
+int FrameWnd::setChildrenRootWnd(ifc_window *child1, ifc_window *child2/* =NULL */) {
+ return _setChildren(child1, child2, NULL, NULL);
+}
+
+int FrameWnd::_setChildren(ifc_window *child1, ifc_window *child2, BaseWnd *child1b, BaseWnd *child2b) {
+ if (child1b) { // we can delete them later
+ children[0] = child1b;
+ children[1] = child2b;
+ }
+ rwchildren[0] = child1;
+ rwchildren[1] = child2;
+ nchild = 0;
+ if (rwchildren[0] != NULL) nchild++;
+ if (rwchildren[1] != NULL) nchild++;
+
+ ASSERTPR(nchild >= 1, "framewnd must have one or more children");
+
+ if (isInited()) {
+ invalidate();
+ onResize();
+ }
+ return nchild;
+}
+
+ifc_window *FrameWnd::enumChild(int which) {
+ if (which < 0 || which >= MAXCHILD) return NULL;
+ return rwchildren[which];
+}
+
+int FrameWnd::childNotify(ifc_window *which, int msg, intptr_t param1, intptr_t param2) {
+// ASSERT(which == rwchildren[0] || which == rwchildren[1] || which == NULL);
+ switch (msg) {
+ case ChildNotify::FRAMEWND_SETTITLEWIDTH:
+ if (pullbarpos == param1) return 0;
+ ASSERT(param1 >= 0);
+ if (which == rwchildren[0]) {
+ // rwchildren[1]->invalidate(); //FG> removed due to change in redraw layout
+ // rwchildren[1]->repaint();
+ ASSERT(divideside == SDP_FROMLEFT);
+ } else {
+ // rwchildren[0]->invalidate();
+ // rwchildren[0]->repaint();
+ ASSERT(divideside == SDP_FROMRIGHT);
+ }
+ pullbarpos = param1;
+ // do it
+ onResize();
+ return 1;
+
+ case ChildNotify::HIDEYHIDEY:
+ if (which == rwchildren[0]) hidey[0] = 1;
+ else if (which == rwchildren[1]) hidey[1] = 1;
+ which->setVisible(FALSE);
+ onResize();
+ return 1;
+
+ case ChildNotify::UNHIDEYHIDEY:
+ if (which == rwchildren[0]) hidey[0] = 0;
+ else if (which == rwchildren[1]) hidey[1] = 0;
+ which->setVisible(TRUE);
+ onResize();
+ return 1;
+
+ case ChildNotify::FRAMEWND_QUERY_SLIDE_MODE:
+ return getSlideMode();
+
+ case ChildNotify::FRAMEWND_SET_SLIDE_MODE:
+ setSlideMode((FrameWndSlideMode)param1);
+ break;
+ case ChildNotify::GOTFOCUS:
+ case ChildNotify::KILLFOCUS:
+ invalidateLabel();
+ break;
+ }
+
+ return FRAMEWND_PARENT::childNotify(which, msg, param1, param2);
+}
+
+/*int FrameWnd::forceFocus() {
+ if (!canShowFocus()) return 0; // we aren't showing a label
+ int v = 0;
+ if (nchild > 0 && rwchildren[0] != NULL) {
+ if (!rwchildren[0]->canShowFocus()) v |= rwchildren[0]->gotFocus();
+ }
+ if (nchild > 1 && rwchildren[1] != NULL) {
+ if (!rwchildren[1]->canShowFocus()) v |= rwchildren[1]->gotFocus();
+ }
+ return v;
+}*/
+
+void FrameWnd::setDividerType(FrameWndDividerType type) {
+ vert = type;
+ ASSERT(vert == DIVIDER_VERTICAL || vert == DIVIDER_HORIZONTAL);
+ if (isInited())
+ onResize();
+}
+
+FrameWndDividerType FrameWnd::getDividerType() {
+ return vert;
+}
+
+int FrameWnd::ConvertPixToProp() {
+ RECT r;
+ int w;
+ getClientRect(&r);
+ if(vert == DIVIDER_VERTICAL) {
+ w = r.right-r.left;
+ } else {
+ w = r.bottom-r.top;
+ }
+ w = (pullbarpos * PULLBAR_FULL) / w;
+ return w;
+}
+
+int FrameWnd::convertPropToPix(int prop) {
+ RECT r;
+ int w;
+
+ getClientRect(&r);
+ if(vert == DIVIDER_VERTICAL) {
+ w = r.right-r.left;
+ } else {
+ w = r.bottom-r.top;
+ }
+ return (w * prop) / PULLBAR_FULL;
+}
+
+int FrameWnd::setDividerPosNoCfg(int from, int pos) {
+ divideside = from;
+
+ ASSERT(pos >= 0);
+ pullbarpos = pos;
+ if (isInited())
+ onResize();
+
+ StringPrintfW buf(L"FrameWnd/%s,p", getId());
+ WASABI_API_CONFIG->setIntPrivate(buf, pullbarpos);
+
+ return 1;
+}
+
+int FrameWnd::setDividerPos(int from, int pos) {
+#ifdef WASABI_COMPILE_CONFIG
+ if (getId() != NULL) {
+ StringPrintfW buf(L"FrameWnd/%s,p", getId());
+ pos = WASABI_API_CONFIG->getIntPrivate(buf, pos);
+ if (pos <= 0) pos = 0;
+ else if (pos >= PULLBAR_FULL) pos = PULLBAR_FULL;
+ }
+#endif
+ return setDividerPosNoCfg(from, pos);
+}
+
+void FrameWnd::getDividerPos(int *from, int *pos) {
+ if (from != NULL) *from = divideside;
+ if (pos != NULL) *pos = pullbarpos;
+}
+
+int FrameWnd::setResizeable(int is) {
+ int prev = resizeable;
+ resizeable = is;
+ return prev;
+}
+
+void FrameWnd::setMinWidth(int min) {
+ //ASSERT(min >= 0);
+ minpixels = min;
+}
+
+void FrameWnd::setMaxWidth(int max)
+{
+ //ASSERT(max >= 0);
+ maxpixels=max;
+ noMaxRestriction = (max == 0);
+ //maxwidth = max;
+}
+
+void FrameWnd::setSlideMode(FrameWndSlideMode mode) {
+ slidemode = mode;
+ if (isInited())
+ onResize();
+}
+
+FrameWndSlideMode FrameWnd::getSlideMode() {
+ return slidemode;
+}
+
+int FrameWnd::dragEnter(ifc_window *sourceWnd) {
+ ifc_window *ch = getWindowShadedChild();
+ if (ch == NULL) return FRAMEWND_PARENT::dragEnter(sourceWnd);
+ return ch->getDragInterface()->dragEnter(sourceWnd);
+}
+
+int FrameWnd::dragOver(int x, int y, ifc_window *sourceWnd) {
+ ifc_window *ch = getWindowShadedChild();
+ if (ch == NULL) return FRAMEWND_PARENT::dragOver(x, y, sourceWnd);
+ return ch->getDragInterface()->dragOver(-1, -1, sourceWnd);
+}
+
+int FrameWnd::dragLeave(ifc_window *sourceWnd) {
+ ifc_window *ch = getWindowShadedChild();
+ if (ch == NULL) return FRAMEWND_PARENT::dragLeave(sourceWnd);
+ return ch->getDragInterface()->dragLeave(sourceWnd);
+}
+
+int FrameWnd::dragDrop(ifc_window *sourceWnd, int x, int y) {
+ ifc_window *ch = getWindowShadedChild();
+ if (ch == NULL) return FRAMEWND_PARENT::dragDrop(sourceWnd, x, y);
+ return ch->getDragInterface()->dragDrop(sourceWnd, x, y);
+}
+
+int FrameWnd::onResize()
+{
+ int rt = FRAMEWND_PARENT::onResize();
+ if (!isInited()) return rt;
+ RECT r;
+ int sizerwidth = SIZERWIDTH;
+
+ if (!isInited()) {
+ prevpullbarpos = pullbarpos;
+ return 1; // no window to resize
+ }
+
+ getClientRect(&r);
+
+ ASSERT(nchild >= 0);
+ if (nchild == 0) {
+ prevpullbarpos = pullbarpos;
+ return 1;
+ }
+
+ if (hidey[0] && hidey[1]) return 0; // both windows are hiding
+
+ // if we have only one child, it takes up all the room
+ if (hidey[0]) {
+ rwchildren[1]->resize(r.left, r.top, r.right-r.left, r.bottom-r.top);
+ return 1;
+ } else if (hidey[1]) {
+ rwchildren[0]->resize(r.left, r.top, r.right-r.left, r.bottom-r.top);
+ return 1;
+ }
+
+ if (nchild == 1) {
+ if (rwchildren[0] != NULL) rwchildren[0]->resize(r.left, r.top, r.right-r.left, r.bottom-r.top);
+ else if (rwchildren[1] != NULL) rwchildren[1]->resize(r.left, r.top, r.right-r.left, r.bottom-r.top);
+ return 1;
+ }
+
+#ifdef ASSERTS_ENABLED
+ for (int i = 0; i < nchild; i++) {
+ ASSERT(rwchildren[i] != NULL);
+ }
+#endif
+
+ if (!resizeable) sizerwidth = 0;
+
+ // resize the subwindows
+
+ int w;
+ if (vert == DIVIDER_VERTICAL) {
+ w = r.right-r.left;
+ } else {
+ w = r.bottom-r.top;
+ }
+ int clientwidth = w; // the logical width
+
+ switch (pullbarpos) {
+ case PULLBAR_FULL: /*w = w;*/ break;
+ case PULLBAR_HALF: w = w/2; break;
+ case PULLBAR_QUARTER: w = w/4; break;
+ case PULLBAR_THREEQUARTER: w = w - w/4; break;
+ case PULLBAR_EIGHTH: w = w/8; break;
+ default: w = pullbarpos; break;
+ }
+
+ // maxpixels holds normally a negative or zero value!
+ if (divideside == SDP_FROMRIGHT)
+ {
+ w = (clientwidth - w);
+ if (maxpixels < 1 && w < -maxpixels) w = -maxpixels; // Martin> This fixes an ugly drawing overlap
+ // TODO: check non-relative width as well, imoh we should rewrite this function from scrap.
+ }
+ else // FROMLEFT
+ {
+ if (maxpixels < 1 && w > clientwidth + maxpixels)
+ w = clientwidth + maxpixels;
+ if (w < minpixels)
+ w = minpixels;
+ }
+
+ RECT r1, r2;
+
+ if (slidemode == FRAMEWND_COVER) { // cover mode
+
+ ASSERTPR(vert == DIVIDER_VERTICAL, "finish implementing");
+
+ if (divideside == SDP_FROMRIGHT) {
+ Wasabi::Std::setRect(&r1, r.left, r.top, r.right-r.left, r.bottom-r.top); //FG> delay resize
+ Wasabi::Std::setRect(&r2, r.left+w, r.top, r.left+clientwidth - w, r.bottom-r.top);
+ } else {
+ Wasabi::Std::setRect(&r1, r.left, r.top, r.left+w, r.bottom-r.top); //FG> delay resize
+ Wasabi::Std::setRect(&r2, r.left, r.top, r.right-r.left, r.bottom-r.top);
+ }
+
+ sizerRect.top = r.top;
+ sizerRect.bottom = r.bottom;
+ sizerRect.left = r.left + w;
+ sizerRect.right = r.left + w + sizerwidth;
+
+ } else { // squish mode
+ // left-right
+ if (vert == DIVIDER_VERTICAL) {
+ sizerRect.top = r.top;
+ sizerRect.bottom = r.bottom;
+ if (divideside == SDP_FROMLEFT) { // from left
+
+ //FG> Warning, this is using a rect for x,y,W,H and NOT l,r,t,b
+ Wasabi::Std::setRect(&r1, r.left, r.top, w, r.bottom-r.top);
+ Wasabi::Std::setRect(&r2, r.left+w+sizerwidth, r.top, (r.right-r.left)-(w+sizerwidth), r.bottom-r.top);
+
+ sizerRect.left = r.left+w;
+ sizerRect.right = sizerRect.left + sizerwidth;
+ }
+ else { // from right
+
+ //FG> Warning, this is using a rect for x,y,W,H and NOT l,r,t,b
+ Wasabi::Std::setRect(&r1, r.left, r.top, w-sizerwidth, r.bottom-r.top);
+ Wasabi::Std::setRect(&r2, r.left+w, r.top, (r.right-r.left)-w, r.bottom-r.top);
+
+ sizerRect.left = r.left+w-sizerwidth;
+ sizerRect.right = r.left+w;
+ }
+ } else {
+ // top-bottom
+
+ //FG> Warning, this is using a rect for x,y,W,H and NOT l,r,t,b
+ Wasabi::Std::setRect(&r1, r.left, r.top, r.right-r.left, w);
+ Wasabi::Std::setRect(&r2, r.left, r.top+w+sizerwidth, r.right-r.left, (r.bottom-r.top)-(w+sizerwidth));
+
+ sizerRect.top = r.top+w;
+ sizerRect.bottom = r.top+w+sizerwidth;
+ sizerRect.left = r.left;
+ sizerRect.right = r.right;
+ }
+ }
+
+ //FG> Choose resizing order. optimizes redraw by avoiding temporary overlap of rwchildren
+ bool reverse = false;
+ if (vert == DIVIDER_VERTICAL) {
+ RECT o;
+ rwchildren[0]->getNonClientRect(&o);
+ reverse = (r1.right > o.right);
+ } else {
+ RECT o;
+ rwchildren[0]->getNonClientRect(&o);
+ reverse = (r1.bottom > o.bottom);
+ }
+
+ //FG> actually resize rwchildren
+ //FG> Warning, this is using a rect for x,y,W,H and NOT l,r,t,b
+ if (reverse) {
+ rwchildren[1]->resize(r2.left, r2.top, r2.right, r2.bottom);
+ rwchildren[0]->resize(r1.left, r1.top, r1.right, r1.bottom);
+ } else {
+ rwchildren[0]->resize(r1.left, r1.top, r1.right, r1.bottom);
+ rwchildren[1]->resize(r2.left, r2.top, r2.right, r2.bottom);
+ }
+
+ onResizeChildren(r1, r2);
+
+// RECT ri = sizerRect;
+#if 0
+ if (vert == DIVIDER_HORIZONTAL) {
+ ri.left -= 2;
+ ri.right += 2;
+ } else {
+ ri.top -= 2;
+ ri.bottom += 2;
+ }
+#endif
+// invalidateRect(&ri);
+ invalidate();
+ repaint();
+
+ prevpullbarpos = pullbarpos;
+
+ return 1;
+}
+
+void FrameWnd::onResizeChildren(RECT leftr, RECT rightr) {
+}
+
+int FrameWnd::onPaint(Canvas *canvas) {
+
+ RECT d;
+ getClientRect(&d);
+ if ((d.left >= d.right) || (d.top >= d.bottom)) {
+ return FRAMEWND_PARENT::onPaint(canvas);
+ }
+
+ RECT cr;
+// PaintBltCanvas paintcanvas;
+ PaintCanvas paintcanvas;
+
+ // if only 1 child, we don't paint anything
+ if (nchild <= 1) return FRAMEWND_PARENT::onPaint(canvas);
+
+ if (canvas == NULL) {
+ if (!paintcanvas.beginPaint(this)) return 0;
+ canvas = &paintcanvas;
+ }
+ FRAMEWND_PARENT::onPaint(canvas);
+
+ getClientRect(&cr);
+
+ if (wantRenderBaseTexture() || !isVirtual())
+ renderBaseTexture(canvas, cr);
+
+ if (resizeable) {
+ RECT r = sizerRect;
+ if (vert == DIVIDER_HORIZONTAL) {
+ r.left -= 2;
+ r.right += 2;
+ } else {
+ r.top -= 2;
+ r.bottom += 2;
+ }
+
+ AutoSkinBitmap &bitmap = (vert == DIVIDER_VERTICAL) ? v_bitmap : h_bitmap;
+ bitmap.stretchToRectAlpha(canvas, &r);
+
+ if (vert == DIVIDER_VERTICAL) {
+ int h = sizerRect.bottom - sizerRect.top;
+ int gh = v_grabber.getHeight();
+ if (h > gh) {
+ RECT rr = sizerRect;
+ rr.top += (h - gh) / 2;
+ rr.bottom -= (h - gh) / 2;
+ v_grabber.stretchToRectAlpha(canvas, &rr);
+ }
+ } else {
+ int w = sizerRect.right - sizerRect.left;
+ int gw = h_grabber.getWidth();
+ if (w > gw) {
+ RECT rr = sizerRect;
+ rr.left += (w - gw) / 2;
+ rr.right -= (w - gw) / 2;
+ h_grabber.stretchToRectAlpha(canvas, &rr);
+ }
+ }
+
+ if (windowshaded[0]) {
+ RECT wr = cr;
+ if (vert == DIVIDER_VERTICAL) {
+ wr.right = r.left;
+ } else if (vert == DIVIDER_HORIZONTAL) {
+ wr.bottom = r.top;
+ }
+
+ ws_bitmap.stretchToRect(canvas, &wr);
+ }
+
+ }
+
+ return 1;
+}
+
+int FrameWnd::onLeftButtonDown(int x, int y) {
+ FRAMEWND_PARENT::onLeftButtonDown(x, y);
+ if (!resizeable) return 1;
+ POINT p = { x, y };
+ if (Wasabi::Std::pointInRect(sizerRect, p)) {
+ beginCapture();
+ RECT r;
+ getClientRect(&r);
+ x -= r.left;
+ y -= r.top;
+ snapoffsety= y - (y % SNAP);
+ snapoffsetx= x - (x % SNAP);
+ resizing = 1;
+ return 1;
+ }
+ return 0;
+}
+
+int FrameWnd::onMouseMove(int x, int y) {
+ int pos, mpos;
+ RECT r;
+
+ if (!resizing) return 1;
+
+ FRAMEWND_PARENT::onMouseMove(x,y);
+
+ prevpullbarpos = pullbarpos;
+
+ getClientRect(&r);
+ x -= r.left;
+ y -= r.top;
+
+ if (vert == DIVIDER_VERTICAL) {
+ pos = r.right - r.left;
+ if ((x - (x % SNAP)) == snapoffsetx)
+ return 1;
+ mpos=x;
+ snapoffsetx=(x - (x % SNAP));
+ } else {
+ pos = r.bottom - r.top;
+ if ((y - (y % SNAP)) == snapoffsety)
+ return 1;
+ mpos=y;
+ snapoffsety=y - (y % SNAP);
+ }
+ ASSERT(pos != 0);
+ if (mpos < 0) mpos = 0;
+ if (mpos > pos) mpos = pos;
+
+ if(divideside == SDP_FROMLEFT) {
+ pullbarpos = mpos;
+ } else {
+ pullbarpos = pos-mpos;
+ }
+
+ int realMinPixels;
+ if (minpixels)
+ {
+ realMinPixels=minpixels;
+ if (minpixels<0)
+ realMinPixels = (r.bottom - r.top) + minpixels;
+ }
+ else
+ realMinPixels = convertPropToPix(minwidth);
+
+ if (divideside == SDP_FROMLEFT)
+ {
+ if (pullbarpos < realMinPixels)
+ {
+ if (rwchildren[0] != NULL && rwchildren[0]->childNotify(NULL, ChildNotify::FRAMEWND_WINDOWSHADE_CAPABLE, 0, 0)) {
+ pullbarpos = 0;
+ windowshade(0, TRUE);
+ } else {
+ pullbarpos = realMinPixels;
+ }
+ } else {
+ windowshade(0, FALSE);
+ }
+ } else if (divideside == SDP_FROMRIGHT) {
+ if (pullbarpos < realMinPixels) {
+ if (rwchildren[1] != NULL /* && rwchildren[1]->childNotify(NULL, CHILD_WINDOWSHADE_CAPABLE) */) {
+ pullbarpos = /*convertPropToPix(PULLBAR_FULL)-*/0;
+ windowshade(1, TRUE);
+ } else {
+ pullbarpos = realMinPixels;
+ }
+ } else {
+ windowshade(1, FALSE);
+ }
+ }
+
+ if (!windowshaded[0] && !windowshaded[1]) {
+// if (pullbarpos > pos-convertPropToPix(minwidth))
+// pullbarpos = pos-convertPropToPix(minwidth);
+ int realMaxPixels;
+ if (maxpixels || noMaxRestriction)
+ {
+ realMaxPixels=maxpixels;
+ if (maxpixels<0 || noMaxRestriction)
+ {
+ if (vert == DIVIDER_VERTICAL)
+ realMaxPixels = (r.right - r.left) + maxpixels;
+ else
+ realMaxPixels = (r.bottom - r.top) + maxpixels;
+ }
+
+ }
+ else
+ realMaxPixels=convertPropToPix(maxwidth);
+
+ if (pullbarpos > realMaxPixels)
+ pullbarpos = realMaxPixels;
+ }
+
+ ASSERT(pullbarpos >= 0);
+
+ if (pullbarpos != prevpullbarpos && isInited())
+ onResize();
+
+ return 1;
+}
+
+int FrameWnd::onLeftButtonUp(int x, int y) {
+ FRAMEWND_PARENT::onLeftButtonUp(x, y);
+ if (resizing) {
+ endCapture();
+ resizing = 0;
+#ifdef WASABI_COMPILE_CONFIG
+ if (getId() != NULL) {
+ StringPrintfW buf(L"FrameWnd/%s,p", getId());
+ WASABI_API_CONFIG->setIntPrivate(buf, pullbarpos);
+ }
+#endif
+ return 1;
+ }
+ return 0;
+}
+
+void FrameWnd::windowshade(int which, int shaded) {
+ ASSERT(which == 0 || which == 1);
+ if (!!windowshaded[which] == !!shaded) return;
+ if (rwchildren[which] == NULL) return;
+ rwchildren[which]->childNotify(NULL, ChildNotify::FRAMEWND_WINDOWSHADE_ENABLE, shaded, 0);
+ windowshaded[which] = shaded;
+ rwchildren[which]->setVisible(!shaded);
+}
+
+ifc_window *FrameWnd::getWindowShadedChild() {
+ if (nchild != 2) return NULL;
+ if (!(windowshaded[0] | windowshaded[1])) return NULL;
+ return windowshaded[0] ? rwchildren[0] : rwchildren[1];
+}
+
+int FrameWnd::onGetFocus() {
+ postDeferredCallback(DC_FWFOCUS, 0);
+ return 1;
+}
+
+int FrameWnd::onDeferredCallback(intptr_t p1, intptr_t p2) {
+ switch (p1) {
+ case DC_FWFOCUS:
+ if (rwchildren[0]) rwchildren[0]->setFocus();
+ break;
+ default:
+ return FRAMEWND_PARENT::onDeferredCallback(p1, p2);
+ }
+ return 1;
+}
+
+
+void FrameWnd::setSnap(int snap)
+{
+ if (snap>0)
+ SNAP=snap;
+} \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/wndclass/framewnd.h b/Src/Wasabi/api/wnd/wndclass/framewnd.h
new file mode 100644
index 00000000..506426e6
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/framewnd.h
@@ -0,0 +1,124 @@
+//NONPORTABLE
+#ifndef _FRAMEWND_H
+#define _FRAMEWND_H
+
+#include <bfc/common.h>
+#include <api/wnd/wndclass/labelwnd.h>
+#include <tataki/bitmap/autobitmap.h>
+
+#define MAXCHILD 2 // this had better never not be 2
+
+typedef enum {
+ DIVIDER_HORIZONTAL, DIVIDER_VERTICAL, DIVIDER_UNDEFINED = -1
+} FrameWndDividerType;
+enum { SDP_FROMLEFT, SDP_FROMRIGHT };
+#define SDP_FROMTOP SDP_FROMLEFT
+#define SDP_FROMBOTTOM SDP_FROMRIGHT
+
+typedef enum {
+ FRAMEWND_SQUISH,
+ FRAMEWND_COVER
+} FrameWndSlideMode;
+
+#define SIZERWIDTH 8
+
+// this window holds other basewnd derived classes
+#define FRAMEWND_PARENT LabelWnd
+class FrameWnd : public FRAMEWND_PARENT {
+public:
+ FrameWnd();
+ virtual ~FrameWnd();
+
+ virtual int onInit();
+
+ virtual int getCursorType(int x, int y);
+
+ virtual int onPaint(Canvas *canvas);
+ virtual int onResize();
+
+ virtual int onLeftButtonDown(int x, int y);
+ virtual int onMouseMove(int x, int y); // only called when mouse captured
+ virtual int onLeftButtonUp(int x, int y);
+
+ virtual int childNotify(ifc_window *which, int msg, intptr_t param1, intptr_t param2);
+
+// virtual int forceFocus();
+
+ // unique to this class
+ int setChildren(BaseWnd *child1, BaseWnd *child2=NULL);
+ int setChildrenRootWnd(ifc_window *child1, ifc_window *child2=NULL);
+ ifc_window *enumChild(int which);
+ // horizontal or vertical?
+ void setDividerType(FrameWndDividerType type);
+ FrameWndDividerType getDividerType();
+ // where is the divider?
+ int setDividerPos(int from, int pos);
+ // this version doesn't check the cfg file for last position
+ int setDividerPosNoCfg(int from, int pos);
+ void getDividerPos(int *from, int *pos);
+
+ int setResizeable(int is);
+ void setMinWidth(int min);
+ void setMaxWidth(int max);
+ void setSnap(int snap);
+
+ virtual int onGetFocus();
+ virtual int onDeferredCallback(intptr_t p1, intptr_t p2);
+
+ // cover or squish
+ void setSlideMode(FrameWndSlideMode mode);
+ FrameWndSlideMode getSlideMode();
+
+ virtual void onResizeChildren(RECT leftr, RECT rightr);
+
+ // drag and drops are forwarded into windowshaded windows
+ virtual int dragEnter(ifc_window *sourceWnd);
+ virtual int dragOver(int x, int y, ifc_window *sourceWnd);
+ virtual int dragLeave(ifc_window *sourceWnd);
+ virtual int dragDrop(ifc_window *sourceWnd, int x, int y);
+
+protected:
+ int convertPropToPix(int prop);
+ int ConvertPixToProp();
+
+ void windowshade(int which, int shaded);
+ ifc_window *getWindowShadedChild();
+
+ void Set_v_bitmap(const wchar_t *new_v_bitmap);
+ void Set_v_grabber(const wchar_t *new_v_grabber);
+
+private:
+ int _setChildren(ifc_window *child1, ifc_window *child2, BaseWnd *child1b, BaseWnd *child2b);
+ int nchild;
+ BaseWnd *children[MAXCHILD];
+ ifc_window *rwchildren[MAXCHILD];
+ int hidey[MAXCHILD];
+ int windowshaded[MAXCHILD];
+
+ FrameWndDividerType vert;
+
+ int resizeable;
+ FrameWndSlideMode slidemode;
+
+ int divideside;
+ int pullbarpos; // 0..65536
+ int prevpullbarpos;
+ int minwidth, maxwidth;
+ int maxpixels;
+ boolean noMaxRestriction;
+ int minpixels;
+ int snapoffsetx, snapoffsety;
+ int SNAP;
+ RECT sizerRect;
+
+ AutoSkinBitmap h_bitmap, v_bitmap, h_grabber, v_grabber, ws_bitmap;
+ int resizing;
+};
+
+#define PULLBAR_FULL 65536L
+#define PULLBAR_HALF (PULLBAR_FULL/2)
+#define PULLBAR_QUARTER (PULLBAR_FULL/4)
+#define PULLBAR_THREEQUARTER (PULLBAR_FULL-PULLBAR_QUARTER)
+#define PULLBAR_EIGHTH (PULLBAR_FULL/8)
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/gradientwnd.cpp b/Src/Wasabi/api/wnd/wndclass/gradientwnd.cpp
new file mode 100644
index 00000000..f34b31f9
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/gradientwnd.cpp
@@ -0,0 +1,82 @@
+#include <precomp.h>
+
+#include "gradientwnd.h"
+
+
+// NOTE
+// works now ;)
+
+GradientWnd::GradientWnd()
+: bitmap(4,4, getOsWindowHandle())
+{
+ cache_w = cache_h = 4;
+ last_w = last_h = -1;
+ recreate = 1;
+ setReverseColors(TRUE);
+}
+
+GradientWnd::~GradientWnd()
+{
+ WASABI_API_SYSCB->syscb_deregisterCallback(static_cast<SkinCallbackI*>(this));
+}
+
+int GradientWnd::onInit ()
+{
+ int r = GRADIENTWND_PARENT::onInit();
+ WASABI_API_SYSCB->syscb_registerCallback(static_cast<SkinCallbackI*>(this));
+ return r;
+}
+
+int GradientWnd::onPaint(Canvas *canvas)
+{
+ ASSERT(canvas != NULL);
+ RECT cr = clientRect();
+
+ int w = cr.right - cr.left, h = cr.bottom - cr.top;
+ if (w && h)
+ {
+ if (w != last_w || h != last_h)
+ {
+ recreate=1;
+ }
+ if (w > cache_w || h > cache_h)
+ {
+ cache_w = max(w, cache_w);
+ cache_h = max(h, cache_h);
+ // round up to nearest 4
+ cache_w = (cache_w+3) & ~3;
+ cache_h = (cache_h+3) & ~3;
+
+ bitmap.DestructiveResize(cache_w,cache_h,32);
+ recreate = 1;
+ }
+
+ if (recreate)
+ {
+ ARGB32 *bits = static_cast<ARGB32*>(bitmap.getBits());
+ renderGradient(bits, w, h, /*pitch=*/cache_w);
+ last_w = w;
+ last_h = h;
+ recreate=0;
+ }
+ RECT src = {0,0,w,h};
+ bitmap./*getSkinBitmap()->*/blitToRect(canvas, &src, &cr, getPaintingAlpha());
+ //bitmap./*getSkinBitmap()->*/blitAlpha(canvas, cr.left, cr.top, getPaintingAlpha());
+ }
+ return 1;
+}
+
+void GradientWnd::onParamChange()
+{
+ invalidate();
+ recreate = 1;
+}
+
+int GradientWnd::skincb_onColorThemeChanged(const wchar_t *newcolortheme)
+{
+ // TODO: This will refresh after ca 1 sec - we need an instand redraw
+ invalidate();
+ recreate = 1;
+ return 0;
+}
+
diff --git a/Src/Wasabi/api/wnd/wndclass/gradientwnd.h b/Src/Wasabi/api/wnd/wndclass/gradientwnd.h
new file mode 100644
index 00000000..c7c02695
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/gradientwnd.h
@@ -0,0 +1,31 @@
+#ifndef _GRADIENTWND_H
+#define _GRADIENTWND_H
+
+#include <api/wnd/wndclass/guiobjwnd.h>
+#include <bfc/draw/gradient.h>
+#include <tataki/canvas/bltcanvas.h>
+
+#define GRADIENTWND_PARENT GuiObjectWnd
+class GradientWnd : public GRADIENTWND_PARENT, public Gradient, public SkinCallbackI {
+public:
+ GradientWnd();
+ virtual ~GradientWnd();
+
+ virtual int onPaint(Canvas *canvas);
+
+protected:
+ virtual void onParamChange();
+
+private:
+ int recreate;
+
+ int last_w, last_h;
+ int cache_w, cache_h;
+ BltCanvas bitmap;
+
+protected:
+ int onInit();
+ int skincb_onColorThemeChanged(const wchar_t *newcolortheme);
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/guiobjwnd.cpp b/Src/Wasabi/api/wnd/wndclass/guiobjwnd.cpp
new file mode 100644
index 00000000..fcb70d0c
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/guiobjwnd.cpp
@@ -0,0 +1,476 @@
+#include <precomp.h>
+#include <api/script/api_maki.h>
+#include <api/wnd/wndclass/guiobjwnd.h>
+#include <api/script/scriptobj.h>
+#include <api/script/scriptguid.h>
+#include <api/service/svcs/svc_droptarget.h>
+#include <api/wnd/notifmsg.h>
+#include <api/script/objects/rootobject.h>
+#include <api/locales/xlatstr.h>
+
+XMLParamPair GuiObjectWnd::params[] =
+ {
+ {GUIOBJECT_ACTIVEALPHA, L"ACTIVEALPHA"},
+ {GUIOBJECT_ALPHA, L"ALPHA"},
+ {GUIOBJECT_SETANCHOR, L"ANCHOR"},
+#ifdef USEAPPBAR
+ {GUIOBJECT_APPBAR, L"APPBAR"},
+#endif
+ {GUIOBJECT_CFGATTR, L"CFGATTRIB"},
+ {GUIOBJECT_SETCURSOR, L"CURSOR"},
+ {GUIOBJECT_DROPTARGET, L"DROPTARGET"},
+ {GUIOBJECT_ENABLED, L"ENABLED"},
+ {GUIOBJECT_FITTOPARENT, L"FITPARENT"},
+ {GUIOBJECT_FOCUSONCLICK, L"FOCUSONCLICK"},
+ {GUIOBJECT_GHOST, L"GHOST"},
+ {GUIOBJECT_H, L"H"},
+ {GUIOBJECT_ID, L"ID"},
+ {GUIOBJECT_INACTIVEALPHA, L"INACTIVEALPHA"},
+ {GUIOBJECT_MOVE, L"MOVE"},
+ {GUIOBJECT_SETNOCONTEXTMENU, L"NOCONTEXTMENU"},
+ {GUIOBJECT_SETNODBLCLICK, L"NODBLCLICK"},
+ {GUIOBJECT_SETNOLEFTCLICK, L"NOLEFTCLICK"},
+ {GUIOBJECT_SETNOMOUSEMOVE, L"NOMOUSEMOVE"},
+ {GUIOBJECT_SETNORIGHTCLICK, L"NORIGHTCLICK"},
+ {GUIOBJECT_NOTIFY, L"NOTIFY"},
+ {GUIOBJECT_NOTIFY, L"NOTIFY0"},
+ {GUIOBJECT_NOTIFY, L"NOTIFY1"},
+ {GUIOBJECT_NOTIFY, L"NOTIFY2"},
+ {GUIOBJECT_NOTIFY, L"NOTIFY3"},
+ {GUIOBJECT_NOTIFY, L"NOTIFY4"},
+ {GUIOBJECT_NOTIFY, L"NOTIFY5"},
+ {GUIOBJECT_NOTIFY, L"NOTIFY6"},
+ {GUIOBJECT_NOTIFY, L"NOTIFY7"},
+ {GUIOBJECT_NOTIFY, L"NOTIFY8"},
+ {GUIOBJECT_NOTIFY, L"NOTIFY9"},
+ {GUIOBJECT_RECTRGN, L"RECTRGN"},
+ {GUIOBJECT_SYSREGION, L"REGIONOP"},
+ {GUIOBJECT_RELATH, L"RELATH"},
+ {GUIOBJECT_RELATW, L"RELATW"},
+ {GUIOBJECT_RELATX, L"RELATX"},
+ {GUIOBJECT_RELATY, L"RELATY"},
+ {GUIOBJECT_RENDERBASETEXTURE, L"RENDERBASETEXTURE"},
+ {GUIOBJECT_SYSMETRICSX, L"SYSMETRICSX"},
+ {GUIOBJECT_SYSMETRICSY, L"SYSMETRICSY"},
+ {GUIOBJECT_SYSMETRICSW, L"SYSMETRICSW"},
+ {GUIOBJECT_SYSMETRICSH, L"SYSMETRICSH"},
+ {GUIOBJECT_SYSREGION, L"SYSREGION"},
+ {GUIOBJECT_TABORDER, L"TABORDER"},
+ {GUIOBJECT_TOOLTIP, L"TOOLTIP"},
+ {GUIOBJECT_TRANSLATE, L"TRANSLATE"},
+ {GUIOBJECT_USERDATA, L"USERDATA"},
+ {GUIOBJECT_VISIBLE, L"VISIBLE"},
+ {GUIOBJECT_W, L"W"},
+ {GUIOBJECT_WANTFOCUS, L"WANTFOCUS"},
+ {GUIOBJECT_X, L"X"},
+ {GUIOBJECT_SETX1, L"X1"},
+ {GUIOBJECT_SETX2, L"X2"},
+ {GUIOBJECT_Y, L"Y"},
+ {GUIOBJECT_SETY1, L"Y1"},
+ {GUIOBJECT_SETY2, L"Y2"},
+ };
+
+GuiObjectWnd::GuiObjectWnd()
+{
+ my_gui_object = static_cast<GuiObject *>(WASABI_API_MAKI->maki_encapsulate(guiObjectGuid, getScriptObject()));
+ getScriptObject()->vcpu_setInterface(xmlObjectGuid, static_cast<XmlObject *>(this));
+ getScriptObject()->vcpu_setInterface(guiObjectWndGuid, static_cast<GuiObjectWnd *>(this));
+#ifdef USEAPPBAR
+ getScriptObject()->vcpu_setInterface(appBarGuid, static_cast<AppBar*>(this));
+#endif
+ my_gui_object->guiobject_setRootWnd(this);
+ getScriptObject()->vcpu_setClassName(L"GuiObject");
+ getScriptObject()->vcpu_setController(WASABI_API_MAKI->maki_getController(guiObjectGuid));
+ cfg_reentry = 0;
+ xuihandle = newXuiHandle();
+ CreateXMLParameters(xuihandle);
+}
+
+void GuiObjectWnd::CreateXMLParameters(int master_handle)
+{
+ int numParams = sizeof(params) / sizeof(params[0]);
+ hintNumberOfParams(xuihandle, numParams);
+ for (int i = 0;i < numParams;i++)
+ addParam(xuihandle, params[i], XUI_ATTRIBUTE_IMPLIED);
+}
+
+GuiObjectWnd::~GuiObjectWnd()
+{
+ WASABI_API_MAKI->maki_deencapsulate(guiObjectGuid, my_gui_object);
+ my_gui_object = NULL;
+}
+
+const wchar_t *GuiObjectWnd::getTip()
+{
+ switch(wantTranslation())
+ {
+ case 1:
+ return _(tip);
+ case 2:
+return __(tip);
+ default:
+ return tip;
+ }
+}
+
+int GuiObjectWnd::onRightButtonDown(int x, int y)
+{
+ if (!my_gui_object) return 1;
+ GUIOBJECTWND_PARENT::onRightButtonDown(x, y);
+ my_gui_object->guiobject_onRightButtonDown(x, y);
+ return 1;
+}
+
+int GuiObjectWnd::onRightButtonUp(int x, int y)
+{
+ if (!my_gui_object) return 1;
+ GUIOBJECTWND_PARENT::onRightButtonUp(x, y);
+ my_gui_object->guiobject_onRightButtonUp(x, y);
+ return 1;
+}
+
+int GuiObjectWnd::onLeftButtonDown(int x, int y)
+{
+ if (!my_gui_object) return 1;
+ GUIOBJECTWND_PARENT::onLeftButtonDown(x, y);
+ my_gui_object->guiobject_onLeftButtonDown(x, y);
+ return 1;
+}
+
+int GuiObjectWnd::onLeftButtonUp(int x, int y)
+{
+ if (!my_gui_object) return 1;
+ GUIOBJECTWND_PARENT::onLeftButtonUp(x, y);
+ my_gui_object->guiobject_onLeftButtonUp(x, y);
+ return 1;
+}
+
+int GuiObjectWnd::onMouseMove(int x, int y)
+{
+ if (!my_gui_object) return 1;
+ GUIOBJECTWND_PARENT::onMouseMove(x, y);
+ my_gui_object->guiobject_onMouseMove(x, y);
+ return 1;
+}
+
+int GuiObjectWnd::wantTranslation()
+{
+ if (!my_gui_object) return 1;
+ return my_gui_object->guiobject_wantTranslation();
+}
+
+int GuiObjectWnd::onLeftButtonDblClk(int x, int y)
+{
+ if (!my_gui_object) return 1;
+ GUIOBJECTWND_PARENT::onLeftButtonDblClk(x, y);
+ my_gui_object->guiobject_onLeftButtonDblClk(x, y);
+ return 1;
+}
+
+int GuiObjectWnd::onRightButtonDblClk(int x, int y)
+{
+ if (!my_gui_object) return 1;
+ GUIOBJECTWND_PARENT::onRightButtonDblClk(x, y);
+ my_gui_object->guiobject_onRightButtonDblClk(x, y);
+ return 1;
+}
+
+// Martin> For the next two functions, we need to ensure that we don't kill volume change if nothing is done
+int GuiObjectWnd::onMouseWheelDown (int click, int line)
+{
+ if (!my_gui_object) return 1;
+ int ret = GUIOBJECTWND_PARENT::onMouseWheelDown(click, line);
+ if (!ret) ret = my_gui_object->guiobject_onMouseWheelDown(click, line);
+ return ret;
+}
+
+int GuiObjectWnd::onMouseWheelUp (int click, int line)
+{
+ if (!my_gui_object) return 1;
+ int ret = GUIOBJECTWND_PARENT::onMouseWheelUp(click, line);
+ if (!ret) ret = my_gui_object->guiobject_onMouseWheelUp(click, line);
+ return ret;
+}
+
+int GuiObjectWnd::onResize()
+{
+ if (!my_gui_object) return 1;
+ GUIOBJECTWND_PARENT::onResize();
+ if (!isInited()) return 1;
+ ifc_window *w = my_gui_object->guiobject_getRootWnd();
+ RECT r;
+ w->getClientRect(&r);
+ my_gui_object->guiobject_onResize(r.left, r.top, r.right - r.left, r.bottom - r.top);
+ return 1;
+}
+
+void GuiObjectWnd::onEnterArea()
+{
+ if (!my_gui_object) return ;
+ GUIOBJECTWND_PARENT::onEnterArea();
+ my_gui_object->guiobject_onEnterArea();
+}
+
+void GuiObjectWnd::onLeaveArea()
+{
+ if (!my_gui_object) return ;
+ GUIOBJECTWND_PARENT::onLeaveArea();
+ my_gui_object->guiobject_onLeaveArea();
+}
+
+void GuiObjectWnd::onSetVisible(int show)
+{
+ if (!my_gui_object)
+ return ;
+
+ GUIOBJECTWND_PARENT::onSetVisible(show);
+ my_gui_object->guiobject_onSetVisible(show);
+}
+
+int GuiObjectWnd::onEnable(int en)
+{
+ if (!my_gui_object) return 1;
+ GUIOBJECTWND_PARENT::onEnable(en);
+ my_gui_object->guiobject_onEnable(en);
+ return 1;
+}
+
+GuiObject *GuiObjectWnd::getGuiObject()
+{
+ return my_gui_object;
+}
+
+RootObject *GuiObjectWnd::getRootObject()
+{
+ return my_gui_object->guiobject_getRootObject();
+}
+
+int GuiObjectWnd::dragDrop(ifc_window *sourceWnd, int x, int y)
+{
+ int r = DropTargetEnum::throwDrop(my_gui_object->guiobject_getDropTarget(), sourceWnd, x, y);
+ if (r == 0)
+ {
+ ifc_window *p = getParent();
+ if (p != NULL)
+ {
+ DragInterface *d = p->getDragInterface();
+ if (d != NULL)
+ return d->dragDrop(sourceWnd, x, y);
+ }
+ }
+ return r;
+}
+
+int GuiObjectWnd::dragEnter(ifc_window *sourceWnd)
+{
+ my_gui_object->guiobject_dragEnter(sourceWnd);
+ return 1;
+}
+
+int GuiObjectWnd::dragOver(int x, int y, ifc_window *sourceWnd)
+{
+ my_gui_object->guiobject_dragOver(x, y, sourceWnd);
+ return 1;
+}
+
+int GuiObjectWnd::dragLeave(ifc_window *sourceWnd)
+{
+ my_gui_object->guiobject_dragLeave(sourceWnd);
+ return 1;
+}
+
+int GuiObjectWnd::onActivate()
+{
+ if (!my_gui_object) return 1;
+ GUIOBJECTWND_PARENT::onActivate();
+ invalidate();
+ return 1;
+}
+
+int GuiObjectWnd::onDeactivate()
+{
+ if (!my_gui_object) return 1;
+ GUIOBJECTWND_PARENT::onDeactivate();
+ invalidate();
+ return 1;
+}
+
+void GuiObjectWnd::onCancelCapture()
+{
+ if (!my_gui_object) return ;
+ GUIOBJECTWND_PARENT::onCancelCapture();
+ my_gui_object->guiobject_onCancelCapture();
+}
+
+int GuiObjectWnd::setXuiParam(int _xuihandle, int attrid, const wchar_t *name, const wchar_t *value)
+{
+ if (_xuihandle == xuihandle)
+ {
+ switch (attrid)
+ {
+ case GUIOBJECT_FOCUSONCLICK:
+ setFocusOnClick(WTOI(value));
+ break;
+ default:
+ getGuiObject()->guiobject_setXmlParamById(attrid, value);
+ break;
+ }
+ }
+ return 0;
+}
+
+int GuiObjectWnd::onUnknownXmlParam(const wchar_t *param, const wchar_t *value)
+{
+ return onUnknownXuiParam(param, value);
+}
+
+int GuiObjectWnd::setXmlParamById(int xmlhandle, int attrid, const wchar_t *name, const wchar_t *value)
+{
+ return setXuiParam(xmlhandle, attrid, name, value);
+}
+
+void *GuiObjectWnd::getInterface(GUID interface_guid)
+{
+ void *r = GUIOBJECTWND_PARENT::getInterface(interface_guid);
+ if (r) return r;
+ return getRootObject()->rootobject_getScriptObject()->vcpu_getInterface(interface_guid);
+}
+
+int GuiObjectWnd::onAction(const wchar_t *action, const wchar_t *param, int x, int y, intptr_t p1, intptr_t p2, void *data, size_t datalen, ifc_window *source)
+{
+#ifdef WASABI_COMPILE_CONFIG
+ if (!_wcsicmp(action, L"reload_config") && isInited())
+ {
+ if (cfg_reentry) return 1;
+ cfg_reentry = 1;
+ int r = onReloadConfig();
+ cfg_reentry = 0;
+ return r;
+ }
+#endif
+ int rt = GUIOBJECTWND_PARENT::onAction(action, param, x, y, p1, p2, data, datalen, source);
+ getGuiObject()->guiobject_onAction(action, param, x, y, p1, p2, data, datalen, source);
+ return rt;
+}
+
+void GuiObjectWnd::setContent(const wchar_t *groupid_orguid, int autoresizefromcontent)
+{
+#ifdef WASABI_COMPILE_SKIN
+
+ // abstract_setAllowDeferredContent(0);
+ abstract_setContent(groupid_orguid, autoresizefromcontent);
+#endif
+}
+
+void GuiObjectWnd::setContentBySkinItem(SkinItem *item, int autoresizefromcontent)
+{
+ // abstract_setAllowDeferredContent(0);
+#ifdef WASABI_COMPILE_SKIN
+ abstract_setContentBySkinItem(item, autoresizefromcontent);
+#endif
+}
+
+void GuiObjectWnd::abstract_onNewContent()
+{
+
+#ifdef WASABI_COMPILE_SKIN
+ GUIOBJECTWND_PARENT::abstract_onNewContent();
+#endif
+ onNewContent();
+#ifdef WASABI_COMPILE_CONFIG
+ if (getGuiObject()->guiobject_hasCfgAttrib())
+ onReloadConfig();
+#endif
+}
+
+GuiObject *GuiObjectWnd::findObject(const wchar_t *object_id)
+{
+ return getGuiObject()->guiobject_findObject(object_id);
+}
+
+#ifdef WASABI_COMPILE_SCRIPT
+ScriptObject *GuiObjectWnd::findScriptObject(const wchar_t *object_id)
+{
+ GuiObject *fo = getGuiObject()->guiobject_findObject(object_id);
+ if (fo != NULL) return fo->guiobject_getScriptObject();
+ return NULL;
+}
+#endif
+const wchar_t *GuiObjectWnd::getId()
+{
+ if (my_gui_object)
+ return my_gui_object->guiobject_getId();
+ return GUIOBJECTWND_PARENT::getId();
+}
+
+int GuiObjectWnd::onPostOnInit()
+{
+ int r = GUIOBJECTWND_PARENT::onPostOnInit();
+#ifdef WASABI_COMPILE_CONFIG
+ if (getGuiObject()->guiobject_hasCfgAttrib())
+ onReloadConfig();
+#endif
+ return r;
+}
+
+int GuiObjectWnd::onInit()
+{
+ int r = GUIOBJECTWND_PARENT::onInit();
+ getGuiObject()->guiobject_onInit();
+ return r;
+}
+
+int GuiObjectWnd::onChar(unsigned int c)
+{
+ if (!my_gui_object) return 1;
+ int r = GUIOBJECTWND_PARENT::onChar(c);
+ getGuiObject()->guiobject_onChar(c);
+ return r;
+}
+
+int GuiObjectWnd::onKeyDown(int vkcode)
+{
+ if (!my_gui_object) return 1;
+ int r = GUIOBJECTWND_PARENT::onKeyDown(vkcode);
+ getGuiObject()->guiobject_onKeyDown(vkcode);
+ return r;
+}
+
+int GuiObjectWnd::onKeyUp(int vkcode)
+{
+ if (!my_gui_object) return 1;
+ int r = GUIOBJECTWND_PARENT::onKeyUp(vkcode);
+ getGuiObject()->guiobject_onKeyUp(vkcode);
+ return r;
+}
+
+int GuiObjectWnd::onGetFocus()
+{
+ if (!my_gui_object) return 1;
+ int r = GUIOBJECTWND_PARENT::onGetFocus();
+ getGuiObject()->guiobject_onGetFocus();
+ return r;
+}
+
+int GuiObjectWnd::onKillFocus()
+{
+ if (!my_gui_object) return 1;
+ int r = GUIOBJECTWND_PARENT::onKillFocus();
+ getGuiObject()->guiobject_onKillFocus();
+ return r;
+}
+
+int GuiObjectWnd::onAcceleratorEvent(const wchar_t *name)
+{
+ int r = GUIOBJECTWND_PARENT::onAcceleratorEvent(name);
+ getGuiObject()->guiobject_onAccelerator(name);
+ return r;
+}
+
+int GuiObjectWnd::wantFocus()
+{
+ if (GUIOBJECTWND_PARENT::wantFocus()) return 1;
+ if (my_gui_object)
+ return my_gui_object->guiobject_wantFocus();
+ return 0;
+}
diff --git a/Src/Wasabi/api/wnd/wndclass/guiobjwnd.h b/Src/Wasabi/api/wnd/wndclass/guiobjwnd.h
new file mode 100644
index 00000000..f172c92f
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/guiobjwnd.h
@@ -0,0 +1,237 @@
+#ifndef __GUIOBJWND_H
+#define __GUIOBJWND_H
+
+#if defined(WIN32) || defined(WIN64)
+#define USEAPPBAR
+#endif
+
+#ifdef USEAPPBAR
+#include <api/wnd/wndclass/appbarwnd.h>
+#define GUIOBJECTWND_PARENT AppBarWnd
+#else
+#include <api/wnd/wndclass/clickwnd.h>
+#define GUIOBJECTWND_PARENT ClickWnd
+#endif
+
+#include <api/script/scriptobj.h>
+#include <api/script/objects/guiobject.h>
+#include <api/script/objects/rootobj.h>
+#include <api/skin/xmlobject.h>
+#include <api/service/svcs/svc_xuiobject.h>
+
+// {E5760861-5489-4ffc-BE02-061D9DA6CD1B}
+const GUID guiObjectWndGuid =
+ { 0xe5760861, 0x5489, 0x4ffc, { 0xbe, 0x2, 0x6, 0x1d, 0x9d, 0xa6, 0xcd, 0x1b } };
+
+#define XUI_ATTRIBUTE_IMPLIED XML_ATTRIBUTE_IMPLIED
+#define XUI_ATTRIBUTE_REQUIRED XML_ATTRIBUTE_REQUIRED
+
+class GuiObjectWnd : public GUIOBJECTWND_PARENT, public RootObjectInstance, public XmlObjectI
+{
+public:
+ GuiObjectWnd();
+ virtual ~GuiObjectWnd();
+
+#ifdef WASABI_COMPILE_CONFIG
+ virtual int onReloadConfig() { return 1; }
+#endif
+
+ // XmlObject
+
+ virtual int setXmlParamById(int xmlhandle, int attrid, const wchar_t *name, const wchar_t *value);
+ virtual int onUnknownXmlParam(const wchar_t *param, const wchar_t *value);
+ virtual int newXuiHandle() { return newXmlHandle(); }
+
+ // ClickWnd
+
+ virtual int onRightButtonDown(int x, int y);
+ virtual int onRightButtonUp(int x, int y);
+ virtual int onLeftButtonDown(int x, int y);
+ virtual int onLeftButtonUp(int x, int y);
+ virtual int onMouseMove(int x, int y);
+ virtual int onLeftButtonDblClk(int x, int y);
+ virtual int onRightButtonDblClk(int x, int y);
+ virtual int onMouseWheelUp(int click, int lines);
+ virtual int onMouseWheelDown(int click, int lines);
+ virtual int onResize();
+ virtual int onActivate();
+ virtual int onDeactivate();
+ virtual void onEnterArea();
+ virtual void onLeaveArea();
+ virtual void onSetVisible(int show);
+ virtual int onEnable(int en);
+ virtual void onCancelCapture();
+ virtual int dragDrop(ifc_window *sourceWnd, int x, int y);
+ virtual int acceptExternalDrops() { return 1; }
+ virtual int dragEnter(ifc_window *sourceWnd);
+ virtual int dragOver(int x, int y, ifc_window *sourceWnd);
+ virtual int dragLeave(ifc_window *sourceWnd);
+ virtual void *getInterface(GUID g);
+ virtual int onAction(const wchar_t *action, const wchar_t *param, int x, int y, intptr_t p1, intptr_t p2, void *data, size_t datalen, ifc_window *source);
+ virtual const wchar_t *getId();
+ virtual int onAcceleratorEvent(const wchar_t *name);
+
+ virtual void setContent(const wchar_t *groupid_orguid, int autoresizefromcontent = 0);
+ virtual void setContentBySkinItem(SkinItem *item, int autoresizefromcontent = 0);
+ virtual void onNewContent() {}
+
+ // AbstractWndHolder
+ virtual void abstract_onNewContent();
+
+
+ virtual int onUnknownXuiParam(const wchar_t *param, const wchar_t *value) { return 0; }
+
+ virtual GuiObject *findObject(const wchar_t *object_id);
+#ifdef WASABI_COMPILE_SCRIPT
+ virtual ScriptObject *findScriptObject(const wchar_t *object_id);
+#endif
+#ifdef WASABI_COMPILE_SKIN
+ virtual GuiObject *getContent() { return abstract_getContent(); }
+ virtual ScriptObject *getContentScriptObject() { return abstract_getContentScriptObject(); }
+ virtual ifc_window *getContentRootWnd() { return abstract_getContentRootWnd(); }
+#endif
+
+ // BaseWnd
+
+ virtual int onInit();
+ virtual int onPostOnInit();
+ virtual int onChar(unsigned int c);
+ virtual int onKeyDown(int vkcode);
+ virtual int onKeyUp(int vkcode);
+
+ virtual int onGetFocus();
+ virtual int onKillFocus();
+ virtual int wantFocus();
+
+ const wchar_t *getTip();
+ // GuiObjectWnd
+ int wantTranslation();
+ GuiObject *getGuiObject();
+ RootObject *getRootObject();
+ int cfg_reentry;
+
+ // XuiObject
+ virtual int setXuiParam(int _xuihandle, int attrid, const wchar_t *name, const wchar_t *value);
+
+protected:
+ /*static */void CreateXMLParameters(int master_handle);
+private:
+ GuiObject *my_gui_object;
+ int xuihandle;
+ static XMLParamPair params[];
+
+
+public:
+
+ enum {
+ GUIOBJECT_ID = 0,
+ GUIOBJECT_ALPHA,
+ GUIOBJECT_ACTIVEALPHA,
+ GUIOBJECT_INACTIVEALPHA,
+ GUIOBJECT_SYSREGION,
+ GUIOBJECT_RECTRGN,
+ GUIOBJECT_TOOLTIP,
+ GUIOBJECT_SYSMETRICSX,
+ GUIOBJECT_SYSMETRICSY,
+ GUIOBJECT_SYSMETRICSW,
+ GUIOBJECT_SYSMETRICSH,
+ GUIOBJECT_MOVE,
+ GUIOBJECT_RENDERBASETEXTURE,
+ GUIOBJECT_CFGATTR,
+ GUIOBJECT_X,
+ GUIOBJECT_Y,
+ GUIOBJECT_W,
+ GUIOBJECT_H,
+ GUIOBJECT_VISIBLE,
+ GUIOBJECT_ENABLED,
+ GUIOBJECT_RELATX,
+ GUIOBJECT_RELATY,
+ GUIOBJECT_RELATW,
+ GUIOBJECT_RELATH,
+ GUIOBJECT_DROPTARGET,
+ GUIOBJECT_GHOST,
+ GUIOBJECT_NOTIFY,
+ GUIOBJECT_FOCUSONCLICK,
+ GUIOBJECT_TABORDER,
+ GUIOBJECT_WANTFOCUS,
+ GUIOBJECT_SETNODBLCLICK,
+ GUIOBJECT_SETNOLEFTCLICK,
+ GUIOBJECT_SETNORIGHTCLICK,
+ GUIOBJECT_SETNOMOUSEMOVE,
+ GUIOBJECT_SETNOCONTEXTMENU,
+ GUIOBJECT_SETX1,
+ GUIOBJECT_SETY1,
+ GUIOBJECT_SETX2,
+ GUIOBJECT_SETY2,
+ GUIOBJECT_SETANCHOR,
+ GUIOBJECT_SETCURSOR,
+ GUIOBJECT_FITTOPARENT,
+ GUIOBJECT_USERDATA,
+#ifdef USEAPPBAR
+ GUIOBJECT_APPBAR,
+#endif
+ GUIOBJECT_TRANSLATE,
+ GUIOBJECT_NUMPARAMS
+ };
+
+
+};
+
+template <class T, const wchar_t XMLTAG[], char SVCNAME[]>
+class XuiObjectSvc : public svc_xuiObjectI
+{
+public:
+ static const wchar_t *xuisvc_getXmlTag() { return XMLTAG; }
+
+ int testTag(const wchar_t *xmltag)
+ {
+ if (!WCSICMP(xmltag, XMLTAG)) return 1;
+ return 0;
+ }
+ GuiObject *instantiate(const wchar_t *xmltag, ifc_xmlreaderparams *params = NULL)
+ {
+ if (testTag(xmltag))
+ {
+ T * obj = new T;
+ ASSERT(obj != NULL);
+ return obj->getGuiObject();
+ }
+ return NULL;
+ }
+ void destroy(GuiObject *g)
+ {
+ T *obj = static_cast<T *>(g->guiobject_getRootWnd());
+ delete obj;
+ }
+ static const char *getServiceName() { return SVCNAME; }
+};
+
+template <class T>
+class XuiObjectSvc2 : public svc_xuiObjectI
+{
+public:
+ static const wchar_t *xuisvc_getXmlTag() { return T::xuiobject_getXmlTag(); }
+ int testTag(const wchar_t *xmltag)
+ {
+ if (!WCSICMP(xmltag, T::xuiobject_getXmlTag())) return 1;
+ return 0;
+ }
+ GuiObject *instantiate(const wchar_t *xmltag, ifc_xmlreaderparams *params = NULL)
+ {
+ if (testTag(xmltag))
+ {
+ T * obj = new T;
+ ASSERT(obj != NULL);
+ return obj->getGuiObject();
+ }
+ return NULL;
+ }
+ void destroy(GuiObject *g)
+ {
+ T *obj = static_cast<T *>(g->guiobject_getRootWnd());
+ delete obj;
+ }
+ static const char *getServiceName() { return T::xuiobject_getServiceName(); }
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/itemlistwnd.cpp b/Src/Wasabi/api/wnd/wndclass/itemlistwnd.cpp
new file mode 100644
index 00000000..1ff97732
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/itemlistwnd.cpp
@@ -0,0 +1,286 @@
+#include "precomp.h"
+
+#include "itemlistwnd.h"
+#include "../../common/metatags.h"
+
+#include "../../studio/api.h"
+
+#include "../skinclr.h"
+#include "../../common/filename.h"
+
+#include "../../common/dragitemi.h"
+#include "../../common/contextmenu.h"
+
+#define NIFTY_OUTLINE
+
+static SkinColor current("wasabi.itemlist.outline.current");
+static SkinColor selborder("wasabi.itemlist.selborder");
+static SkinColor focus("wasabi.itemlist.outline.focus");
+
+ItemListColumn_MetaTag::ItemListColumn_MetaTag(const char *newtag, int centered, const char *label)
+ : ItemListColumn() {
+ if (label == NULL) label = newtag;
+ setLabel(label);
+ tag = newtag;
+ center = centered;
+ datatype = api->metadb_getMetaDataType(tag);
+}
+
+ItemListColumn_Callback::ItemListColumn_Callback(ItemListWnd *_parent, LPARAM _lparam, const char *name)
+: ItemListColumn(name)
+{
+ parent = _parent;
+ lparam = _lparam;
+}
+
+void ItemListColumn_Callback::render(int pos, const char *playstring, Canvas &c, RECT &r) {
+ parent->userRender(pos, playstring, c, r, lparam);
+}
+
+void ItemListColumn_Callback::columnToText(int pos, const char *playstring, char *str, int maxlen) {
+ parent->userColumnToText(pos, playstring, lparam, str, maxlen);
+}
+
+void ItemListColumn_MetaTag::render(int pos, const char *playstring, Canvas &canvas, RECT &r) {
+ char buf[4096]="";
+ if (api->metadb_getMetaData(playstring, tag, buf, 4096) <= 1) return;
+ api->metadb_renderData(&canvas, r, buf, datatype, center);
+}
+
+void ItemListColumn_MetaTag::columnToText(int pos, const char *playstring, char *str, int maxlen) {
+ api->metadb_getMetaData(playstring, tag, str, maxlen);
+}
+
+const char *ItemListColumn_MetaTag::getTag() {
+ return tag;
+}
+
+void ItemListColumn_Numbered::render(int pos, const char *playstring, Canvas &c, RECT &r) {
+ StringPrintf buf("%d.", pos+1);
+ c.textOutEllipsed(r.left, r.top, r.right - r.left, r.bottom-r.top, buf);
+}
+
+void ItemListColumn_Numbered::columnToText(int pos, const char *playstring, char *str, int maxlen) {
+ StringPrintf buf("%d", pos+1);
+ STRNCPY(str, buf, maxlen);
+}
+
+ItemListWnd::ItemListWnd() {
+ keep = NULL;
+ item_invalidate_border++;
+}
+
+ItemListWnd::~ItemListWnd() {
+ api->syscb_deregisterCallback(static_cast<MetaCallbackI *>(this));
+}
+
+int ItemListWnd::onInit() {
+
+ ITEMLISTWND_PARENT::onInit();
+
+ api->syscb_registerCallback(static_cast<MetaCallbackI *>(this));
+
+ return 1;
+}
+
+int ItemListWnd::insertColumn(ItemListColumn *column, int width, int pos) {
+ column->setWidth(width);
+ return ITEMLISTWND_PARENT::insertColumn(column, pos);
+}
+
+int ItemListWnd::onBeginDrag(int iItem) {
+
+ if (!wantAutoDrag()) return ITEMLISTWND_PARENT::onBeginDrag(iItem);
+
+ // add all the entries
+ int n, i, c = 0;
+ n = getNumItems();
+ if (n == 0) return 0; // empty list
+
+ ASSERT(keep == NULL);
+ keep = new PtrList<FilenameNC>();
+
+ // count up the items
+ for (i = 0; i < n; i++) {
+ if (getItemSelected(i)) { // expose all the pointers we can
+ LPARAM lparam = getItemData(i);
+ if (!addMoreDragTypes(i)) {
+ FilenameNC *fn = keep->addItem(new FilenameNC(convertlParam(lparam)));
+ addDragItem(DD_FILENAME, static_cast<Filename*>(fn));
+ }
+ c++;
+ }
+ }
+
+ if (keep->getNumItems() == 0 || c <= 0) {
+ delete keep; keep = NULL;
+ return 0;
+ }
+
+ handleDrag();
+
+ return 1;
+}
+
+int ItemListWnd::dragComplete(int success) {
+ ASSERT(keep != NULL);
+
+ keep->deleteAll();
+ delete keep; keep = NULL;
+
+ return 1;
+}
+
+int ItemListWnd::ownerDraw(Canvas *canvas, int pos, RECT *r, LPARAM lParam, int isselected, int isfocused) {
+ const char *playstring = convertlParam(lParam);
+ if (playstring == NULL) return 0;
+ COLORREF bgcolor = isfocused ? getFocusColor(lParam) : getSelBgColor(lParam);
+ COLORREF fgcolor = getTextColor(lParam);
+ int iscur = getSelected(lParam);
+
+ RECT box;
+ canvas->getClipBox(&box);
+
+ if (!getBgBitmap()) {
+ RECT r2 = *r;
+ r2.left = box.left;
+ RegionI *reg = new RegionI(&r2);
+ canvas->selectClipRgn(reg);
+ delete reg;
+ canvas->fillRect(r, getBgColor());
+ }
+
+ canvas->setTextColor(fgcolor);
+
+// ASSERT(cols.getNumItems() == getNumColumns());
+
+ if (isselected) {
+ RECT mr = *r;
+ canvas->fillRect(&mr, bgcolor);
+/*au gratin potatoes/broccoli
+chicken^2
+salad, croutons, cheese, ranch
+fries */
+#ifdef NIFTY_OUTLINE
+ int prevsel = getItemSelected(pos-1);
+ int nextsel = getItemSelected(pos+1);
+ mr.bottom--;
+ canvas->pushPen(selborder);
+ canvas->lineDraw(mr.left, mr.top, mr.left, mr.bottom);
+ canvas->lineDraw(mr.right-1, mr.top, mr.right-1, mr.bottom);
+ if (!prevsel) canvas->lineDraw(mr.left, mr.top, mr.right, mr.top);
+ if (!nextsel) canvas->lineDraw(mr.left, mr.bottom, mr.right, mr.bottom);
+ canvas->popPen();
+#endif
+ }
+
+ if (isfocused || iscur) {
+ int pentype = isfocused ? FALSE : TRUE;
+ int boxcolor = iscur ? current : focus;
+ canvas->drawRect(r, pentype, boxcolor);
+ }
+
+ canvas->pushTextSize(getFontSize());
+
+ int x = 1+r->left;
+ for (int i = 0; i < getNumColumns(); i++) {
+ ItemListColumn *col = (ItemListColumn *)enumListColumn(i);
+ RECT ir;
+ ir.left = x;
+ ir.right = x + getColumnWidth(i);
+ ir.top = r->top;
+ ir.bottom = r->bottom;
+ if (ir.right >= box.left && ir.bottom >= box.top && ir.left <= box.right && ir.top <= box.bottom) {
+ col->render(pos, playstring, *canvas, ir);
+ }
+ x = ir.right;
+ }
+ canvas->popTextSize();
+ return 1;
+}
+
+void ItemListWnd::convertlParamColumn(int col, int pos, LPARAM param, char *str, int maxlen) {
+ ASSERT(str != NULL);
+ ItemListColumn *cl = (ItemListColumn *)enumListColumn(col);
+ const char *playstring = convertlParam(param);
+ cl->columnToText(pos, playstring, str, maxlen);
+}
+
+
+int ItemListWnd::onContextMenu(int x, int y) {
+ PtrList<FilenameNC> filenames;
+ DragItemI *dragitem = NULL;
+
+ if ((dragitem = itemlistwnd_getDragItem(x, y)) == NULL) {
+ DragItemT<Filename> *di = new DragItemT<Filename>;
+ int n = getNumItems();
+ for (int i = 0; i < n; i++) {
+ if (getItemSelected(i)) {
+ LPARAM lparam = getItemData(i);
+ const char *playstring = convertlParam(lparam);
+ di->addDatum(filenames.addItem(new FilenameNC(playstring)));
+ }
+ }
+ dragitem = di;
+ }
+
+ ContextMenu cm(this, filenames.getNumItems() ? dragitem : NULL, false);
+
+ PtrList<DragItemI> drags;
+ for (int i = 0; ; i++) {
+ DragItemI *aitem = itemlistwnd_getSecondDragItem(i);
+ if (aitem == NULL) break;
+ drags.addItem(aitem);
+ if (cm.getNumCommands()) cm.addSeparator();
+ cm.addDragItem(aitem);
+ }
+ itemlistwnd_addCustomContextMenuCommands(&cm);
+ int r = cm.popAtMouse();
+ if (r < -10) itemlistwnd_contextMenuResult(r);
+ drags.deleteAll();
+
+ filenames.deleteAll();
+
+ delete dragitem;
+
+ return 1;
+}
+
+#if 0
+int ItemListWnd::onRightClick(int itemnum, int _x, int _y) {
+ // figure out which column they clicked on
+ int x, l = 0, r = 0;
+ for (int i = 0; i < cols.getNumItems(); i++) {
+ l = r;
+ r += getColumnWidth(i);
+ if (_x >= l && y <= r) break;
+ }
+ if (i >= cols.getNumItems()) return 0;
+ PlayItem *item = convertlParam(itemnum);
+ if (!allowEdition(item, cols[i]->getTag())) return 0;
+
+ return 0;
+}
+#endif
+
+void ItemListWnd::metacb_onItemChange(const char *playstring, const char *tag) {
+ int n = getNumItems();
+ for (int i = 0; i < n; i++) {
+ const char *ps = convertlParam(getItemData(i));
+ if (ps != NULL && STREQL(ps, playstring)) {
+ onItemChange(i, ps);
+ invalidateItem(i);
+ }
+ }
+}
+
+void ItemListWnd::metacb_onItemDel(const char *playstring) {
+ int n = getNumItems();
+ for (int i = 0; i < n; i++) {
+ const char *ps = convertlParam(getItemData(i));
+ if (ps != NULL && STREQL(ps, playstring)) {
+ onItemDel(i, ps);
+ invalidateItem(i);
+ }
+ }
+}
diff --git a/Src/Wasabi/api/wnd/wndclass/itemlistwnd.h b/Src/Wasabi/api/wnd/wndclass/itemlistwnd.h
new file mode 100644
index 00000000..b2245d9c
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/itemlistwnd.h
@@ -0,0 +1,426 @@
+//PORTABLE
+#ifndef _ITEMLIST_H
+#define _ITEMLIST_H
+
+#include "listwnd.h"
+#include "../canvas.h"
+#include "../named.h"
+#include "../ptrlist.h"
+#include "../string.h"
+#include "../../studio/metacb.h"
+
+class FilenameNC;
+class DragItemI;
+class ContextMenu;
+
+// this class just handles rendering the various properties of playitems
+// in a listwnd... the rest is up to you, just override the convert fn
+
+// abstract base class to render something in a column for a playstring
+
+/**
+ Class
+
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see
+*/
+class NOVTABLE ItemListColumn : public ListColumn {
+protected:
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ ItemListColumn(const wchar_t *name=NULL) : ListColumn(name) {}
+public:
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual ~ItemListColumn() {}
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void render(int pos, const wchar_t *playstring, Canvas &c, RECT &r)=0;
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+
+ virtual void columnToText(int pos, const wchar_t *playstring, wchar_t *str, int maxlen)=0;
+};
+
+#define ITEMLISTWND_PARENT ListWnd
+
+/**
+ Class
+
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see
+*/
+class ItemListWnd : public ListWnd, private MetaCallbackI {
+friend class ItemListColumn_Callback;
+public:
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ ItemListWnd();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual ~ItemListWnd();
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onInit();
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int insertColumn(ItemListColumn *column, int width, int pos=-1);
+
+protected:
+ // override and return 0 to suppress auto-dragging from window
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int wantAutoDrag() { return 1; }
+ // handles auto-adding all selected rows and calls addDragTypes
+ // so you can add more via addDragItem()
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onBeginDrag(int);
+ // if you return 0, the Filename version will be auto-added, otherwise not
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int addMoreDragTypes(int pos) { return 0; }
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int dragComplete(int success);
+
+ // tell ListWnd we do our own drawing
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int ownerDraw(Canvas *canvas, int pos, RECT *r, LPARAM lParam, int isselected, int isfocused);
+
+ // ItemListColumn_Callback calls this to do its rendering, lParam is what you
+ // gave it to pass back to you
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void userRender(int pos, const wchar_t *playstring, Canvas &c, RECT &r, LPARAM lParam) {}
+
+ // ItemListColumn_Callback calls this to get the column text, lParam is what you
+ // gave it to pass back to you
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void userColumnToText(int pos, const wchar_t *playstring, LPARAM lParam, wchar_t *str, int maxlen) {}
+
+ // override this to turn the ownerdraw into a playstring
+ virtual const wchar_t *convertlParam(LPARAM lParam)=0;
+ virtual void convertlParamColumn(int col, int pos, LPARAM lParam, wchar_t *str, int maxlen);
+
+ // override this and return 1 if you want a "current" box around item
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int getSelected(LPARAM lParam) { return 0; }
+
+// virtual int onRightClick(int itemnum, int x, int y);
+ // automatically generated context menu (uses Filename)
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onContextMenu(int x, int y);
+
+ // return optional DragItemI for context menu (will be deleted for you)
+ virtual DragItemI *itemlistwnd_getDragItem(int x, int y) { return NULL; }
+ virtual DragItemI *itemlistwnd_getSecondDragItem(int n) { return NULL; }
+ virtual void itemlistwnd_addCustomContextMenuCommands(ContextMenu *cm) { }
+ virtual void itemlistwnd_contextMenuResult(int res) { }
+
+ // return TRUE if it's ok to edit in place
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int allowEdition(const wchar_t *playstring, wchar_t *field) { return 0; }
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void resort() {
+ //TODO> implement me!
+ }
+
+protected:
+ // implement this if you want to know when an item's metadata changed
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void onItemChange(int pos, const wchar_t *playstring) { }
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void onItemDel(int pos, const wchar_t *playstring) { }
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void metacb_onItemChange(const wchar_t *playstring, const wchar_t *tag);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void metacb_onItemDel(const wchar_t *);
+
+private:
+ PtrList<FilenameNC> *keep;
+};
+
+// column class to ask ItemListWnd to do the rendering
+
+/**
+ Class
+
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see
+*/
+class ItemListColumn_Callback : public ItemListColumn {
+public:
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ ItemListColumn_Callback(ItemListWnd *_parent, LPARAM _lparam, const wchar_t *name=NULL);
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void render(int pos, const wchar_t *playstring, Canvas &c, RECT &r);
+ virtual void columnToText(int pos, const wchar_t *playstring, wchar_t *str, int maxlen);
+
+private:
+ ItemListWnd *parent;
+ LPARAM lparam;
+};
+
+// column class to render a metatag
+
+/**
+ Class
+
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see
+*/
+class ItemListColumn_MetaTag : public ItemListColumn {
+public:
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ ItemListColumn_MetaTag(const wchar_t *tag, int center=0, const wchar_t *label=NULL);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual ~ItemListColumn_MetaTag() {}
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void render(int pos, const wchar_t *playstring, Canvas &c, RECT &r);
+ virtual void columnToText(int pos, const wchar_t *playstring, wchar_t *str, int maxlen);
+
+ const wchar_t *getTag();
+
+private:
+ StringW tag;
+ int center;
+ int datatype;
+};
+
+// this just renders the position of the item, starting from 1
+
+/**
+ Class
+
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see
+ */
+class ItemListColumn_Numbered : public ItemListColumn {
+public:
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ ItemListColumn_Numbered(int _offset=0) : offset(_offset) {}
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void render(int pos, const wchar_t *playstring, Canvas &c, RECT &r);
+ virtual void columnToText(int pos, const wchar_t *playstring, wchar_t *str, int maxlen);
+
+private:
+ int offset;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/labelwnd.cpp b/Src/Wasabi/api/wnd/wndclass/labelwnd.cpp
new file mode 100644
index 00000000..d9aedd0f
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/labelwnd.cpp
@@ -0,0 +1,203 @@
+#include <precomp.h>
+
+#include "labelwnd.h"
+
+#include <api/locales/xlatstr.h>
+#include <api/wnd/paintsets.h>
+
+#include <tataki/canvas/bltcanvas.h>
+#include <tataki/color/skinclr.h>
+#include <api/wnd/notifmsg.h>
+#include <tataki/region/region.h>
+#include <api/wnd/PaintCanvas.h>
+
+static SkinColor labelfg(L"wasabi.labelwnd.foreground");
+static SkinColor labelbg(L"wasabi.labelwnd.background", L"Text backgrounds");
+
+#define DEF_LABEL_HEIGHT 0
+#define DEF_LABEL_FONTSIZE 16
+
+LabelWnd::LabelWnd() {
+ show_label = FALSE;
+ labelsize = DEF_LABEL_FONTSIZE;
+ labelHeight = 0;
+ margin=0;
+ setVirtual(0);
+}
+
+void LabelWnd::getClientRect(RECT *r) {
+ LABELWND_PARENT::getClientRect(r);
+ r->top += getLabelHeight();
+}
+
+int LabelWnd::onResize() {
+ LABELWND_PARENT::onResize();
+ invalidateLabel();
+/* if (getLabelHeight() <= 0) return 0;
+ RECT r,ir;
+ LABELWND_PARENT::getClientRect(&r);
+ LABELWND_PARENT::getNonClientRect(&ir);
+ ir.bottom = ir.top + getLabelHeight()+margin;
+ invalidateRect(&ir);*/
+ return 1;
+}
+
+int LabelWnd::onPaint(Canvas *canvas) {
+ if (getLabelHeight() <= 0) return LABELWND_PARENT::onPaint(canvas);
+
+ PaintBltCanvas paintcanvas;
+ if (canvas == NULL) {
+ if (!paintcanvas.beginPaintNC(this)) return 0;
+ canvas = &paintcanvas;
+ }
+
+ RECT r;
+ LabelWnd::getNonClientRect(&r);
+
+ if (canvas->isFixedCoords()) { // handle possible double buffer
+ // convert to canvas coords
+ r.right -= r.left; r.left = 0;
+ r.bottom -= r.top; r.top = 0;
+ }
+
+ r.bottom = r.top + getLabelHeight();
+
+ if (margin) {
+ r.left+=margin;
+ r.right-=margin;
+ r.bottom+=margin*2;
+ }
+
+ LABELWND_PARENT::onPaint(canvas);
+ int got_focus = gotFocus() || forceFocus();
+
+ if (wantRenderBaseTexture()) {
+ WASABI_API_WND->skin_renderBaseTexture(getBaseTextureWindow(), canvas, r, this);
+ }
+
+#ifdef WASABI_COMPILE_PAINTSETS
+ WASABI_API_WND->paintset_render(Paintset::LABEL, canvas, &r, got_focus ? 255 : 64);
+#endif
+ Wasabi::FontInfo fontInfo;
+ fontInfo.opaque=false;
+ fontInfo.pointSize = getLabelHeight()-1;
+ const wchar_t *name = getName();
+ if (name == NULL || *name == '\0')
+ name = L"Label";
+#define LEFTMARGIN 3
+ fontInfo.color = labelbg;
+ const wchar_t *xname = name;
+
+ switch(wantTranslation())
+ {
+ case 1:
+ xname = _(name);
+ break;
+ case 2:
+ xname = __(name);
+ break;
+ }
+
+ canvas->textOut(r.left+LEFTMARGIN+1, r.top+1, xname, &fontInfo);
+ fontInfo.color = labelfg;
+ canvas->textOut(r.left+LEFTMARGIN, r.top, xname, &fontInfo);
+
+ return 1;
+}
+
+void LabelWnd::onSetName() {
+ LABELWND_PARENT::onSetName();
+ // make sure label gets repainted
+ if (isInited()) {
+ RECT r;
+ LabelWnd::getNonClientRect(&r);
+ r.bottom = r.top + getLabelHeight();
+ invalidateRect(&r);
+ }
+}
+
+//CUTint LabelWnd::childNotify(api_window *child, int msg, intptr_t param1, intptr_t param2) {
+//CUT switch (msg) {
+//CUT case CHILD_WINDOWSHADE_CAPABLE: return show_label;
+//CUT case CHILD_WINDOWSHADE_ENABLE: return TRUE;
+//CUT }
+//CUT return LABELWND_PARENT::childNotify(child, msg, param1, param2);
+//CUT}
+
+int LabelWnd::showLabel(int show) {
+ show_label = show;
+ setFontSize(-1);
+ if (isPostOnInit()) {
+ onResize();
+ }
+ return 1;
+}
+
+int LabelWnd::getLabelHeight() {
+ return show_label ? labelHeight : 0;
+}
+
+void LabelWnd::setMargin(int newmargin) {
+ margin = newmargin;
+ RECT r;
+ getNonClientRect(&r);
+ r.bottom = getLabelHeight()+margin;
+ invalidateRect(&r);
+}
+
+int LabelWnd::onGetFocus() {
+ LABELWND_PARENT::onGetFocus();
+ invalidateLabel();
+ return 1;
+}
+
+int LabelWnd::onKillFocus() {
+ LABELWND_PARENT::onKillFocus();
+ invalidateLabel();
+ return 1;
+}
+
+void LabelWnd::invalidateLabel() {
+ if (labelHeight <= 0) return;
+ RECT ncr;
+ RECT cr;
+// RECT lr;
+ LabelWnd::getNonClientRect(&ncr);
+ LabelWnd::getClientRect(&cr);
+ RegionI nonClientRgn(&ncr);
+ RegionI clientRgn(&cr);
+ nonClientRgn.subtractRgn(&clientRgn);
+ invalidateRgn(&nonClientRgn);
+// SubtractRect(&lr, &ncr, &cr); // PORT ME
+// invalidateRect(&lr);
+}
+
+int LabelWnd::wantFocus() {
+ return (labelHeight > 0);
+}
+
+void LabelWnd::reloadResources()
+{
+ LABELWND_PARENT::reloadResources();
+ if (isPostOnInit())
+ onResize();
+ invalidateLabel();
+}
+
+int LabelWnd::setFontSize(int size)
+{
+ LABELWND_PARENT::setFontSize(size);
+ TextInfoCanvas blt(this);
+ Wasabi::FontInfo fontInfo;
+#ifndef WASABINOMAINAPI
+ fontInfo.pointSize = labelsize+api->metrics_getDelta();
+#else
+ fontInfo.pointSize = labelsize;
+ //MULTIAPI-FIXME: not handling delta
+#endif
+ labelHeight = blt.getTextHeight(&fontInfo) + 1;
+ invalidate();
+ if (isPostOnInit()) onResize();
+ return 1;
+}
+
diff --git a/Src/Wasabi/api/wnd/wndclass/labelwnd.h b/Src/Wasabi/api/wnd/wndclass/labelwnd.h
new file mode 100644
index 00000000..f6425514
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/labelwnd.h
@@ -0,0 +1,46 @@
+#ifndef _LABELWND_H
+#define _LABELWND_H
+
+#include <bfc/common.h>
+#include <api/wnd/wndclass/guiobjwnd.h>
+
+#define LABELWND_PARENT GuiObjectWnd
+class LabelWnd : public LABELWND_PARENT {
+protected:
+ LabelWnd();
+public:
+
+ virtual void getClientRect(RECT *);
+ virtual int onResize();
+ virtual int onPaint(Canvas *canvas);
+ virtual int onGetFocus();
+ virtual int onKillFocus();
+ virtual void invalidateLabel();
+ virtual int wantFocus();
+ virtual int wantRenderBaseTexture() { return 1; }
+
+ // override & return 1 to force painting label with focus all the time
+ virtual int forceFocus() { return 0; }
+
+ virtual void onSetName();
+ virtual void setMargin(int newmargin);
+
+ virtual int setFontSize(int size);
+
+//CUT virtual int childNotify(api_window *child, int msg, intptr_t param1=0, intptr_t param2=0);
+
+ int showLabel(int show);
+ int getLabelHeight();
+
+ void reloadResources();
+
+private:
+ int show_label, labelsize;
+ int labelHeight;
+ int margin;
+};
+
+// use this if you want a generic labelwnd (but try not to)
+class LabelWndI : public LabelWnd { };
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/listwnd.cpp b/Src/Wasabi/api/wnd/wndclass/listwnd.cpp
new file mode 100644
index 00000000..5da770be
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/listwnd.cpp
@@ -0,0 +1,2151 @@
+#pragma warning(disable:4355)
+
+#include <precomp.h>
+
+#include "listwnd.h"
+
+#include <bfc/wasabi_std.h>
+#include <api/wnd/usermsg.h>
+#include <bfc/ptrlist.h>
+#include <tataki/color/skinclr.h>
+#include <api/wnd/notifmsg.h>
+
+#include <bfc/assert.h>
+
+#include <api/locales/xlatstr.h>
+#include <api/wnd/accessible.h>
+#include <bfc/string/StringW.h>
+#include <new>
+#define DEF_TEXT_SIZE 14 // Default text size
+
+#define ITEMLIST_INC 4092
+#define LISTWND_DRAG_TIMERID 0x8972
+#define LISTWND_DRAG_MARGIN 12
+#define LISTWND_DRAG_TIMERDELAY 100
+#define DRAGSKIP_START 5
+
+#define X_SHIFT 2
+#define Y_SHIFT 2
+#define DRAG_THRESHOLD 4
+#define COLUMNS_DEFAULT_HEIGHT 12
+#define COLUMNS_DEFAULT_WIDTH 96
+#define COLUMNS_MARGIN 2
+#define COLUMNS_RESIZE_THRESHOLD 4
+#define COLUMNS_MIN_WIDTH 1
+#define COLSEPHEIGHT 1
+
+static SkinColor textColor(L"studio.list.text");// todo: have own color in skin.cpp
+static SkinColor bgcolor(L"studio.list.background");// todo: have own color in skin.cpp
+static SkinColor color_item_selected_fg(L"studio.list.item.selected.fg"); // RGB(0, 0, 128)
+static SkinColor color_item_selected(L"studio.list.item.selected"); // RGB(0, 0, 128)
+static SkinColor color_item_focused(L"studio.list.item.focused");// RGB(0, 128, 128)
+static SkinColor color_item_focusrect(L"studio.list.item.focused");// RGB(0, 128, 128)
+static SkinColor color_headers(L"studio.list.column.background");//RGB(0, 152, 208)
+static SkinColor columnTextColor(L"studio.list.column.text");
+static SkinColor columnSepColor(L"studio.list.column.separator");
+
+typedef struct
+{
+ wchar_t *label;
+ int column;
+} listSubitemStruct;
+
+class listItem
+{
+friend ListWnd;
+public:
+ ListWnd *getList() const { return listwnd; }
+protected:
+ listItem()
+ {
+ data = 0;
+ subitems = NULL;
+ listwnd = NULL;
+ }
+ ~listItem()
+ {
+ if (subitems != NULL)
+ {
+ for (int i=0;i<subitems->getNumItems();i++)
+ {
+ listSubitemStruct *subitem = subitems->enumItem(i);
+ if (subitem->label)
+ FREE(subitem->label);
+ }
+ subitems->freeAll();
+ delete subitems;
+ }
+ }
+ void setList(ListWnd *newlist) { listwnd=newlist; }
+
+ StringW label;
+ LPARAM data;
+ PtrList<listSubitemStruct> *subitems;
+ ListWnd *listwnd;
+ AutoSkinBitmap icon;
+};
+
+class CompareListItem {
+public:
+ static int compareItem(listItem *p1, listItem *p2);
+};
+
+int CompareListItem::compareItem(listItem *p1, listItem *p2) {
+ return p1->getList()->sortCompareItem(p1, p2);
+}
+
+
+XMLParamPair ListWnd::params[] = {
+ {LIST_ANTIALIAS, L"ANTIALIAS"},
+ {LIST_BACKGROUND, L"BACKGROUND"},
+ {LIST_TILE, L"TILE"},
+ {LIST_NOCOLHEADER, L"NOCOLHEADER"},
+};
+
+ListWnd::ListWnd()
+: selItemList(this)
+{
+ xuihandle = newXuiHandle();
+ CreateXMLParameters(xuihandle);
+
+ if (WASABI_API_SKIN->skin_getVersion() >= 1) {
+ textColor.setElementName(L"wasabi.list.text");
+ textColor.setColorGroup(L"");
+ bgcolor.setElementName(L"wasabi.list.background");
+ bgcolor.setColorGroup(L"");
+ color_item_selected_fg.setElementName(L"wasabi.list.text.selected");
+ color_item_selected_fg.setColorGroup(L"");
+ color_item_selected.setElementName(L"wasabi.list.text.selected.background");
+ color_item_selected.setColorGroup(L"");
+ color_headers.setElementName(L"wasabi.list.column.background");
+ color_headers.setColorGroup(L"");
+ columnTextColor.setElementName(L"wasabi.list.column.text");
+ columnTextColor.setColorGroup(L"");
+ columnSepColor.setElementName(L"wasabi.list.column.frame.bottom");
+ columnSepColor.setColorGroup(L"");
+ color_item_focused.setColorGroup(L"");
+ color_item_focusrect.setColorGroup(L"");
+ }
+ selectonupdown = 1;
+ setAutoSort(FALSE);
+ setOwnerDraw(FALSE);
+ setSortDirection(0);
+ setSortColumn(0);
+ lastcolsort=-1;
+ dragtimeron = 0;
+ dragskip = DRAGSKIP_START;
+ dragskipcount = 0;
+ item_invalidate_border = 0;
+
+ metrics_ok = FALSE;
+ setFontSize(DEF_TEXT_SIZE);
+ redraw = TRUE;
+ columnsHeight = COLUMNS_DEFAULT_HEIGHT;
+ lastItemFocused = NULL;
+ lastItemFocusedPos = -1;
+ lastAddedItem = NULL;
+ selectionStart = -1;
+ colresize = -1;
+ resizing_col = FALSE;
+ processbup = FALSE;
+ bdown = FALSE;
+ nodrag = FALSE;
+ showColumnsHeaders = TRUE;
+ rectselecting=0;
+ preventMultipleSelection = 0;
+//CUT autoresizecol0 = 0;
+ wantautodeselect = 1;
+ registerAcceleratorSection(L"listwnd");
+ hoverselect = 0;
+ firstItemVisible = -1;
+ lastItemVisible = -1;
+ showicons = 0;
+ iconWidth = -1; // If it's still negative use itemHeight instead -- better user getIconWidth()
+ iconHeight = -1;
+ antialias=1;
+ hasUserBg = false;
+}
+
+void ListWnd::CreateXMLParameters(int master_handle)
+{
+ //LISTWND_PARENT::CreateXMLParameters(master_handle);
+ int numParams = sizeof(params) / sizeof(params[0]);
+ hintNumberOfParams(xuihandle, numParams);
+ for (int i = 0;i < numParams;i++)
+ addParam(xuihandle, params[i], XUI_ATTRIBUTE_IMPLIED);
+}
+
+ListWnd::~ListWnd() {
+ deleteAllItems();
+ columnsList.deleteAll();
+ nodrag=FALSE;
+}
+
+int ListWnd::setXuiParam(int _xuihandle, int xmlattributeid, const wchar_t *xmlattributename, const wchar_t *value)
+{
+ if (_xuihandle != xuihandle)
+ return ScrlBkgWnd::setXuiParam(_xuihandle, xmlattributeid, xmlattributename, value);
+
+ switch (xmlattributeid)
+ {
+ case LIST_ANTIALIAS:
+ antialias = WTOI(value);
+ break;
+ case LIST_BACKGROUND:
+ {
+ SkinBitmap __bmp(value);
+ if (!__bmp.isInvalid())
+ {
+ this->setBgBitmap(value);
+ hasUserBg = true;
+ }
+ else
+ {
+ this->setBgBitmap(L"wasabi.list.background");
+ hasUserBg = false;
+ }
+ }
+ this->invalidate();
+ break;
+ case LIST_TILE:
+ this->wantTileBg = WTOI(value)?1:0;
+ this->invalidate();
+ break;
+ case LIST_NOCOLHEADER:
+ setShowColumnsHeaders(!WTOI(value));
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+int ListWnd::onInit() {
+
+ LISTWND_PARENT::onInit();
+
+ if (!hasUserBg) setBgBitmap(L"wasabi.list.background");
+ setLineHeight(getItemHeight());
+
+ return 1;
+}
+
+int ListWnd::onPostOnInit() {
+ LISTWND_PARENT::onPostOnInit();
+ recalcHeaders();
+ return 1;
+}
+
+int ListWnd::onPaint(Canvas *canvas)
+{
+
+ PaintCanvas paintcanvas;
+ PaintBltCanvas paintbcanvas;
+
+ if (canvas == NULL) {
+ if (needDoubleBuffer()) {
+ if (!paintbcanvas.beginPaintNC(this)) return 0;
+ canvas = &paintbcanvas;
+ } else {
+ if (!paintcanvas.beginPaint(this)) return 0;
+ canvas = &paintcanvas;
+ }
+ }
+
+ LISTWND_PARENT::onPaint(canvas);
+
+ RegionI clip;
+ canvas->getClipRgn(&clip);
+ api_region *orig;
+ orig = clip.clone();
+
+ drawColumnHeaders(canvas);
+
+ if (getColumnsHeight() > 0) {
+ RECT cr;
+ getClientRect(&cr);
+ cr.bottom = cr.top;
+ cr.top -= getColumnsHeight();
+ clip.subtractRect(&cr);
+ canvas->selectClipRgn(&clip);
+ }
+
+ firstItemVisible = -1;
+ lastItemVisible = -1;
+
+ //drawSubItems(canvas, x, &y, items, r.top, r.bottom, 0);
+ drawItems(canvas);
+
+ canvas->selectClipRgn(orig); // reset cliping region;
+
+ clip.disposeClone(orig);
+
+ return 1;
+}
+
+int ListWnd::onResize() {
+ LISTWND_PARENT::onResize();
+ recalcHeaders();
+ return 1;
+}
+
+int ListWnd::getNumItems(void) {
+ return itemList.getNumItems();
+}
+
+void ListWnd::drawItems(Canvas *canvas) {
+
+ RECT r, c;
+ getClientRect(&r);
+
+ RegionI clip;
+ if (!canvas->getClipRgn(&clip))
+ {
+ clip.setRect(&r);
+ }
+
+ if (GetClipBox(canvas->getHDC(), &c) == NULLREGION) {
+ getClientRect(&c);
+ }
+
+// DebugString("%d %d %d %d\n", c.left, c.top, c.right, c.bottom);
+
+// float f,l;
+ calcBounds();
+
+ //int first, last;
+
+/* RECT s=c;
+
+ s.bottom = min(s.bottom, r.bottom);
+ s.top = max(s.top, getLabelHeight()+(showColumnsHeaders ? getColumnsHeight() : 0));
+
+ f = ((float)(s.top - getLabelHeight() - (showColumnsHeaders ? getColumnsHeight() : 0) - getYShift() + getScrollY())) / (float)itemHeight;
+ l = ((float)(s.bottom - getLabelHeight() - (showColumnsHeaders ? getColumnsHeight() : 0) - getYShift() + getScrollY())) / (float)itemHeight;
+ first = (int)f;
+ first = max(0,first);
+ last = (int)l;
+ if ((float)((int)l) != l) {
+ last++;
+ }*/
+
+ int g=0;
+
+ for (int i=firstItemVisible;i<=lastItemVisible && i<itemList.getNumItems();i++) {
+ RECT ir={0,0,0,0};
+ getItemRect(i, &ir);
+ int a=ir.right;
+ ir.right = r.right;
+ if (!clip.doesIntersectRect(&ir))
+ continue;
+ ir.right=a;
+ g++;
+
+ LPARAM itemdata = getItemData(i);
+ int itemselected = getItemSelected(i);
+ int itemfocused = getItemFocused(i);
+
+ onPreItemDraw(canvas, i, &ir, itemdata, itemselected, itemfocused);
+
+ int sel = getItemSelected(i);
+ canvas->pushPen(PS_SOLID, 1, getColumnSepColor());
+
+ if (!ownerDraw(canvas, i, &ir, itemdata, itemselected, itemfocused))
+ {
+ Wasabi::FontInfo fontInfo;
+ fontInfo.antialias = getTextAntialias(itemdata);
+ fontInfo.bold = getTextBold(itemdata);
+ fontInfo.italic = !!getTextItalic(itemdata);
+ fontInfo.opaque = false;
+ fontInfo.color = sel ? getSelFgColor(itemdata) : getTextColor(itemdata);
+ fontInfo.pointSize = getFontSize();
+ int x = -getScrollX();
+ if (sel)
+ canvas->fillRect(&ir, getSelBgColor(itemdata));
+ if (getItemFocused(i))
+ canvas->fillRect(&ir, getFocusColor(itemdata));
+ if (needFocusRect(itemdata))
+ canvas->drawRect(&ir, 1, getFocusRectColor(itemdata));
+ if (showicons)
+ {
+ SkinBitmap *icon = getItemIcon(i);
+ if (icon)
+ {
+ RECT dst={x+X_SHIFT+r.left+1, ir.top+1, x+X_SHIFT+r.left+getIconWidth()+1, ir.top+getIconHeight()+1};
+ icon->stretchToRect(canvas, &dst);
+ }
+ x += getIconWidth()+1;
+ }
+ int xsep = wantColSepOnItems()?COLSEPHEIGHT:0;
+ for (int j=0;j<columnsList.getNumItems();j++) {
+ ListColumn *col = columnsList[j];
+ RECT cr=ir;
+ cr.left = x+X_SHIFT+r.left;
+ cr.right = cr.left + col->getWidth()-X_SHIFT*2+xsep;
+ if (j > 0 && wantColSepOnItems()) {
+ canvas->moveTo(x, ir.top);
+ canvas->lineTo(x, ir.top+getItemHeight());
+ }
+ switch (col->getAlignment()) {
+ case COL_LEFTALIGN:
+ canvas->textOutEllipsed(cr.left+2, cr.top, cr.right-cr.left-4, cr.bottom-cr.top, getSubitemText(i, j), &fontInfo);
+ break;
+ case COL_CENTERALIGN: {
+ RECT _cr = {cr.left+2, cr.top, cr.right-4, cr.bottom};
+ canvas->textOutCentered(&_cr, getSubitemText(i, j), &fontInfo);
+ break;
+ }
+ case COL_RIGHTALIGN: {
+ const wchar_t *txt = getSubitemText(i, j);
+ int __x = cr.left;
+ int __y = cr.top;
+ int fw = canvas->getTextWidth(txt, &fontInfo);
+ int aw = cr.right-cr.left-4;
+ __x -= fw-aw;
+ canvas->textOut(__x, __y, txt, &fontInfo);
+ break;
+ }
+ }
+ x += col->getWidth()+xsep;
+ }
+ if (wantColSepOnItems()) {
+ canvas->moveTo(x, ir.top);
+ canvas->lineTo(x, ir.top+getItemHeight());
+ }
+ }
+
+ canvas->popPen();
+ onPostItemDraw(canvas, i, &ir, itemdata, itemselected, itemfocused);
+ }
+/*
+ OutputDebugString("%d items draw\n", g);
+*/
+}
+
+int ListWnd::wantColSepOnItems() {
+ return 0;
+}
+
+int ListWnd::getXShift() {
+ if (wantColSepOnItems()) return X_SHIFT; else return 0;
+}
+
+int ListWnd::getFirstItemSelected() {
+ return getNextItemSelected(-1);
+}
+
+int ListWnd::getNextItemSelected(int lastpos) {
+ if (lastpos < -1) lastpos = -1;
+ for (int i=lastpos+1;i<itemList.getNumItems();i++)
+ if (getItemSelected(i))
+ return i;
+ return -1;
+}
+
+void ListWnd::calcBounds() {
+ lastComplete = TRUE;
+ firstComplete = TRUE;
+ float f,l;
+ RECT r;
+ getClientRect(&r);
+
+ f = ((float)(getScrollY()-Y_SHIFT) / getItemHeight());
+ l = ((float)(getScrollY()-Y_SHIFT+(r.bottom-r.top)) / getItemHeight()) - 1.0f;
+
+ firstItemVisible = (int)f;
+ lastItemVisible = (int)l;
+
+ if ((float)((int)l) != l) {
+ lastItemVisible++;
+ lastComplete = FALSE;
+ }
+ if ((float)((int)f) != f && f >= 0) {
+ firstComplete = FALSE;
+ }
+}
+
+// Draws tiled background
+void ListWnd::drawBackground(Canvas *canvas)
+{
+ LISTWND_PARENT::drawBackground(canvas);
+ drawColumnHeaders(canvas);
+}
+
+void ListWnd::drawColumnHeaders(Canvas *c)
+{
+ if (columnsList.getNumItems() == 0 || !showColumnsHeaders) return;
+
+ RECT r;
+ getClientRect(&r);
+ r.top -= getColumnsHeight();
+ r.bottom = r.top + getColumnsHeight();
+ if (renderRatioActive())
+ r.left -= (int)((double)getScrollX()*getRenderRatio());
+ else
+ r.left-=getScrollX();
+
+ c->fillRect(&r, color_headers);
+ int x = r.left + X_SHIFT/*+ 1*/;
+
+ if (showicons)
+ x += getIconWidth()+1 + 2;
+
+ Wasabi::FontInfo fontInfo;
+ fontInfo.color = columnTextColor;
+ fontInfo.opaque = false;
+ fontInfo.pointSize = getColumnsHeight();
+ c->pushPen(PS_SOLID, 1, getColumnSepColor());
+
+ for (int i=0;i<columnsList.getNumItems();i++)
+ {
+ ListColumn *col = columnsList[i];
+ int width = col->getWidth();
+ if (i > 0) {
+ c->moveTo(x, r.top);
+ c->lineTo(x, r.top+getColumnsHeight());
+ }
+ RECT ch;
+ ch.left = x+COLUMNS_MARGIN-((i==0)?X_SHIFT:0);
+ ch.top = r.top;
+ ch.right = ch.left + col->getWidth()-1-COLUMNS_MARGIN*2+((i==0)?X_SHIFT:0);
+ ch.bottom = ch.top + getColumnsHeight()-1;
+ col->customDrawHeader(c, &ch, &fontInfo);
+ x+=width/*+1*/;
+ }
+ c->moveTo(x, r.top);
+ c->lineTo(x, r.top+getColumnsHeight());
+ c->popPen();
+
+}
+
+ARGB32 ListWnd::getColumnSepColor() {
+ return columnSepColor;
+}
+
+int ListWnd::getHeaderHeight() {
+ return (showColumnsHeaders && columnsList.getNumItems() > 0) ? getColumnsHeight() : 0;
+}
+
+// Returns the current tree width in pixels
+int ListWnd::getContentsWidth() {
+ return getColumnsWidth()+X_SHIFT;
+}
+
+// Returns the current tree height in pixels
+int ListWnd::getContentsHeight() {
+ return itemList.getNumItems()*(getItemHeight()+(wantColSepOnItems()?COLSEPHEIGHT:0))+Y_SHIFT*2;
+}
+
+void ListWnd::setAutoSort(bool dosort) {
+ autosort = dosort;
+ itemList.setAutoSort(dosort);
+}
+
+void ListWnd::setOwnerDraw(bool doownerdraw) {
+ ownerdraw = doownerdraw;
+}
+
+int ListWnd::setFontSize(int size)
+{
+ LISTWND_PARENT::setFontSize(size);
+ if (size >= 0) textsize = size;
+ TextInfoCanvas c(this);
+ Wasabi::FontInfo fontInfo;
+ fontInfo.pointSize = getFontSize();
+ setItemHeight(c.getTextHeight(&fontInfo)+2, false);
+ redraw = TRUE;
+ metrics_ok = FALSE;
+ invalidate();
+ return 1;
+}
+
+int ListWnd::getFontSize() {
+#ifndef WASABINOMAINAPI
+ return textsize+api->metrics_getDelta();
+#else
+ //MULTIAPI-FIXME: not handling delta
+ return textsize;
+#endif
+}
+
+void ListWnd::onSetVisible(int show) {
+ LISTWND_PARENT::onSetVisible(show);
+ if (show) invalidate();
+}
+
+int ListWnd::fullyVisible(int pos) {
+ return (((lastComplete && pos <= lastItemVisible) || (!lastComplete && pos < lastItemVisible)) && ((firstComplete && pos >= firstItemVisible) || (!firstComplete && pos > firstItemVisible)));
+}
+
+void ListWnd::ensureItemVisible(int pos) {
+ if (pos >= itemList.getNumItems()) pos = itemList.getNumItems()-1;
+ if (pos < 0) pos = 0;
+ if (fullyVisible(pos)) return;
+
+ RECT c;
+ int y=pos*getItemHeight();
+ getClientRect(&c);
+ int showing_height = c.bottom - c.top;
+
+ if (getScrollY() < y) // scrolling up
+ y = (y - showing_height) + getItemHeight()*3;
+ else
+ y -= getItemHeight()*2;
+
+ if (y < 0) y = 0;
+ else if (y + showing_height > getContentsHeight()) {
+ // just show bottom pane
+ y = getContentsHeight()-showing_height;
+ }
+ scrollToY(y);
+}
+
+void ListWnd::scrollToItem(int pos) {
+ if (!isInited()) return;
+ scrollToY(Y_SHIFT+pos*(getItemHeight()+(wantColSepOnItems()?COLSEPHEIGHT:0)));
+}
+
+int ListWnd::getNumColumns() {
+ return columnsList.getNumItems();
+}
+
+ListColumn *ListWnd::getColumn(int n) {
+ return columnsList.enumItem(n);
+}
+
+int ListWnd::getColumnWidth(int c) {
+ ListColumn *col = columnsList[c];
+ ASSERT(col != NULL);
+ return col->getWidth();
+}
+
+int ListWnd::selectAll(int cb) {
+
+ int i;
+
+ if (preventMultipleSelection) return 1;
+
+ for (i=0;i<itemList.getNumItems();i++) {
+ selItemList.setSelected(i, TRUE, cb);
+ }
+
+ if (cb)
+ notifySelChanged();
+ return 1;
+}
+
+int ListWnd::deselectAll(int cb) {
+
+ int lif = getItemFocused();
+ if (lif != -1)
+ invalidateItem(lif);
+ lastItemFocused = NULL;
+
+ for (int i = 0; i < itemList.getNumItems(); i++) {
+ selItemList.setSelected(i, FALSE, cb);
+ }
+
+ if (cb)
+ notifySelChanged();
+ return 1;
+}
+
+void ListWnd::notifySelChanged(int item, int sel) {
+ if (!getRedraw()) return;
+ if (item == -1)
+ notifyParent(ChildNotify::LISTWND_SELCHANGED);
+ else
+ notifyParent(ChildNotify::LISTWND_ITEMSELCHANGED, item, sel);
+}
+
+int ListWnd::invertSelection(int cb) {
+ if (preventMultipleSelection) return 1;
+ for (int i = 0; i < itemList.getNumItems(); i++) {
+ toggleSelection(i, FALSE, cb);
+ }
+ return 1;
+}
+
+int ListWnd::invalidateItem(int pos) {
+ RECT r;
+ if (!isInited()) return 0;
+ int rv = getItemRect(pos, &r);
+ r.top -= item_invalidate_border;
+ r.bottom += item_invalidate_border;
+ if (rv)
+ invalidateRect(&r);
+ return rv;
+}
+
+int ListWnd::onLeftButtonDblClk(int x, int y) {
+ // check for column dblclick
+ int colhit;
+ if ((colhit = hitTestColumns(Wasabi::Std::makePoint(x, y))) >= 0) {
+ return onColumnDblClick(colhit, x, y);
+ }
+
+ if (itemList.getNumItems() == 0) return 0;
+ POINT p={x,y};
+ int i = hitTest(p);
+ if (i > -1) {
+ notifyParent(ChildNotify::LISTWND_DBLCLK, i, 0);
+ onDoubleClick(i);
+ return 1;
+ }
+ return 0;
+}
+
+int ListWnd::onRightButtonDown(int x, int y) {
+ nodrag=TRUE;
+ return 1;
+}
+
+int ListWnd::onRightButtonUp(int x, int y) {
+ nodrag=FALSE;
+ int i = hitTest(x,y);
+ if (i >= 0) { // did hit something
+ setItemFocused(i); // it always gets the focus
+ if (!getItemSelected(i)) { // reselect the item out of the cur selection
+ ListWnd::onLeftButtonDown(x,y); // don't call inherited!
+ ListWnd::onLeftButtonUp(x,y); // don't call inherited!
+ }
+ onRightClick(i);
+ } else {
+ if (wantAutoDeselect())
+ deselectAll();
+ }
+ onContextMenu(x,y);
+
+ return 1;
+}
+
+int ListWnd::onRightClick(int itemnum) {
+ return 0;
+}
+
+
+int ListWnd::onLeftButtonDown(int x, int y) {
+ if (colresize != -1) {
+ resizing_col = TRUE;
+ drawXorLine(colresizept.x);
+ }
+
+ processbup = FALSE;
+ bdown = TRUE;
+ bdownx = x;
+ bdowny = y;
+
+ if (!resizing_col) {
+
+ POINT p={x,y};
+ int i = hitTest(p);
+ if (i >= 0) {
+ if (Std::keyDown(VK_SHIFT)) {
+ if (getItemSelected(i))
+ processbup=TRUE;
+ else
+ setSelectionEnd(i);
+ } else
+ if (Std::keyDown(VK_CONTROL)) {
+ if (getItemSelected(i))
+ processbup=TRUE;
+ else
+ toggleSelection(i);
+ } else {
+ if (getItemSelected(i))
+ processbup = TRUE;
+ else
+ setSelectionStart(i);
+ }
+ } else {
+ if (wantAutoDeselect())
+ deselectAll();
+ /*rectselecting=1;
+ selectStart.x = x;
+ selectStart.y = y;
+ selectLast.x = x;
+ selectLast.y = y;
+ drawRect(selectStart.x, selectStart.y, x, y);
+ beginCapture();*/
+ }
+ }
+
+ return 1;
+}
+
+int ListWnd::onLeftButtonUp(int x, int y) {
+
+ bdown = FALSE;
+
+ if (resizing_col) {
+ resizing_col = FALSE;
+ drawXorLine(colresizept.x);
+ calcNewColWidth(colresize, colresizept.x);
+ recalcHeaders();
+ return 1;
+ }
+
+ // check for column label click
+ int colhit;
+ if ((colhit = hitTestColumnsLabel(Wasabi::Std::makePoint(x, y))) >= 0) {
+ ListColumn *lc = getColumn(colhit);
+ int ret = lc->onHeaderClick();
+ if (!ret) ret = onColumnLabelClick(colhit, x, y);
+ return ret;
+ }
+
+ POINT p={x,y};
+ int i = hitTest(p);
+
+ if (rectselecting || (processbup && !resizing_col) || hoverselect) {
+ if (i >= 0) {
+ if (Std::keyDown(VK_SHIFT)) {
+ if (getItemSelected(i))
+ setSelectionStart(i);
+ else
+ setSelectionEnd(i);
+ } else {
+ if (Std::keyDown(VK_CONTROL) || !wantAutoDeselect()) {
+ toggleSelection(i);
+ selectionStart = i;
+ } else {
+ setSelectionStart(i);
+ }
+ }
+ } else {
+/* if (rectselecting) {
+ drawRect(selectStart.x, selectStart.y, selectLast.x, selectLast.y);
+ endCapture();
+ rectselecting=0;
+ selectRect(selectStart.x, selectStart.y, x, y);
+ } else*/
+ if (wantAutoDeselect())
+ deselectAll();
+ }
+ }
+
+ if (i >= 0) {
+ int cn = hitTestColumnClient(x);
+ int r = 0;
+ if (cn >= 0) {
+ ListColumn *lc = getColumn(cn);
+ ASSERT(lc != NULL);
+ r = lc->onColumnLeftClick(i);
+ }
+ if (!r)
+ {
+ // Add 1px clickable border to our icon
+ if (x < getIconWidth()+2) r = onIconLeftClick(i,x,y-(i*getItemHeight()) - getHeaderHeight());
+ if (!r) onLeftClick(i);
+ }
+ }
+
+ return 1;
+}
+
+int ListWnd::onMouseMove(int x, int y) {
+ LISTWND_PARENT::onMouseMove(x,y);
+
+ if (!bdown && (Std::keyDown(MK_RBUTTON) || Std::keyDown(MK_RBUTTON))) {
+ bdown = TRUE;
+ processbup = TRUE;
+ _enterCapture();
+ }
+
+ if (!rectselecting && bdown && !resizing_col && !nodrag && (ABS(x-bdownx) >= 4 || ABS(y-bdowny) >= 4)) {
+ processbup = FALSE;
+ bdown = FALSE;
+ int i = hitTest(x, y);
+ if (i != -1) {
+ onBeginDrag(i);
+ return 1;
+ }
+ }
+
+/* if (rectselecting) {
+ drawRect(selectStart.x, selectStart.y, selectLast.x, selectLast.y);
+ selectLast.x = x;
+ selectLast.y = y;
+ drawRect(selectStart.x, selectStart.y, selectLast.x, selectLast.y);
+ return 1;
+ }*/
+
+ POINT p={x,y};
+ if (wantResizeCols()) {
+ if (!resizing_col) {
+ int c = hitTestColumns(p, &colresizeo);
+ if (c != -1) {
+ if (colresize != c) {
+ SetCursor(LoadCursor(NULL, IDC_SIZEWE)); // NONPORTABLE
+ if (!getCapture())
+ beginCapture();
+ colresize = c;
+ colresizept = p;
+ }
+ } else {
+ if (colresize != -1) {
+ SetCursor(LoadCursor(NULL, IDC_ARROW)); // NONPORTABLE
+ endCapture();
+ colresize = -1;
+ }
+ }
+ } else {
+ if (p.x + getScrollX() < colresizeo + COLUMNS_MIN_WIDTH) {
+ p.x = colresizeo + COLUMNS_MIN_WIDTH - getScrollX();
+ }
+ drawXorLine(colresizept.x);
+ colresizept = p;
+ drawXorLine(colresizept.x);
+ }
+ }
+
+ if (hoverselect) {
+ int i = hitTest(x, y);
+ if (i >= 0 && !getItemSelected(i)) {
+ deselectAll(0);
+ setSelected(i, 1, 0);
+ wchar_t t[256]=L"";
+ getItemLabel(i, 0, t, 255);
+ foreach(tempselectnotifies)
+ sendAction(tempselectnotifies.getfor(), L"tempselectnotify", t);
+ endfor;
+ }
+ }
+ return 1;
+}
+
+// NONPORTABLE / Todo: implement necessary stuff in canvas
+void ListWnd::drawXorLine(int x) {
+ HDC dc = GetDC(gethWnd());
+ HBRUSH brush = CreateSolidBrush(0xFFFFFF);
+ HPEN pen = CreatePen(PS_SOLID,0,0xFFFFFF);
+ HBRUSH oldB = (HBRUSH)SelectObject(dc, brush);
+ HPEN oldP = (HPEN)SelectObject(dc, pen);
+ int mix = SetROP2(dc,R2_XORPEN);
+
+ RECT r;
+ getClientRect(&r);
+ r.top -= getColumnsHeight();
+ r.bottom = r.top + getColumnsHeight();
+
+ if (renderRatioActive()) {
+ multRatio(&x);
+ multRatio(&r);
+ }
+
+ MoveToEx(dc, x, r.top, NULL);
+ LineTo(dc, x, r.bottom);
+
+ SelectObject(dc, oldB);
+ SelectObject(dc, oldP);
+ SetROP2(dc, mix);
+ DeleteObject(pen);
+ DeleteObject(brush);
+ ReleaseDC(gethWnd(), dc);
+}
+
+void ListWnd::calcNewColWidth(int c, int px) {
+ RECT r;
+ getClientRect(&r);
+ r.top -= getColumnsHeight();
+ r.bottom = r.top + getColumnsHeight();
+ px += getScrollX();
+ int x = r.left+X_SHIFT;
+ for (int i=0;i<columnsList.getNumItems();i++) {
+ ListColumn *col = columnsList[i];
+ if (col->getIndex() == c) {
+ int w = px - x;
+ col->setWidth(w);
+ setSlidersPosition();
+ return;
+ }
+ x += col->getWidth();
+ }
+ return;
+}
+
+int ListWnd::hitTestColumns(POINT p, int *origin) {
+ RECT r;
+ if (!showColumnsHeaders) return -1;
+ int best=-1, besto = 0, bestd=9999;
+ getClientRect(&r);
+ r.top -= getColumnsHeight();
+ r.bottom = r.top + getColumnsHeight();
+ p.x += getScrollX();
+ if (p.y > r.top && p.y < r.top + getColumnsHeight()) {
+ int x = r.left+X_SHIFT;
+ for (int i=0;i<columnsList.getNumItems();i++) {
+ ListColumn *col = columnsList[i];
+ x += col->getWidth();
+ if (p.x > x-COLUMNS_RESIZE_THRESHOLD && p.x < x+COLUMNS_RESIZE_THRESHOLD) {
+ int d = ABS(p.x-x);
+ if (d < bestd) {
+ bestd = d;
+ besto = x - col->getWidth();
+ best = col->getIndex();
+ }
+ }
+ }
+ }
+
+ if (best != -1)
+ if (origin != NULL) *origin = besto;
+ return best;
+}
+
+int ListWnd::hitTestColumnClient(int x) {
+ RECT cr = clientRect();
+ int x1 = cr.left+X_SHIFT;
+ foreach(columnsList)
+ int x2 = x1 + columnsList.getfor()->getWidth();
+ if (x >= x1 && x <= x2) return foreach_index;
+ x1 = x2;
+ endfor
+ return -1;
+}
+
+void ListWnd::invalidateColumns() {
+ RECT r;
+ getClientRect(&r);
+ r.top -= getColumnsHeight();
+ r.bottom = r.top + getColumnsHeight();
+ invalidateRect(&r);
+}
+
+int ListWnd::hitTestColumnsLabel(POINT p) {
+ RECT r;
+ if (!showColumnsHeaders) return -1;
+ getClientRect(&r);
+ r.top -= getColumnsHeight();
+ r.bottom = r.top + getColumnsHeight();
+ p.x += getScrollX();
+ if (p.y > r.top && p.y < r.top + getColumnsHeight()) {
+ int x = X_SHIFT;
+ for (int i=0;i<columnsList.getNumItems();i++) {
+ ListColumn *col = columnsList[i];
+ if (p.x >= x && p.x <= x+col->getWidth())
+ return i;
+ x += col->getWidth();
+ }
+ }
+ return -1;
+}
+
+void ListWnd::setSelectionStart(int pos, int wantcb) {
+ if (wantAutoDeselect())
+ deselectAll(wantcb);
+ if (!selItemList.isSelected(pos)) {
+ selItemList.setSelected(pos, TRUE, wantcb);
+ lastItemFocused = itemList[pos];
+ lastItemFocusedPos = pos;
+ invalidateItem(pos);
+ repaint();
+ }
+
+ selectionStart = pos;
+ notifySelChanged();
+}
+
+void ListWnd::setSelectionEnd(int pos) {
+
+ if (itemList.getNumItems() == 0) return;
+ if (selectionStart == -1) selectionStart = 0;
+
+ if (wantAutoDeselect())
+ deselectAll();
+
+ int inc = (selectionStart > pos) ? -1 : 1;
+ int i = selectionStart;
+
+ while (1) {
+ if (!selItemList.isSelected(i)) {
+ selItemList.setSelected(i, TRUE);
+ lastItemFocused = itemList[i];
+ lastItemFocusedPos = i;
+ invalidateItem(i);
+ }
+ if (i == pos) break;
+ i += inc;
+ }
+ notifySelChanged();
+}
+
+void ListWnd::setSelected(int pos, int selected, int cb) {
+ selItemList.setSelected(pos, selected, cb);
+}
+
+void ListWnd::toggleSelection(int pos, int setfocus, int cb) {
+ if (!selItemList.isSelected(pos)) {
+ selItemList.setSelected(pos, TRUE, cb);
+ if (setfocus) {
+ if (selItemList.getNumSelected() > 1) {
+ for (int i=0;i<itemList.getNumItems();i++)
+ if (selItemList.isSelected(i))
+ invalidateItem(i);
+ }
+ lastItemFocused = itemList[pos];
+ lastItemFocusedPos = pos;
+ }
+ } else {
+ selItemList.setSelected(pos, FALSE, cb);
+ if (setfocus) {
+ lastItemFocused = NULL;
+ lastItemFocusedPos = -1;
+ }
+ }
+
+ invalidateItem(pos);
+ if (cb)
+ notifySelChanged();
+}
+
+int ListWnd::onBeginDrag(int iItem) {
+ // nothing by default
+ lastItemFocused = NULL;
+ lastItemFocusedPos = -1;
+ invalidateItem(iItem);
+ return 0;
+}
+
+int ListWnd::dragOver(int x, int y, ifc_window *sourceWnd) {
+ int rt = LISTWND_PARENT::dragOver(x, y, sourceWnd);
+ if (dragtimeron) return rt;
+
+ POINT pos={x,y};
+ screenToClient(&pos);
+
+ int item = hitTest(pos);
+ if (item == LW_HT_BELOW || item == LW_HT_ABOVE) {
+ dragtimeron = 1;
+ dragskip = DRAGSKIP_START;
+ dragskipcount = DRAGSKIP_START-1; // start right away
+ setTimer(LISTWND_DRAG_TIMERID, LISTWND_DRAG_TIMERDELAY);
+ }
+ return rt;
+}
+
+void ListWnd::onDragTimer() {
+ POINT pos;
+ Wasabi::Std::getMousePos(&pos);
+ screenToClient(&pos);
+ int item = hitTest(pos);
+ if (item == LW_HT_BELOW || item == LW_HT_ABOVE) {
+ dragskipcount++;
+ if (dragskipcount >= dragskip) {
+ switch (item) {
+ case LW_HT_BELOW:
+ scrollDown();
+ break;
+ case LW_HT_ABOVE:
+ scrollUp();
+ break;
+ }
+ dragskipcount = 0;
+ if (dragskip > 0) dragskip--;
+ }
+ } else {
+ killTimer(LISTWND_DRAG_TIMERID);
+ dragtimeron = 0;
+ }
+}
+
+void ListWnd::timerCallback(int id) {
+ switch (id) {
+ case LISTWND_DRAG_TIMERID:
+ onDragTimer();
+ return;
+ }
+ LISTWND_PARENT::timerCallback(id);
+}
+
+void ListWnd::onSelectAll() {
+}
+
+void ListWnd::onDelete() {
+ // do nothing by default
+}
+
+void ListWnd::onDoubleClick(int itemnum) {
+ // do nothing by default
+}
+
+void ListWnd::onLeftClick(int itemnum) {
+ // do nothing by default
+}
+
+int ListWnd::onIconLeftClick (int itemnum, int x, int y)
+{
+ return 0;
+}
+
+void ListWnd::onSecondLeftClick(int itemnum) {
+ // do nothing by default
+}
+
+int ListWnd::scrollAbsolute(int x) {
+ scrollToX(x);
+ return getScrollX();
+}
+
+int ListWnd::scrollRelative(int x) {
+ scrollToX(getScrollX() + x);
+ return getScrollX();
+}
+
+int ListWnd::getItemFocused() {
+ if (lastItemFocused == NULL) return -1;
+ if (itemList[lastItemFocusedPos] == lastItemFocused)
+ return lastItemFocusedPos;
+ else {
+ lastItemFocusedPos = itemList.searchItem(lastItemFocused);
+ return lastItemFocusedPos;
+ }
+}
+
+void ListWnd::setItemFocused(int pos, int ensure_visible) {
+ invalidateItem(lastItemFocusedPos);
+ lastItemFocused = itemList[pos];
+ lastItemFocusedPos = -1;
+ if (lastItemFocused != NULL) lastItemFocusedPos = pos;
+ invalidateItem(lastItemFocusedPos);
+ if (ensure_visible) ensureItemVisible(pos);
+}
+
+int ListWnd::getItemRect(int pos, RECT *r) {
+ MEMSET(r, 0, sizeof(RECT));
+ if (pos < 0 || pos >= itemList.getNumItems()) return 0;
+ RECT cr={0,0,0,0};
+ getClientRect(&cr);
+ r->left = -getScrollX() + X_SHIFT + cr.left;
+ r->right = cr.left + getColumnsWidth();
+ if (showicons) r->right += getItemHeight();
+ r->top = -getScrollY() + pos * (getItemHeight() + (wantColSepOnItems() ? COLSEPHEIGHT : 0)) + Y_SHIFT + cr.top;
+ r->bottom = r->top + getItemHeight();
+
+ // clip!
+ if (r->top > cr.bottom || r->bottom < cr.top) return 0;
+
+ return 1;
+}
+
+int ListWnd::locateData(LPARAM data) { // linear search
+ for (int i=0;i<itemList.getNumItems();i++) {
+ if (itemList[i]->data == data)
+ return i;
+ }
+ return -1;
+}
+
+int ListWnd::getItemFocused(int pos) {
+ if (pos >= itemList.getNumItems()) return 0;
+ return getItemFocused() == pos;
+}
+
+int ListWnd::getItemSelected(int pos) {
+ listItem *item = itemList[pos];
+ return (item && selItemList.isSelected(pos));
+}
+
+int ListWnd::hitTest(POINT pos, int drag) {
+ RECT r;
+ getClientRect(&r);
+ if (pos.y < r.top) return LW_HT_ABOVE;
+ if (getScrollY() > 0 && drag && pos.y < r.top + LISTWND_DRAG_MARGIN) return LW_HT_ABOVE;
+ if (pos.y > r.bottom) return LW_HT_BELOW;
+ if (getContentsHeight() > (getScrollY() + r.bottom-r.top) && drag && pos.y > r.bottom - LISTWND_DRAG_MARGIN) return LW_HT_BELOW;
+
+ if (pos.x > r.left + getColumnsWidth() - getScrollX()) return LW_HT_DONTKNOW;
+ if (pos.x < r.left + getScrollX()) return LW_HT_DONTKNOW;
+
+ int i = (pos.y - r.top + getScrollY() - Y_SHIFT) / (getItemHeight() + (wantColSepOnItems() ? COLSEPHEIGHT : 0));
+ if (i >= itemList.getNumItems()) return LW_HT_DONTKNOW;
+ return i;
+}
+
+int ListWnd::hitTest(int x, int y, int drag) {
+ POINT pt={x, y};
+ return hitTest(pt, drag);
+}
+
+void ListWnd::selectRect(int x1, int y1, int x2, int y2) {
+
+}
+
+void ListWnd::drawRect(int x1, int y1, int x2, int y2) {
+ HDC dc = GetDC(gethWnd());
+ RECT r={x1,y1,x2,y2};
+ DrawFocusRect(dc, &r);
+ ReleaseDC(gethWnd(), dc);
+}
+
+LPARAM ListWnd::getItemData(int pos) {
+ if (pos >= itemList.getNumItems()) return 0;
+ listItem *item = itemList[pos];
+ if (item) return item->data;
+ return NULL;
+}
+
+int ListWnd::getItemLabel(int pos, int subpos, wchar_t *txt, int textmax)
+{
+ const wchar_t *t = getSubitemText(pos, subpos);
+ if (t)
+ {
+ WCSCPYN(txt, t, textmax);
+ return 1;
+ }
+ return 0;
+}
+
+void ListWnd::setItemLabel(int pos, const wchar_t *text)
+{
+ if (pos >= itemList.getNumItems()) return;
+ listItem *item = itemList[pos];
+ if (!item) return;
+ item->label = text;
+ invalidateItem(pos);
+}
+
+void ListWnd::resort() {
+ itemList.sort(TRUE);
+ invalidate();
+}
+
+int ListWnd::getSortDirection() {
+ return sortdir;
+}
+
+int ListWnd::getSortColumn() {
+ return sortcol;
+}
+
+void ListWnd::setSortDirection(int dir) {
+ sortdir=dir;
+}
+
+void ListWnd::setSortColumn(int col) {
+ sortcol=col;
+}
+
+int ListWnd::sortCompareItem(listItem *p1, listItem *p2)
+{
+ const wchar_t *l1=p1->label;
+ const wchar_t *l2=p2->label;
+
+ int i;
+
+ if(sortcol!=0)
+ {
+ if (p1->subitems != NULL)
+ {
+ for (i=0;i<p1->subitems->getNumItems();i++)
+ {
+ listSubitemStruct *subitem = p1->subitems->enumItem(i);
+ if (subitem->column == sortcol)
+ {
+ l1=subitem->label;
+ break;
+ }
+ }
+ } else {
+ l1 = L"";
+ }
+ if (p2->subitems != NULL) {
+ for (i=0;i<p2->subitems->getNumItems();i++) {
+ listSubitemStruct *subitem = p2->subitems->enumItem(i);
+ if (subitem->column == sortcol) {
+ l2=subitem->label;
+ break;
+ }
+ }
+ } else {
+ l2 = L"";
+ }
+ }
+
+ if(!columnsList.enumItem(sortcol)->getNumeric()) {
+ if(!sortdir) return(WCSICMP(l1, l2));
+ else return(WCSICMP(l2, l1));
+ } else {
+ int a=WTOI(l1),b=WTOI(l2);
+ if(!sortdir) return a-b;
+ else return b-a;
+ }
+}
+
+
+int ListWnd::findItemByParam(LPARAM param) {
+ for (int i=0;i<itemList.getNumItems();i++) {
+ if (itemList[i]->data == param)
+ return i;
+ }
+ return -1;
+}
+
+void ListWnd::setItemParam(int pos, LPARAM param) {
+ if (pos >= itemList.getNumItems()) return;
+ itemList[pos]->data = param;
+ invalidateItem(pos);
+}
+
+int ListWnd::deleteByPos(int pos) {
+ listItem *item = itemList[pos];
+ if (item == NULL) return 0;
+
+// selItemList.setSelected(pos, FALSE); // If you do not delete the item from the selItemList, you corrupt it for all item positions downstream of this one.
+ selItemList.deleteByPos(pos);
+
+ itemList.removeByPos(pos);
+
+ onItemDelete(item->data);
+
+ deleteListItem(item); item=NULL;
+
+ if (redraw) {
+ invalidate();
+ setSlidersPosition();
+ }
+ return 1;
+}
+
+void ListWnd::deleteAllItems() {
+ bool sav = getRedraw();
+ deselectAll();
+ setRedraw(FALSE);
+ selItemList.deselectAll(); //force desel so as to avoid the MEMCPY
+ while (itemList.getNumItems()) {
+ deleteByPos(0);
+ }
+ setRedraw(sav);
+// setSlidersPosition();
+}
+
+void ListWnd::setSubItem(int pos, int subpos, const wchar_t *txt)
+{
+ if (pos >= itemList.getNumItems()) return;
+ listItem *item = itemList[pos];
+ if (!item) return;
+ if (!item->subitems)
+ item->subitems = new PtrList<listSubitemStruct>;
+ for (int i=0;i<item->subitems->getNumItems();i++) {
+ listSubitemStruct *subitem = item->subitems->enumItem(i);
+ if (subitem->column == subpos) {
+ if (subitem->label) {
+ FREE(subitem->label);
+ subitem->label = NULL;
+ }
+ if (txt)
+ subitem->label = WCSDUP(txt);
+ invalidateItem(pos);
+ return;
+ }
+ }
+ listSubitemStruct *subitem = (listSubitemStruct *) MALLOC(sizeof(listSubitemStruct));
+ item->subitems->addItem(subitem);
+ subitem->label = WCSDUP(txt);
+ subitem->column = subpos;
+ invalidateItem(pos);
+}
+
+SkinBitmap *ListWnd::getItemIcon(int pos)
+{
+ if (pos >= itemList.getNumItems()) return NULL;
+ listItem *item = itemList[pos];
+ return item->icon;
+}
+
+void ListWnd::setItemIcon(int pos, const wchar_t *bitmapid) {
+ if (pos >= itemList.getNumItems()) return;
+ listItem *item = itemList[pos];
+ item->icon = bitmapid;
+ invalidateItem(pos);
+}
+
+const wchar_t *ListWnd::getSubitemText(int pos, int subpos) {
+ if (pos >= itemList.getNumItems()) return NULL;
+ listItem *item = itemList[pos];
+ if (!item) return NULL;
+ if (subpos == 0) {
+ return item->label;
+ }
+ if (!item->subitems) return NULL;
+ for (int i=0;i<item->subitems->getNumItems();i++) {
+ listSubitemStruct *subitem = item->subitems->enumItem(i);
+ if (subitem->column == subpos) {
+ return subitem->label;
+ }
+ }
+ return NULL;
+}
+
+listItem *ListWnd::createListItem() {
+ listItem *item = listItem_freelist.getRecord();
+ new(item) listItem();
+ item->setList(this);
+ return item;
+}
+
+void ListWnd::deleteListItem(listItem *item) {
+ if (item == NULL) return;
+ item->~listItem();
+ listItem_freelist.freeRecord(item);
+}
+
+ListColumn *ListWnd::enumListColumn(int pos) {
+ return columnsList[pos];
+}
+
+int ListWnd::getColumnPosByName(const wchar_t *name)
+{
+ for (int i = 0; i < columnsList.getNumItems(); i++)
+ {
+ const wchar_t *name2 = columnsList[i]->getName();
+ if (name2 == NULL) continue;
+ if (!wcscmp(name, name2)) return i;
+ }
+ return -1;
+}
+
+int ListWnd::delColumnByPos(int pos) {
+ if (pos < 0 || pos >= columnsList.getNumItems()) return 0;
+ delete columnsList[pos];
+ columnsList.removeByPos(pos);
+ recalcHeaders();
+ return 1;
+}
+
+void ListWnd::recalcHeaders() {
+ if (getNumColumns() <= 0) return;
+
+ int wid = 0, ndynamic = 0;
+ for (int i = 0; i < getNumColumns(); i++) {
+ ListColumn *col = enumListColumn(i);
+ if (!col->isDynamic()) wid += col->getWidth()+COLUMNS_MARGIN-1;
+ else ndynamic++;
+ }
+ if (ndynamic == 0) return;
+
+ RECT r = clientRect();
+ int wwidth = (r.right - r.left) - 2;
+
+ int leftover = wwidth - wid;
+ if (leftover <= 1) return;
+
+ leftover--;
+ leftover /= ndynamic;
+
+ for (int i = 0; i < getNumColumns(); i++) {
+ ListColumn *col = enumListColumn(i);
+ if (col->isDynamic()) col->setWidth(leftover);
+ }
+
+ //BU note: we could probably find a way to not invalidate everything
+ invalidate();
+}
+
+void ListWnd::itemSelection(int itemnum, int selected) {
+ notifySelChanged(itemnum, selected);
+ onItemSelection(itemnum, selected);
+}
+
+void ListWnd::onItemSelection(int itemnum, int selected) {
+ if (selected) {
+ Accessible *a = getAccessibleObject();
+ if (a != NULL)
+ a->onGetFocus(itemnum);
+ }
+}
+
+int ListWnd::doAddItem(const wchar_t *label, LPARAM lParam, int pos)
+{
+ listItem *item = createListItem();
+ item->label = label;
+ item->data = lParam;
+
+ itemList.addItem(item, pos, ITEMLIST_INC);
+ lastAddedItem = item;
+
+ if (redraw)
+ {
+ invalidate(); // todo: optimize to invalidate only if necessary
+ setSlidersPosition();
+ }
+
+ if (isInited()) calcBounds();
+ int p = (pos == POS_LAST) ? itemList.getNumItems()-1 : pos;
+ if (p <= selectionStart) selectionStart++;
+ if (autosort) {
+ itemList.sort();
+ p = itemList.searchItem(item);
+ }
+ return p;
+}
+
+void ListWnd::setMinimumSize(int size) {
+ if (size > 0) itemList.setMinimumSize(size);
+}
+
+int ListWnd::addItem(const wchar_t *label, LPARAM lParam)
+{
+ return doAddItem(label, lParam, POS_LAST);
+}
+
+int ListWnd::insertItem(int pos, const wchar_t *label, LPARAM lParam)
+{
+ return doAddItem(label, lParam, pos);
+}
+
+int ListWnd::getLastAddedItemPos() {
+ if (lastAddedItem == NULL) return -1;
+ return itemList.searchItem(lastAddedItem);
+}
+
+int ListWnd::getColumnsHeight() {
+ return columnsHeight;
+}
+
+int ListWnd::getColumnsWidth() {
+ int i, x=0;
+ for (i=0;i<columnsList.getNumItems();i++) x+= columnsList[i]->getWidth();
+ return x+1;
+}
+
+int ListWnd::insertColumn(ListColumn *col, int pos, int alignment)
+{
+ ASSERT(col != NULL);
+ ASSERT(pos >= -1);
+ if (pos < 0) col->setIndex(columnsList.getNumItems());
+ else col->setIndex(pos);
+ col->setList(this);
+ col->setAlignment(alignment);
+ columnsList.addItem(col);
+ if (pos >= 0) {
+ columnsList.moveItem(columnsList.getNumItems()-1, pos);
+ }
+ if (redraw && isInited()) {
+ invalidate();
+ setSlidersPosition();
+ }
+ recalcHeaders();
+ return columnsList.getNumItems();
+}
+
+void ListWnd::deleteAllColumns() {
+ columnsList.deleteAll();
+ if (redraw && isInited()) {
+ invalidate();
+ setSlidersPosition();
+ }
+ recalcHeaders();
+}
+
+int ListWnd::addColumn(const wchar_t *name, int width, int numeric, int align)
+{
+ ListColumn *col = new ListColumn();
+ col->setWidth(width);
+ col->setLabel(name);
+ col->setNumeric(numeric);
+ col->setAlignment(align);
+ return insertColumn(col, -1, align);
+}
+
+bool ListWnd::setRedraw(bool _redraw) {
+ bool prev = redraw;
+ if (!redraw && _redraw) {
+ invalidate();
+ setSlidersPosition();
+ notifySelChanged();
+ }
+ redraw = _redraw;
+ return prev;
+}
+
+bool ListWnd::getRedraw() {
+ return redraw;
+}
+
+int ListWnd::onChar(unsigned int c) {
+ //CT> Commented this out so shortcuts work in playlist editor
+ /*char b = TOUPPER(c);
+ if (b >= 'A' && b <= 'Z') {
+ jumpToNext(b);
+ return 1;
+ }*/
+
+ return LISTWND_PARENT::onChar(c);
+}
+
+int ListWnd::onKeyDown(int keyCode) {
+ switch (keyCode) {
+ case VK_DOWN:
+ next(selectonupdown);
+ return 1;
+ case VK_UP:
+ previous(selectonupdown);
+ return 1;
+ case VK_PRIOR:
+ pageup(selectonupdown);
+ return 1;
+ case VK_NEXT:
+ pagedown(selectonupdown);
+ return 1;
+ case VK_HOME:
+ home(selectonupdown);
+ return 1;
+ case VK_END:
+ end(selectonupdown);
+ return 1;
+ case VK_DELETE:
+ onDelete();
+ return 1;
+ case VK_RETURN: {
+ int i=getItemFocused();
+ //setSelected(i, 0, 0);
+ //setSelected(i, 1, 1);
+ if(i!=-1)
+ onDoubleClick(i);
+ return 1;
+ }
+ }
+ return LISTWND_PARENT::onKeyDown(keyCode);
+}
+
+void ListWnd::next(int wantcb) {
+ int from=getItemFocused();
+/* if (selItemList.getNumItems() > 0)
+ for (int i=0;i<itemList.getNumItems();i++)
+ if (getItemSelected(i)) {
+ from = i;
+ break;
+ }*/
+ int to = from + 1;
+ if (to < itemList.getNumItems() && to >= 0) {
+ setSelectionStart(to, wantcb);
+ if (!fullyVisible(to)) {
+ RECT c;
+ getClientRect(&c);
+ scrollToY((Y_SHIFT*2+(to+1)*(getItemHeight()+(wantColSepOnItems()?COLSEPHEIGHT:0)))-(c.bottom-c.top));
+ }
+ if (!wantcb)
+ {
+ wchar_t t[256]=L"";
+ getItemLabel(to, 0, t, 255);
+ foreach(tempselectnotifies)
+ sendAction(tempselectnotifies.getfor(), L"tempselectnotify", t);
+ endfor;
+ }
+ }
+}
+
+void ListWnd::selectCurrent() {
+ int from=getItemFocused();
+ int to = from;
+ if (to < itemList.getNumItems() && to >= 0) {
+ setSelectionStart(to);
+ if (!fullyVisible(to)) {
+ RECT c;
+ getClientRect(&c);
+ scrollToY((Y_SHIFT*2+(to+1)*(getItemHeight()+(wantColSepOnItems()?COLSEPHEIGHT:0)))-(c.bottom-c.top));
+ }
+ }
+}
+
+void ListWnd::selectFirstEntry(int wantcb) {
+ setSelectionStart(0, wantcb);
+ ensureItemVisible(0);
+}
+
+void ListWnd::previous(int wantcb) {
+ int from=0;
+/* if (selItemList.getNumItems() > 0)
+ for (int i=0;i<itemList.getNumItems();i++)
+ if (getItemSelected(i)) {
+ from = i;
+ break;
+ }*/
+ from = getItemFocused();
+ int to = from - 1;
+ if (to < itemList.getNumItems() && to >= 0) {
+ setSelectionStart(to, wantcb);
+ ensureItemVisible(to);
+ if (!wantcb) {
+ wchar_t t[256]=L"";
+ getItemLabel(to, 0, t, 255);
+ foreach(tempselectnotifies)
+ sendAction(tempselectnotifies.getfor(), L"tempselectnotify", t);
+ endfor;
+ }
+ }
+}
+
+void ListWnd::pagedown(int wantcb) {
+ int from=-1,to;
+ if (selItemList.getNumSelected())
+ for (int i=0;i<itemList.getNumItems();i++)
+ if (getItemSelected(i)) {
+ from = i;
+ break;
+ }
+ if(from==-1) to = 0;
+ else to = from + getLinesPerPage();
+ to=MIN(to,itemList.getNumItems()-1);
+ if(to>=0) {
+ setSelectionStart(to, wantcb);
+ if (!fullyVisible(to)) {
+ RECT c;
+ getClientRect(&c);
+ scrollToY((Y_SHIFT*2+(to+1)*(getItemHeight()+(wantColSepOnItems()?COLSEPHEIGHT:0)))-(c.bottom-c.top));
+ }
+ if (!wantcb) {
+ wchar_t t[256]=L"";
+ getItemLabel(to, 0, t, 255);
+ foreach(tempselectnotifies)
+ sendAction(tempselectnotifies.getfor(), L"tempselectnotify", t);
+ endfor;
+ }
+ }
+}
+
+void ListWnd::pageup(int wantcb) {
+ int from=-1,to;
+ if (selItemList.getNumSelected())
+ for (int i=0;i<itemList.getNumItems();i++)
+ if (getItemSelected(i)) {
+ from = i;
+ break;
+ }
+ if(from==-1) to = 0;
+ else to = from - getLinesPerPage();
+ to=MAX(to,0);
+ to=MIN(to,itemList.getNumItems()-1);
+ if(to>=0) {
+ setSelectionStart(to, wantcb);
+ ensureItemVisible(to);
+ if (!wantcb) {
+ wchar_t t[256]=L"";
+ getItemLabel(to, 0, t, 255);
+ foreach(tempselectnotifies)
+ sendAction(tempselectnotifies.getfor(), L"tempselectnotify", t);
+ endfor;
+ }
+ }
+}
+
+void ListWnd::home(int wantcb) {
+ if(!itemList.getNumItems()) return;
+ setSelectionStart(0, wantcb);
+ ensureItemVisible(0);
+ if (!wantcb) {
+ wchar_t t[256]=L"";
+ getItemLabel(0, 0, t, 255);
+ foreach(tempselectnotifies)
+ sendAction(tempselectnotifies.getfor(), L"tempselectnotify", t);
+ endfor;
+ }
+}
+
+void ListWnd::end(int wantcb) {
+ if(!itemList.getNumItems()) return;
+ int i=itemList.getNumItems()-1;
+ setSelectionStart(i, wantcb);
+ if (!fullyVisible(i)) {
+ RECT c;
+ getClientRect(&c);
+ scrollToY((Y_SHIFT*2+(i+1)*(getItemHeight()+(wantColSepOnItems()?COLSEPHEIGHT:0)))-(c.bottom-c.top));
+ }
+ if (!wantcb) {
+ wchar_t t[256]=L"";
+ getItemLabel(i, 0, t, 255);
+ foreach(tempselectnotifies)
+ sendAction(tempselectnotifies.getfor(), L"tempselectnotify", t);
+ endfor;
+ }
+}
+
+void ListWnd::jumpToNext(wchar_t c)
+{
+ if (doJumpToNext(c, FALSE)) return;
+ doJumpToNext(c, TRUE);
+}
+
+int ListWnd::doJumpToNext(wchar_t c, bool fromtop)
+{
+ int from = 0;
+ if (!fromtop && selItemList.getNumSelected())
+ {
+ for (int i=0;i<itemList.getNumItems();i++)
+ if (getItemSelected(i))
+ {
+ from = i+1;
+ break;
+ }
+ }
+ for (int j=from;j<itemList.getNumItems();j++)
+ {
+ listItem *item = itemList[j];
+ if (item->label != NULL) {
+ wchar_t z = TOUPPERW(*(item->label));
+ if (z == c)
+ {
+ setSelectionStart(j);
+ ensureItemVisible(j);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+void ListWnd::reset() {
+ columnsList.deleteAll();
+ deleteAllItems();
+}
+
+void ListWnd::setShowColumnsHeaders(int show) {
+ int prev = showColumnsHeaders;
+ showColumnsHeaders = !!show;
+ if (prev != show) {
+ invalidate();
+ }
+}
+
+int ListWnd::onContextMenu (int x, int y) {
+ return notifyParent(ChildNotify::LISTWND_POPUPMENU, x, y);
+}
+
+void ListWnd::scrollUp(int lines) {
+ scrollToY(MAX(0, getScrollY()-getItemHeight()*lines));
+}
+
+void ListWnd::scrollLeft(int lines) {
+ scrollToX(MAX(0, getScrollX()-getItemHeight()*lines));
+}
+
+void ListWnd::scrollDown(int lines) {
+ scrollToY(MIN(getMaxScrollY(), getScrollY()+getItemHeight()*lines));
+}
+
+void ListWnd::scrollRight(int lines) {
+ scrollToX(MIN(getMaxScrollX(), getScrollX()+getItemHeight()*lines));
+}
+
+int ListWnd::onMouseWheelUp(int clicked, int lines) {
+ lines *= Wasabi::Std::osparam_getScrollLines();
+ if (!clicked)
+ scrollUp(lines);
+ else
+ scrollLeft(lines);
+ return 1;
+}
+
+int ListWnd::onMouseWheelDown(int clicked, int lines) {
+ lines *= Wasabi::Std::osparam_getScrollLines();
+ if (!clicked)
+ scrollDown(lines);
+ else
+ scrollRight(lines);
+ return 1;
+}
+
+int ListWnd::onColumnLabelClick(int col, int x, int y)
+{
+ if(lastcolsort==col) {
+ setSortDirection(1);
+ lastcolsort=-1;
+ } else {
+ setSortDirection(0);
+ lastcolsort=col;
+ }
+ setSortColumn(col);
+ resort();
+ return 1;
+}
+
+ARGB32 ListWnd::getTextColor(LPARAM lParam) {
+ return textColor;
+}
+
+ARGB32 ListWnd::getSelBgColor(LPARAM LParam) {
+ return color_item_selected;
+}
+
+ARGB32 ListWnd::getSelFgColor(LPARAM LParam) {
+ ARGB32 r = color_item_selected_fg;
+ if (r == 0xFFFFFFFF)
+ return color_item_selected_fg;
+ return r;
+}
+
+ARGB32 ListWnd::getBgColor() {
+ return bgcolor;
+}
+
+ARGB32 ListWnd::getFocusColor(LPARAM LParam) {
+ return color_item_focused;
+}
+
+ARGB32 ListWnd::getFocusRectColor(LPARAM lParam) {
+ return color_item_focusrect;
+}
+
+
+void ListWnd::moveItem(int from, int to) {
+ itemList.moveItem(from,to);
+ invalidate();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// ListColumn
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+ListColumn::ListColumn(const wchar_t *name, int isdynamic)
+: NamedW(name), dynamic(isdynamic)
+{
+ align=COL_LEFTALIGN;
+ index = -1;
+ width = COLUMNS_DEFAULT_WIDTH;
+ list = NULL;
+ numeric = 0;
+}
+
+void ListColumn::setLabel(const wchar_t *newlabel) {
+ setName(newlabel);
+}
+
+const wchar_t *ListColumn::getLabel() {
+ return getName();
+}
+
+void ListColumn::setIndex(int newindex) {
+ index = newindex;
+}
+
+int ListColumn::getIndex() {
+ return index;
+}
+
+void ListColumn::setWidth(int _width) {
+ width = _width;
+ if (list && list->getRedraw()) {
+ list->invalidate();
+ }
+}
+
+int ListColumn::getWidth() {
+ return width;
+}
+
+int ListColumn::customDrawHeader(Canvas *c, RECT *r, const Wasabi::FontInfo *fontInfo)
+{
+ int y = (r->bottom-r->top-c->getTextHeight(fontInfo)) / 2;
+ c->textOutEllipsed(r->left, y, r->right-r->left, c->getTextHeight(fontInfo), _(getName()), fontInfo);
+ return 1;
+}
+
+void ListColumn::setDynamic(int isdynamic)
+{
+ int prev = dynamic;
+ dynamic = !!isdynamic;
+ if (prev != dynamic && dynamic && list != NULL)
+ list->recalcHeaders();
+}
+
+void ListColumn::setList(ListWnd *_list) {
+ list = _list;
+}
+
+ListWnd *ListColumn::getList() {
+ return list;
+}
+
+int ListWnd::wantAutoContextMenu() {
+ return 0;
+}
+
+int ListWnd::onAcceleratorEvent(const wchar_t *name) {
+ if(!_wcsicmp(name, L"selectall")) {
+ selectAll();
+ return 1;
+ }
+ return 0;
+}
+
+int ListWnd::onAction(const wchar_t *action, const wchar_t *param, int x, int y, intptr_t p1, intptr_t p2, void *data, size_t datalen, ifc_window *source) {
+ int r = LISTWND_PARENT::onAction(action, param, x, y, p1, p2, data, datalen, source);
+ if (WCSCASEEQLSAFE(action, L"register_tempselectnotify")) {
+ tempselectnotifies.addItem(source);
+ }
+ else if (WCSCASEEQLSAFE(action, L"up")) {
+ previous((int)p1);
+ }
+ else if (WCSCASEEQLSAFE(action, L"down")) {
+ next((int)p1);
+ }
+ else if (WCSCASEEQLSAFE(action, L"home")) {
+ home((int)p1);
+ }
+ else if (WCSCASEEQLSAFE(action, L"end")) {
+ end((int)p1);
+ }
+ else if (WCSCASEEQLSAFE(action, L"pageup")) {
+ pageup((int)p1);
+ }
+ else if (WCSCASEEQLSAFE(action, L"pagedown")) {
+ pagedown((int)p1);
+ }
+ else if (WCSCASEEQLSAFE(action, L"select_current")) {
+ selectCurrent();
+ }
+ else if (WCSCASEEQLSAFE(action, L"doubleclick")) {
+ int pos = getItemFocused();
+ if (pos >= 0) onDoubleClick(pos);
+ return 1;
+ }
+ return r;
+}
+
+void ListWnd::setShowIcons(int icons)
+{
+ showicons = icons;
+ invalidate();
+}
+
+int ListWnd::getShowIcons ()
+{
+ return showicons;
+}
+
+int ListWnd::getIconWidth ()
+{
+ // The old behaviour used the itemheight as value, so we return this for backwards compatibility if iconWidth is negative
+ return (iconWidth < 0 ? itemHeight-2 : iconWidth);
+}
+
+void ListWnd::setIconWidth (int width)
+{
+ iconWidth = width;
+ invalidate();
+}
+
+int ListWnd::getIconHeight ()
+{
+ // The old behaviour used the itemheight as value, so we return this for backwards compatibility if iconWidth is negative
+ return (iconHeight < 0 ? itemHeight-2 : iconHeight);
+}
+
+void ListWnd::setIconHeight (int height)
+{
+ iconHeight = height;
+ invalidate();
+}
+
+int ListWnd::getItemHeight ()
+{
+ return (itemHeight < getIconHeight()+2) ? getIconHeight()+2 : itemHeight;
+}
+
+void ListWnd::setItemHeight (int height, bool forceInvalidate /*true*/)
+{
+ itemHeight = height;
+ if (forceInvalidate) invalidate();
+} \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/wndclass/listwnd.h b/Src/Wasabi/api/wnd/wndclass/listwnd.h
new file mode 100644
index 00000000..018986ca
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/listwnd.h
@@ -0,0 +1,459 @@
+#ifndef _LISTWND_H
+#define _LISTWND_H
+
+#include <api/wnd/wndclass/scbkgwnd.h>
+#include <bfc/common.h>
+
+#include <bfc/freelist.h>
+#include "SelItemList.h"
+#define POS_LAST -1
+
+#define LISTWND_PARENT ScrlBkgWnd
+
+#define LW_HT_DONTKNOW (-1)
+#define LW_HT_ABOVE (-10)
+#define LW_HT_BELOW (-20)
+
+#define COL_LEFTALIGN 0
+#define COL_CENTERALIGN 1
+#define COL_RIGHTALIGN 2
+
+class listItem;
+class ListWnd;
+class CompareListItem;
+
+class ListColumn : public NamedW
+{
+friend class ListWnd;
+public:
+ ListColumn(const wchar_t *name=NULL, int isdynamic=FALSE);
+ virtual ~ListColumn() { }
+
+ int getWidth();
+ void setWidth(int newwidth);
+ const wchar_t *getLabel();
+ void setLabel(const wchar_t *newlabel);
+ virtual int customDrawHeader(Canvas *c, RECT *cr, const Wasabi::FontInfo *fontInfo);
+ virtual int onHeaderClick() { return 0; }//return 1 if you override
+ virtual int onColumnLeftClick(int pos) { return 0; }//return 1 if you override
+ int getNumeric() { return numeric; }
+ void setDynamic(int isdynamic);
+ int isDynamic() { return dynamic; }
+ void setAlignment(int _align) { align = _align; }
+ int getAlignment() { return align; }
+
+protected:
+ void setIndex(int i);
+ int getIndex();
+ void setList(ListWnd *list);
+ ListWnd *getList();
+
+ void setNumeric(int n) { numeric=n; }
+
+private:
+ int width;
+ int index;
+ int numeric;
+ int dynamic;
+ ListWnd *list;
+ int align;
+};
+
+//class SelItemList;
+
+
+
+class ListWnd : public ScrlBkgWnd
+{
+friend class ListColumn;
+friend class SelItemList;
+public:
+ ListWnd();
+
+ virtual ~ListWnd();
+ virtual int onInit();
+ virtual int onPostOnInit();
+ virtual int onPaint(Canvas *canvas);
+ virtual int onResize();
+ virtual int onLeftButtonDown(int x, int y);
+ virtual int onLeftButtonUp(int x, int y);
+ virtual int onRightButtonDown(int x, int y);
+ virtual int onRightButtonUp(int x, int y);
+ virtual int onMouseMove(int x, int y);
+ virtual int onLeftButtonDblClk(int x, int y);
+ virtual int onChar(unsigned int c);
+ virtual int onKeyDown(int keyCode);
+ virtual int onContextMenu (int x, int y);
+ virtual int wantAutoContextMenu();
+ virtual int onMouseWheelUp(int click, int lines);
+ virtual int onMouseWheelDown(int click, int lines);
+ virtual int wantAutoDeselect() { return wantautodeselect; }
+ virtual void setWantAutoDeselect(int want) { wantautodeselect = want; }
+
+ void onSetVisible(int show);
+
+ void setAutoSort(bool dosort);
+ void setOwnerDraw(bool doownerdraw);
+
+ virtual void timerCallback(int id);
+
+ void next(int wantcb=1);
+ void selectCurrent();
+ void selectFirstEntry(int wantcb=1);
+ void previous(int wantcb=1);
+ void pagedown(int wantcb=1);
+ void pageup(int wantcb=1);
+ void home(int wantcb=1);
+ void end(int wantcb=1);
+ void setItemCount(int c);
+ void reset();
+ void setShowColumnsHeaders(int show);
+ int addColumn(const wchar_t *name, int width, int numeric=0, int align=COL_LEFTALIGN); // adds to end
+ ListColumn *getColumn(int n);
+ int getNumColumns();
+ int getColumnWidth(int col);
+ bool setRedraw(bool redraw); // returns prev state
+ bool getRedraw();
+ void setMinimumSize(int size);
+ virtual int addItem(const wchar_t *label, LPARAM lParam);
+ virtual int insertItem(int pos, const wchar_t *label, LPARAM lParam);
+ virtual int getLastAddedItemPos();
+ virtual void setSubItem(int pos, int subpos, const wchar_t *txt);
+ virtual void deleteAllItems();
+ virtual int deleteByPos(int pos);
+ int getNumItems(void);
+
+ virtual int getItemLabel(int pos, int subpos, wchar_t *text, int textmax);
+ virtual void setItemLabel(int pos, const wchar_t *text);
+ virtual LPARAM getItemData(int pos);
+ virtual int getItemRect(int pos, RECT *r);
+ virtual int getItemSelected(int pos); // returns 1 if selected
+ virtual int getItemFocused(int pos); // returns 1 if focused
+ virtual int getItemFocused(); // returns focused item
+ void setItemFocused(int pos, int ensure_visible=TRUE);
+ void ensureItemVisible(int pos);
+ void invalidateColumns();
+ virtual int scrollAbsolute(int x);
+ virtual int scrollRelative(int x);
+ virtual void scrollLeft(int lines=1);
+ virtual void scrollRight(int lines=1);
+ virtual void scrollUp(int lines=1);
+ virtual void scrollDown(int lines=1);
+ virtual const wchar_t *getSubitemText(int pos, int subpos);
+
+
+ int getFirstItemSelected();
+
+
+ int getNextItemSelected(int lastpos); // next item AFTER given pos
+
+
+ virtual int selectAll(int cb=1); // force all items selected
+
+ virtual int deselectAll(int cb=1); // force all items to be deselected
+
+ virtual int invertSelection(int cb=1); // invert all selections
+
+ virtual int hitTest(POINT pos, int drag=0);
+
+ /**
+ Method
+
+ @see
+ @ret
+ */
+ virtual int hitTest(int x, int y, int drag=0);
+
+ /**
+ Method
+
+ @see
+ @ret
+ */
+ virtual int invalidateItem(int pos);
+ virtual int locateData(LPARAM data);
+
+ // -1 if we've never been drawn yet
+
+ /**
+ Method
+
+ @see
+ @ret
+ */
+ int getFirstItemVisible() const { return firstItemVisible; }
+
+ /**
+ Method
+
+ @see
+ @ret
+ */
+ int getLastItemVisible() const { return lastItemVisible; }
+
+ virtual int setFontSize(int size);
+
+ virtual int getFontSize();
+ virtual void jumpToNext(wchar_t c);
+ int wantFocus() { return 1; }
+ void scrollToItem(int pos);
+ virtual void resort();
+ int getSortDirection();
+
+ /**
+ Method
+
+ @see
+ @ret
+ */
+ int getSortColumn();
+
+ void setSortColumn(int col);
+
+ void setSortDirection(int dir);
+
+ int findItemByParam(LPARAM param);
+
+ void setItemParam(int pos, LPARAM param);
+
+ int getItemCount() { return getNumItems(); }
+
+ void setSelectionStart(int pos, int wantcb=1);
+
+ /**
+ Method
+
+ @see
+ @ret
+ */
+ virtual void setSelectionEnd(int pos);
+
+ void setSelected(int pos, int selected, int cb=1);
+ void toggleSelection(int pos, int setfocus=TRUE, int cb=1);
+ virtual int getHeaderHeight();
+
+ // this sort function just provides string/numeric comparison
+ // if you need more types, just override and provide your own
+
+ virtual int sortCompareItem(listItem *p1, listItem *p2);
+
+ int getPreventMultipleSelection() { return preventMultipleSelection; }
+ int setPreventMultipleSelection(int val) { return preventMultipleSelection = val; }
+ void moveItem(int from, int to);
+ virtual int onAcceleratorEvent(const wchar_t *name);
+
+ // override this to turn the LPARAM into a text
+ virtual const wchar_t *convertlParam(LPARAM lParam) { return NULL; }
+ virtual void convertlParamColumn(int col, int pos, LPARAM param, wchar_t *str, int maxlen) { };
+
+protected:
+ /*static */void CreateXMLParameters(int master_handle);
+
+ // return 1 if you override this
+
+ virtual int ownerDraw(Canvas *canvas, int pos, RECT *r, LPARAM lParam, int selected, int focused) { return 0; };
+ virtual void onPreItemDraw(Canvas *canvas, int pos, RECT *r, LPARAM lParam, int selected, int focused) { }
+ virtual void onPostItemDraw(Canvas *canvas, int pos, RECT *r, LPARAM lParam, int selected, int focused) { };
+ virtual ARGB32 getTextColor(LPARAM lParam);
+ int getTextAntialias(LPARAM lParam) { return antialias; }
+ virtual int getTextBold(LPARAM lParam) { return 0; }
+ virtual int getTextItalic(LPARAM lParam) { return 0; }
+ virtual ARGB32 getSelBgColor(LPARAM lParam);
+ virtual ARGB32 getSelFgColor(LPARAM lParam);
+ virtual ARGB32 getBgColor();
+ virtual ARGB32 getFocusColor(LPARAM lParam);
+ virtual ARGB32 getFocusRectColor(LPARAM lParam);
+ virtual int needFocusRect(LPARAM lParam) { return 0; }
+ virtual ARGB32 getColumnSepColor();
+ virtual int wantColSepOnItems();
+ virtual int getXShift();
+
+public:
+ int insertColumn(ListColumn *col, int pos=-1, int alignment=COL_LEFTALIGN);// -1 is add to end
+// void deleteColumn(int pos);
+ void deleteAllColumns();
+
+ void setHoverSelect(int a) { hoverselect = a; }
+ int getHoverSelect() { return hoverselect; }
+
+ void setSelectOnUpDown(int i) { selectonupdown = i; }
+ int getSelectOnUpDown() { return selectonupdown; }
+ virtual int onAction(const wchar_t *action, const wchar_t *param=NULL, int x=-1, int y=-1, intptr_t p1=0, intptr_t p2=0, void *data=NULL, size_t datalen=0, ifc_window *source=NULL);
+
+ /**
+ Method
+ Will only work with simple text lists, be forwarned!!!
+
+ @see
+ @ret
+ */
+ int getItemHeight();
+ void setItemHeight(int height, bool forceInvalidate = true);
+
+ int getIconWidth();
+ void setIconWidth(int width);
+ int getIconHeight();
+ void setIconHeight(int height);
+
+protected:
+
+ virtual int getColumnsHeight();
+ virtual int getColumnsWidth();
+ virtual int getContentsWidth();
+ virtual int getContentsHeight();
+
+ virtual void drawBackground(Canvas *canvas);
+
+ void drawColumnHeaders(Canvas *c);
+
+ void drawItems(Canvas *canvas);
+
+ void updateScrollX();
+
+ void updateScrollY();
+ int doJumpToNext(wchar_t c, bool fromTop);
+ int fullyVisible(int pos);
+
+ virtual int onBeginDrag(int iItem);
+
+
+ virtual int dragOver(int x, int y, ifc_window *sourceWnd);
+ virtual void onSelectAll(); // hit Control-A
+
+ virtual void onDelete(); // hit 'delete'
+
+ virtual void onItemDelete(LPARAM lparam) {}
+
+ virtual void onDoubleClick(int itemnum); // double-click on an item
+ // this is called with the selected item#
+
+ virtual void onLeftClick(int itemnum); // left-click
+ // the second time you click on an already-focused item
+
+ virtual void onSecondLeftClick(int itemnum);
+ // this is called once for the item under cursor on click
+
+ virtual int onRightClick(int itemnum); // right-click on item
+
+ virtual int onIconLeftClick(int itemnum, int x, int y); // Returns 1 if we should not invoke onLeftClick()
+
+ // override this to be notified of item selections & deselections
+
+ virtual void onItemSelection(int itemnum, int selected);
+
+ virtual int onColumnDblClick(int col, int x, int y) { return 0; }
+
+ virtual int onColumnLabelClick(int col, int x, int y);
+
+ void selectRect(int x1, int y1, int x2, int y2);
+
+ void drawRect(int x1, int y1, int x2, int y2);
+
+ // interface to Freelist
+
+ listItem *createListItem();
+ void deleteListItem(listItem *item);
+ ListColumn *enumListColumn(int pos);
+
+ int getColumnPosByName(const wchar_t *name);
+
+ int delColumnByPos(int pos);
+public: // Martin> dunno why these were protected...
+ void setShowIcons(int icons);
+ int getShowIcons(); // Maybe useful or not
+ SkinBitmap *getItemIcon(int item);
+ void setItemIcon(int pos, const wchar_t *bitmapid);
+
+protected:
+ int item_invalidate_border;
+ bool showColumnsHeaders;
+ void recalcHeaders();
+ void itemSelection(int itemnum, int selected);
+
+private:
+ int doAddItem(const wchar_t *label, LPARAM lParam, int pos);
+
+
+ int hitTestColumns(POINT p, int *origin=NULL);
+ int hitTestColumnClient(int x);
+ int hitTestColumnsLabel(POINT p);
+ void drawXorLine(int x);
+ void calcNewColWidth(int col, int x);
+ void calcBounds();
+ void onDragTimer();
+ void notifySelChanged(int item=-1, int sel=-1);
+ virtual int wantResizeCols() { return 1; }
+
+ int autosort, ownerdraw;
+ int textsize;
+ int itemHeight;
+ int iconWidth; // If it's still negative use itemHeight instead -- better user getIconWidth()
+ int iconHeight;
+ bool metrics_ok;
+ bool redraw;
+ int columnsHeight;
+ int dragtimeron;
+
+ int antialias;
+
+ PtrList<ListColumn> columnsList;
+ PtrListQuickSorted<listItem,CompareListItem> itemList;
+
+ int firstItemVisible;
+ int lastItemVisible;
+
+ listItem *lastItemFocused;
+ int lastItemFocusedPos;
+
+ listItem *lastAddedItem;
+ SelItemList selItemList;
+
+ int dragskip;
+ int dragskipcount;
+ int selectionStart;
+ int colresize;
+ POINT colresizept;
+ bool resizing_col;
+ int colresizeo;
+
+ bool processbup;
+ bool bdown;
+ bool nodrag;
+ int bdownx, bdowny;
+ bool firstComplete, lastComplete;
+
+ int rectselecting;
+ POINT selectStart;
+ POINT selectLast;
+
+ int sortdir, sortcol, lastcolsort;
+
+ int preventMultipleSelection;
+
+ Freelist<listItem> listItem_freelist;
+ int wantautodeselect;
+
+ int hoverselect;
+ int selectonupdown;
+ PtrList<ifc_window> tempselectnotifies;
+ StringW accessibleItemName;
+ int showicons;
+
+private:
+ /* XML Parameters */
+ static XMLParamPair params[];
+ int xuihandle;
+ bool hasUserBg;
+
+ enum
+ {
+ LIST_ANTIALIAS = 0,
+ LIST_BACKGROUND,
+ LIST_TILE,
+ LIST_NOCOLHEADER,
+ };
+ protected:
+ int setXuiParam(int xuihandle, int xmlattributeid, const wchar_t *xmlattributename, const wchar_t *value);
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/oswnd.cpp b/Src/Wasabi/api/wnd/wndclass/oswnd.cpp
new file mode 100644
index 00000000..021327ab
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/oswnd.cpp
@@ -0,0 +1,32 @@
+#include <precomp.h>
+#include "oswnd.h"
+
+int OSWnd::onInit()
+{
+ OSWND_PARENT::onInit();
+ onSetVisible(isVisible());
+ return 1;
+}
+
+void OSWnd::onSetVisible(int show)
+{
+#ifdef WIN32
+ ShowWindow(getOSHandle(), show ? SW_NORMAL : SW_HIDE);
+#endif
+}
+
+int OSWnd::onResize()
+{
+ OSWND_PARENT::onResize();
+#ifdef WIN32
+ if (getOSHandle())
+ {
+ RECT r;
+ getClientRect(&r);
+ SetWindowPos(getOSHandle(), NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+#endif
+ return 1;
+}
+
+
diff --git a/Src/Wasabi/api/wnd/wndclass/oswnd.h b/Src/Wasabi/api/wnd/wndclass/oswnd.h
new file mode 100644
index 00000000..7093dd6e
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/oswnd.h
@@ -0,0 +1,19 @@
+#ifndef __OSWND_H
+#define __OSWND_H
+
+#include <api/wnd/wndclass/guiobjwnd.h>
+
+#define OSWND_PARENT GuiObjectWnd
+
+class OSWnd : public OSWND_PARENT
+{
+public:
+ virtual int onInit();
+ virtual void onSetVisible(int show);
+ virtual int onResize();
+ virtual int handleRatio() { return 0; }
+
+ virtual HWND getOSHandle() = 0;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/oswndhost.cpp b/Src/Wasabi/api/wnd/wndclass/oswndhost.cpp
new file mode 100644
index 00000000..ab1a9680
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/oswndhost.cpp
@@ -0,0 +1,14 @@
+#include <precomp.h>
+#include "oswndhost.h"
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+#define CBCLASS OSWndHostI
+START_DISPATCH;
+ VCB(OSWNDHOST_OSWNDHOST_HOST, oswndhost_host);
+ VCB(OSWNDHOST_OSWNDHOST_UNHOST, oswndhost_unhost);
+ VCB(OSWNDHOST_OSWNDHOST_SETREGIONOFFSETS, oswndhost_setRegionOffsets);
+END_DISPATCH;
+
+
diff --git a/Src/Wasabi/api/wnd/wndclass/oswndhost.h b/Src/Wasabi/api/wnd/wndclass/oswndhost.h
new file mode 100644
index 00000000..8e7503e5
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/oswndhost.h
@@ -0,0 +1,53 @@
+#ifndef __OSWNDHOST_H
+#define __OSWNDHOST_H
+
+#include <bfc/dispatch.h>
+
+// {7050AACF-2731-4319-AF32-4ECE4CC8BDC4}
+static const GUID osWndHostGuid =
+ { 0x7050aacf, 0x2731, 0x4319, { 0xaf, 0x32, 0x4e, 0xce, 0x4c, 0xc8, 0xbd, 0xc4 } };
+
+
+class OSWndHost : public Dispatchable
+{
+public:
+ void oswndhost_host(HWND oswnd);
+ void oswndhost_unhost();
+ void oswndhost_setRegionOffsets(RECT *r);
+
+ DISPATCH_CODES
+ {
+ OSWNDHOST_OSWNDHOST_HOST = 0,
+ OSWNDHOST_OSWNDHOST_UNHOST = 5,
+ OSWNDHOST_OSWNDHOST_SETREGIONOFFSETS = 10,
+ };
+};
+
+inline void OSWndHost::oswndhost_host(HWND oswnd)
+{
+ _voidcall(OSWNDHOST_OSWNDHOST_HOST, oswnd);
+}
+
+inline void OSWndHost::oswndhost_unhost()
+{
+ _voidcall(OSWNDHOST_OSWNDHOST_UNHOST);
+}
+
+inline void OSWndHost::oswndhost_setRegionOffsets(RECT *r)
+{
+ _voidcall(OSWNDHOST_OSWNDHOST_SETREGIONOFFSETS, r);
+}
+
+class OSWndHostI : public OSWndHost
+{
+public:
+ virtual void oswndhost_host(HWND oswnd) = 0;
+ virtual void oswndhost_unhost() = 0;
+ virtual void oswndhost_setRegionOffsets(RECT *r) = 0;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/qpaintwnd.cpp b/Src/Wasabi/api/wnd/wndclass/qpaintwnd.cpp
new file mode 100644
index 00000000..dfdccc18
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/qpaintwnd.cpp
@@ -0,0 +1,357 @@
+#include <precomp.h>
+#include "qpaintwnd.h"
+#include <tataki/canvas/bltcanvas.h>
+#include "../nu/threadpool/TimerHandle.hpp"
+
+#define TIMER_QUICKPAINT 0x650
+
+// thread context, this is here so we can avoid the windows types in quickpaintwnd.h
+class QuickPaintContext
+{
+public:
+ QuickPaintContext(QuickPaintWnd *_wnd, int timeout)
+ {
+ killswitch = 0;
+ wnd = _wnd;
+ death = CreateEvent(NULL, FALSE, FALSE, NULL);
+ timer_ms = timeout;
+ WASABI_API_THREADPOOL->AddHandle(0, timer_handle, QPThreadPoolFunc, (void *)this, 0, 0/*api_threadpool::FLAG_LONG_EXECUTION*/);
+ timer_handle.Wait(timer_ms);
+ }
+
+ ~QuickPaintContext()
+ {
+ CloseHandle(death);
+ timer_handle.Close();
+ }
+
+ void Kill()
+ {
+ InterlockedExchangePointer((volatile PVOID*)&wnd, 0);
+ killswitch=1;
+ WaitForSingleObject(death, INFINITE);
+ }
+
+ QuickPaintWnd *wnd;
+ TimerHandle timer_handle;
+ HANDLE death;
+ volatile int killswitch;
+ int timer_ms;
+ static int QPThreadPoolFunc(HANDLE h, void *user_data, intptr_t t);
+};
+
+int QuickPaintContext::QPThreadPoolFunc(HANDLE h, void *user_data, intptr_t t)
+{
+ QuickPaintContext *context = (QuickPaintContext *)user_data;
+
+ if (context->killswitch)
+ {
+ WASABI_API_THREADPOOL->RemoveHandle(0, h);
+ SetEvent(context->death);
+ }
+ else
+ {
+ DWORD start = GetTickCount();
+ QuickPaintWnd *wnd = 0;
+ InterlockedExchangePointer((volatile PVOID*)&wnd, context->wnd);
+ if (wnd)
+ {
+ wnd->quickPaint();
+ TimerHandle timer_handle(h);
+ DWORD end = GetTickCount();
+ if (end-start > (DWORD)context->timer_ms)
+ timer_handle.Wait(1);
+ else
+ timer_handle.Wait(context->timer_ms - (end - start));
+ }
+ }
+
+ return 0;
+}
+
+
+// -----------------------------------------------------------------------
+QuickPaintWnd::QuickPaintWnd()
+{
+ invalidates_required = 0;
+ realtime = 1;
+ canvas_w = -1;
+ canvas_h = -1;
+ timerset = 0;
+ speed = 25;
+ enabled = 0;
+ render_canvas1 = NULL;
+ render_canvas2 = NULL;
+ paint_canvas = NULL;
+ thread_context = 0;
+
+ while (1)
+ {
+ svc_skinFilter *obj = sfe.getNext();
+ if (!obj) break;
+ filters.addItem(obj);
+ }
+ invalidated = 0;
+}
+
+// -----------------------------------------------------------------------
+QuickPaintWnd::~QuickPaintWnd()
+{
+ foreach(filters)
+ sfe.release(filters.getfor());
+ endfor;
+
+ KillThread();
+
+ delete render_canvas1;
+ delete render_canvas2;
+}
+
+// -----------------------------------------------------------------------
+void QuickPaintWnd::setRealtime(int rt)
+{
+ realtime = rt;
+}
+
+// -----------------------------------------------------------------------
+int QuickPaintWnd::getRealtime() const
+{
+ return realtime;
+}
+
+// -----------------------------------------------------------------------
+void QuickPaintWnd::setSpeed(int ms)
+{
+ speed = ms;
+ if (enabled && timerset)
+ {
+ if (thread_context)
+ thread_context->timer_ms = ms;
+ // let it change the timer value on the invalidate() timer
+ killTimer(TIMER_QUICKPAINT);
+ setTimer(TIMER_QUICKPAINT, getSpeed());
+ }
+}
+
+// -----------------------------------------------------------------------
+void QuickPaintWnd::startQuickPaint()
+{
+ enabled = 1;
+ if (!isInited()) return;
+ CreateRenderThread();
+ timerset=1;
+}
+
+// -----------------------------------------------------------------------
+void QuickPaintWnd::stopQuickPaint()
+{
+ enabled = 0;
+ if (!isInited()) return;
+ KillThread();
+ timerset=0;
+}
+
+// -----------------------------------------------------------------------
+int QuickPaintWnd::isQuickPainting()
+{
+ return enabled;
+}
+
+// -----------------------------------------------------------------------
+int QuickPaintWnd::getSpeed()
+{
+ return speed;
+}
+
+// -----------------------------------------------------------------------
+int QuickPaintWnd::onInit()
+{
+ QUICKPAINTWND_PARENT::onInit();
+ if (enabled)
+ {
+ ASSERT(!thread_context);
+ CreateRenderThread();
+ timerset = 1;
+ }
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+void QuickPaintWnd::timerCallback(int id)
+{
+ switch (id)
+ {
+ case TIMER_QUICKPAINT:
+ if (invalidates_required)
+ {
+ invalidated = 1;
+
+ if (getRealtime() && isVisible() && !isMinimized())
+ cascadeRepaint();
+ else
+ invalidate();
+
+ InterlockedExchange(&invalidates_required, 0);
+ }
+ //quickPaint();
+ break;
+ default:
+ QUICKPAINTWND_PARENT::timerCallback(id);
+ }
+}
+
+void QuickPaintWnd::SetPaintingCanvas(BltCanvas *c)
+{
+ InterlockedExchangePointer((volatile PVOID*)&paint_canvas, c);
+}
+
+BltCanvas *&QuickPaintWnd::GetDrawingConvas()
+{
+ if (paint_canvas == render_canvas2)
+ return render_canvas1;
+ else
+ return render_canvas2;
+}
+
+// -----------------------------------------------------------------------
+int QuickPaintWnd::quickPaint()
+{
+ int repaint=0;
+
+ int w, h;
+ getQuickPaintSize(&w, &h);
+
+ if (wantEvenAlignment())
+ {
+ if (w & 1) w++;
+ if (h & 1) h++;
+ }
+
+ if (w == 0 && h == 0) return 0;
+
+ BltCanvas *&render_canvas = GetDrawingConvas();
+ int newone = 0;
+
+ if (canvas_w != w || canvas_h != h)
+ {
+ delete render_canvas1; render_canvas1=0;
+ delete render_canvas2; render_canvas2=0;
+ }
+
+ if (!render_canvas)
+ {
+ render_canvas = new BltCanvas(w, wantNegativeHeight() ? -h : h, getOsWindowHandle());
+ canvas_w = w;
+ canvas_h = h;
+ newone = 1;
+ }
+
+ repaint = onQuickPaint(render_canvas, canvas_w, canvas_h, newone);
+
+ SetPaintingCanvas(render_canvas);
+ if (repaint)
+ InterlockedIncrement(&invalidates_required);
+
+ return repaint;
+}
+
+// -----------------------------------------------------------------------
+void QuickPaintWnd::getQuickPaintSize(int *w, int *h)
+{
+ RECT r;
+ getClientRect(&r);
+ if (w) *w = r.right - r.left;
+ if (h) *h = r.bottom - r.top;
+}
+
+// -----------------------------------------------------------------------
+void QuickPaintWnd::getQuickPaintSource(RECT *r)
+{
+ ASSERT(r != NULL);
+ r->left = 0;
+ r->right = canvas_w;
+ r->top = 0;
+ r->bottom = canvas_h;
+}
+
+// -----------------------------------------------------------------------
+void QuickPaintWnd::getQuickPaintDest(RECT *r)
+{
+ ASSERT(r != NULL);
+ getClientRect(r);
+}
+
+// -----------------------------------------------------------------------
+void QuickPaintWnd::onSetVisible(int show)
+{
+ QUICKPAINTWND_PARENT::onSetVisible(show);
+ if (!show)
+ {
+ if (timerset)
+ {
+ KillThread();
+ timerset = 0;
+ }
+ }
+ else
+ {
+ if (enabled && !timerset)
+ {
+ CreateRenderThread();
+
+ timerset = 1;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+int QuickPaintWnd::onPaint(Canvas *canvas)
+{
+ QUICKPAINTWND_PARENT::onPaint(canvas);
+
+ if (!enabled) return 1;
+
+ BltCanvas *render_canvas;
+ InterlockedExchangePointer((volatile PVOID*)&render_canvas, paint_canvas);
+ if (!render_canvas) return 1;
+
+ RECT r;
+ getQuickPaintDest(&r);
+ RECT sr;
+ getQuickPaintSource(&sr);
+
+ if (invalidated && wantFilters())
+ {
+ foreach(filters)
+ filters.getfor()->filterBitmap((unsigned char *)render_canvas->getBits(), canvas_w, canvas_h, 32, NULL, getFiltersGroup());
+ endfor;
+ invalidated = 0;
+ }
+
+ render_canvas->/*getSkinBitmap()->*/stretchToRectAlpha(canvas, &sr, &r, getPaintingAlpha());
+ InterlockedExchange(&invalidates_required, 0);
+ return 1;
+}
+
+void QuickPaintWnd::KillThread()
+{
+ if (thread_context)
+ {
+ killTimer(TIMER_QUICKPAINT);
+ thread_context->Kill();
+ delete thread_context;
+ thread_context = 0;
+ }
+}
+
+void QuickPaintWnd::CreateRenderThread()
+{
+ int sp = getSpeed();
+ if (!thread_context)
+ {
+ thread_context = new QuickPaintContext(this, sp);
+ }
+ else
+ thread_context->timer_ms = sp;
+ setTimer(TIMER_QUICKPAINT, sp);
+} \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/wndclass/qpaintwnd.h b/Src/Wasabi/api/wnd/wndclass/qpaintwnd.h
new file mode 100644
index 00000000..b758d440
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/qpaintwnd.h
@@ -0,0 +1,154 @@
+#ifndef __QPAINTWND_H
+#define __QPAINTWND_H
+
+#include <api/wnd/wndclass/guiobjwnd.h>
+#include <api/service/svcs/svc_skinfilter.h>
+
+#define QUICKPAINTWND_PARENT GuiObjectWnd
+
+/**
+ class QuickPaintWnd .
+
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see
+ @cat BFC
+*/
+class QuickPaintContext;
+class QuickPaintWnd : public QUICKPAINTWND_PARENT {
+
+ public:
+ /**
+ QuickPaintWnd constructor .
+
+ @see ~QuickPaintWnd()
+ */
+ QuickPaintWnd();
+
+ /**
+ Destructor for QuickPaintWnd .
+
+ @see QuickPaintWnd()
+ */
+ virtual ~QuickPaintWnd();
+
+ /**
+ QuickPaintWnd method onInit .
+
+ @ret 1
+ */
+ virtual int onInit();
+ virtual int onPaint(Canvas *c);
+
+ /**
+ QuickPaintWnd method timerCallback .
+
+ @param id Identifies requested action
+ */
+ virtual void timerCallback(int id);
+ virtual void onSetVisible(int show);
+
+ /**
+ QuickPaintWnd method setRealtime .
+
+ @see getRealtime()
+ @param rt
+ */
+ virtual void setRealtime(int rt);
+ int getRealtime() const;
+
+ /**
+ QuickPaintWnd method setSpeed sets the timer interval in milliseconds.
+
+ @see getSpeed()
+ @param ms The timer interval in milliseconds.
+ */
+ virtual void setSpeed(int ms);
+
+ /**
+ QuickPaintWnd method getSpeed gets the timer interval in milliseconds.
+
+ @see setSpeed()
+ @param ms The timer interval in milliseconds.
+ */
+ virtual int getSpeed();
+
+ /**
+ QuickPaintWnd method startQuickPaint .
+ */
+ virtual void startQuickPaint();
+
+ /**
+ QuickPaintWnd method stopQuickPaint .
+ */
+ virtual void stopQuickPaint();
+
+ /**
+ QuickPaintWnd method isQuickPainting .
+ */
+ virtual int isQuickPainting();
+
+ virtual int onQuickPaint(BltCanvas *c, int w, int h, int newone) { return 0; } // return 1 if your content has changed, or 0 to cancel update of your buffer to the window
+ virtual int wantEvenAlignment() { return 0; } // if you need even coordinates for your framebuffer, return 1 here
+
+ /**
+ QuickPaintWnd method getQuickPaintSize gets the client area width and
+ height.
+
+ @param w A pointer to the width to fill.
+ @param h A pointer to the height to fill.
+ */
+ virtual void getQuickPaintSize(int *w, int *h); // by default returns client width/height
+
+ /**
+ QuickPaintWnd method getQuickPaintSource .
+
+ @see getQuickPaintSize()
+ @assert r exists.
+ @ret None
+ @except
+ @param r
+ */
+ virtual void getQuickPaintSource(RECT *r); // by default returns the size of the quickpaint canvas
+
+ /**
+ QuickPaintWnd method getQuickPaintDest .
+
+ @see getQuickPaintSource()
+ @assert r exists.
+ @param r
+ */
+ virtual void getQuickPaintDest(RECT *r); // by default returns the size of client area
+ virtual int wantNegativeHeight() { return 0; }
+ virtual int wantFilters() { return 0; }
+ virtual const wchar_t *getFiltersGroup() { return L"Vis/Eq"; }
+
+ protected:
+int invalidated;
+ private:
+ /**
+ QuickPaintWnd method quickPaint .
+ */
+ friend class QuickPaintContext;
+ int quickPaint();
+ void KillThread();
+ void CreateRenderThread();
+ int realtime;
+ volatile LONG invalidates_required;
+ BltCanvas *render_canvas1, *render_canvas2, *paint_canvas;
+ void SetPaintingCanvas(BltCanvas *c);
+ BltCanvas *&GetDrawingConvas();
+ int canvas_w, canvas_h;
+ int speed;
+ int timerset;
+ int enabled;
+
+
+ PtrList<svc_skinFilter>filters;
+ SkinFilterEnum sfe;
+ QuickPaintContext *thread_context;
+};
+
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/rootwndholder.cpp b/Src/Wasabi/api/wnd/wndclass/rootwndholder.cpp
new file mode 100644
index 00000000..ad6000f3
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/rootwndholder.cpp
@@ -0,0 +1,113 @@
+#include "precomp.h"
+#include <api/wnd/api_wnd.h>
+
+#include "rootwndholder.h"
+#include <api/wnd/notifmsg.h>
+#include <tataki/canvas/canvas.h>
+
+
+RootWndHolder::RootWndHolder() {
+ privptr = NULL;
+}
+
+RootWndHolder::~RootWndHolder() {
+}
+
+void RootWndHolder::rootwndholder_getRect(RECT *r) {
+ if (isInited())
+ getClientRect(r);
+ else
+ MEMSET(r, 0, sizeof(RECT));
+}
+
+int RootWndHolder::onInit() {
+ ROOTWNDHOLDER_PARENT::onInit();
+ ifc_window *w = rootwndholder_getRootWnd();
+ if (w) {
+ checkInit(w);
+ setName(rootwndholder_getRootWnd()->getRootWndName());
+ }
+ return 1;
+}
+
+void RootWndHolder::checkInit(ifc_window *w) {
+ if (w && !w->isInited()) {
+ if (w->getParent() == NULL)
+ w->setParent(this);
+// w->setStartHidden(getStartHidden());
+ w->init(this);
+ }
+}
+
+int RootWndHolder::onResize() {
+ int rv = ROOTWNDHOLDER_PARENT::onResize();
+ if (!isInited()) return 1;
+ ifc_window *held = rootwndholder_getRootWnd();
+ if (!held) return rv;
+ RECT r;
+ rootwndholder_getRect(&r);
+ if (renderRatioActive() && !held->handleRatio())
+ multRatio(&r);
+ held->resize(r.left, r.top, r.right-r.left, r.bottom-r.top);
+ return rv;
+}
+
+/*void RootWndHolder::onSetVisible(int v) {
+ ROOTWNDHOLDER_PARENT::onSetVisible(v);
+ if (!rootwndholder_getRootWnd()) return;
+ rootwndholder_getRootWnd()->setVisible(v);
+}*/
+
+int RootWndHolder::onActivate() {
+ int r = ROOTWNDHOLDER_PARENT::onActivate();
+ if (rootwndholder_getRootWnd())
+ rootwndholder_getRootWnd()->onActivate();
+ return r;
+}
+
+int RootWndHolder::onDeactivate() {
+ int r = ROOTWNDHOLDER_PARENT::onDeactivate();
+ if (rootwndholder_getRootWnd())
+ rootwndholder_getRootWnd()->onDeactivate();
+ return r;
+}
+
+int RootWndHolder::getPreferences(int what) {
+ if (rootwndholder_getRootWnd())
+ return rootwndholder_getRootWnd()->getPreferences(what);
+ return ROOTWNDHOLDER_PARENT::getPreferences(what);
+}
+
+ifc_window *RootWndHolder::rootwndholder_getRootWnd() {
+ return privptr;
+}
+
+void RootWndHolder::rootwndholder_setRootWnd(ifc_window *w) {
+ if (privptr == w) return;
+ privptr = w;
+ checkInit(w);
+ if (isPostOnInit())
+ onResize();
+}
+
+int RootWndHolder::onAction(const wchar_t *action, const wchar_t *param, int x, int y, intptr_t p1, intptr_t p2, void *data, size_t datalen, ifc_window *source) {
+ if (rootwndholder_getRootWnd())
+ return rootwndholder_getRootWnd()->onAction(action, param, x, y, p1, p2, data, datalen, source);
+ return ROOTWNDHOLDER_PARENT::onAction(action, param, x, y, p1, p2, data, datalen, source);
+}
+
+int RootWndHolder::childNotify(ifc_window *child, int msg, intptr_t param1, intptr_t param2) {
+ if (msg == ChildNotify::NAMECHANGED && child == rootwndholder_getRootWnd())
+ setName(child->getRootWndName());
+ return passNotifyUp(child, msg, (int)param1, (int)param2);
+}
+
+int RootWndHolder::onPaint(Canvas *c) {
+ int rt = ROOTWNDHOLDER_PARENT::onPaint(c);
+ if (wantRenderBaseTexture()) {
+ RECT r;
+ rootwndholder_getRect(&r);
+ WASABI_API_WND->skin_renderBaseTexture(getBaseTextureWindow(), c, r, this);
+ }
+ return rt;
+} \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/wndclass/rootwndholder.h b/Src/Wasabi/api/wnd/wndclass/rootwndholder.h
new file mode 100644
index 00000000..6c718ce5
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/rootwndholder.h
@@ -0,0 +1,41 @@
+#ifndef __ROOTWNDHOLD_H
+#define __ROOTWNDHOLD_H
+
+#include <api/wnd/virtualwnd.h>
+
+/**
+ A simple wnd that holds another window. Initializes it if needed, but DOES not delete it (and for a good reason, this is a ifc_window),
+ so your inheritor has to call whoever is needed to destroy the wnd
+*/
+
+#define ROOTWNDHOLDER_PARENT VirtualWnd
+
+class RootWndHolder : public ROOTWNDHOLDER_PARENT
+{
+ public:
+ RootWndHolder();
+ virtual ~RootWndHolder();
+
+ // override this
+ virtual ifc_window *rootwndholder_getRootWnd();
+ virtual void rootwndholder_getRect(RECT *r);
+ virtual void rootwndholder_setRootWnd(ifc_window *w);
+
+ // BaseWnd
+ virtual int onInit();
+ virtual int onResize();
+// virtual void onSetVisible(int v);
+ virtual int wantRenderBaseTexture() { return 0; }
+ virtual int onPaint(Canvas *c);
+ virtual int onActivate();
+ virtual int onDeactivate();
+ virtual int getPreferences(int what);
+ virtual int onAction(const wchar_t *action, const wchar_t *param=NULL, int x=-1, int y=-1, intptr_t p1=0, intptr_t p2=0, void *data=NULL, size_t datalen=0, ifc_window *source=NULL);
+ virtual int childNotify(ifc_window *child, int msg, intptr_t param1=0, intptr_t param2=0);
+
+ private:
+ void checkInit(ifc_window *w);
+ ifc_window *privptr;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/wndclass/scbkgwnd.cpp b/Src/Wasabi/api/wnd/wndclass/scbkgwnd.cpp
new file mode 100644
index 00000000..758c7660
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/scbkgwnd.cpp
@@ -0,0 +1,869 @@
+#include <precomp.h>
+#include "scbkgwnd.h"
+#include <api/wnd/notifmsg.h>
+#include <bfc/wasabi_std_wnd.h>
+#include <api/wnd/PaintCanvas.h>
+
+#define SCROLLBAR_SEP 4
+#define TIMER_SMOOTHSCROLLY 8873
+#define TIMER_SMOOTHSCROLLX 8874
+#define SMOOTH_STEPS 5
+#define DEFAULT_BGCOLOR RGB(0,0,0)
+
+ScrlBkgWnd::ScrlBkgWnd()
+{
+ inDestroy = FALSE;
+ bmp = NULL;
+ bgColor = DEFAULT_BGCOLOR;
+ scrollX = 0;
+ scrollY = 0;
+ dbbuffer = 1;
+ needSetSliders = FALSE;
+ lineHeight = 16;
+ wantsep = 0;
+ wantTileBg = true;
+ lastratio = 1.0;
+ MEMSET(&smsqr, 0, sizeof(RECT));
+ in_set_slider_position = 0;
+
+ smoothScrollYInc = smoothScrollXInc = 0;
+ smoothScrollYCur = smoothScrollXCur = 0;
+ smoothScrollYTimerCount = smoothScrollXTimerCount = 0;
+ smoothYTimer = smoothXTimer = 0;
+}
+
+ScrlBkgWnd::~ScrlBkgWnd()
+{
+ inDestroy = TRUE;
+}
+
+int ScrlBkgWnd::onInit()
+{
+
+ SCRLBKGWND_PARENT::onInit();
+
+ scrollY = 0;
+ scrollX = 0;
+
+ hSep.setOrientation(SEP_HORIZONTAL);
+
+ hScroll.setBitmaps(L"wasabi.scrollbar.horizontal.left",
+ L"wasabi.scrollbar.horizontal.left.pressed",
+ L"wasabi.scrollbar.horizontal.left.hover",
+ L"wasabi.scrollbar.horizontal.right",
+ L"wasabi.scrollbar.horizontal.right.pressed",
+ L"wasabi.scrollbar.horizontal.right.hover",
+ L"wasabi.scrollbar.horizontal.button",
+ L"wasabi.scrollbar.horizontal.button.pressed",
+ L"wasabi.scrollbar.horizontal.button.hover");
+
+ hScroll.setBackgroundBitmaps(L"wasabi.scrollbar.horizontal.background.left",
+ L"wasabi.scrollbar.horizontal.background.middle",
+ L"wasabi.scrollbar.horizontal.background.right");
+
+ vSep.setOrientation(SEP_VERTICAL);
+
+ vScroll.setBitmaps(L"wasabi.scrollbar.vertical.left",
+ L"wasabi.scrollbar.vertical.left.pressed",
+ L"wasabi.scrollbar.vertical.left.hover",
+ L"wasabi.scrollbar.vertical.right",
+ L"wasabi.scrollbar.vertical.right.pressed",
+ L"wasabi.scrollbar.vertical.right.hover",
+ L"wasabi.scrollbar.vertical.button",
+ L"wasabi.scrollbar.vertical.button.pressed",
+ L"wasabi.scrollbar.vertical.button.hover");
+
+ vScroll.setBackgroundBitmaps(L"wasabi.scrollbar.vertical.background.top",
+ L"wasabi.scrollbar.vertical.background.middle",
+ L"wasabi.scrollbar.vertical.background.bottom");
+
+ // hScroll->setVertical(FALSE);
+ vScroll.setVertical(TRUE);
+
+ hScroll.setStartHidden(TRUE); // prevent showing window at creation
+ vScroll.setStartHidden(TRUE);
+ hSep.setStartHidden(TRUE);
+ vSep.setStartHidden(TRUE);
+
+ hScroll.setParent(this);
+ vScroll.setParent(this);
+ hSep.setParent(this);
+ vSep.setParent(this);
+
+ hScroll.init(getOsModuleHandle(), getOsWindowHandle());
+ vScroll.init(getOsModuleHandle(), getOsWindowHandle());
+ hSep.init(getOsModuleHandle(), getOsWindowHandle());
+ vSep.init(getOsModuleHandle(), getOsWindowHandle());
+
+ hScroll.setPosition(0);
+ vScroll.setPosition(0);
+
+ setSlidersPosition(); // position sliders and show them if needed
+
+ return 1;
+}
+
+void ScrlBkgWnd::setBgBitmap(const wchar_t *b)
+{
+ bmp = b;
+ if (b) setBgColor(DEFAULT_BGCOLOR);
+}
+
+void ScrlBkgWnd::setBgColor(ARGB32 rgb)
+{
+ bgColor = rgb;
+}
+
+SkinBitmap *ScrlBkgWnd::getBgBitmap(void)
+{
+ return bmp;
+}
+
+ARGB32 ScrlBkgWnd::getBgColor(void)
+{
+ return bgColor;
+}
+
+// Scroll to a specified Y-pixels
+void ScrlBkgWnd::scrollToY(int y, int signal)
+{
+
+ WndCanvas *canvas = NULL;
+ RECT r;
+ int offset;
+ int dor2 = 0;
+ RECT r2 = {0, 0, 0, 0};
+ int focused = gotFocus();
+
+ if (isVirtual() || renderRatioActive())
+ {
+ scrollY = y;
+ invalidateRect(&clientRect());
+ onScrollY(y);
+ return ;
+ }
+
+ if (!Wasabi::Std::Wnd::isValidWnd(getOsWindowHandle())) return ; // no need to paint
+
+ if (y > scrollY)
+ { // tree scrolling up, scroller going down. invalidating from the bottom. bitblting from bottom to top
+ int lines = y - scrollY;
+ offset = -lines;
+ getClientRect(&r);
+ canvas = new WndCanvas();
+ canvas->attachToClient(this);
+
+ RegionI reg;
+ makeWindowOverlayMask(&reg);
+ RegionI clip(&r);
+ reg.offset(0, offset);
+ clip.subtractRegion(&reg);
+ canvas->selectClipRgn(&clip);
+
+ int b = hScroll.isVisible() ? hScroll.getHeight() : 0;
+ int c = vScroll.isVisible() ? vScroll.getWidth() : 0;
+ int a = focused && (!b);
+ if (r.bottom-r.top-lines > 0)
+ canvas->blit(r.left, r.top+lines, canvas, r.left, r.top, r.right-r.left- c, r.bottom-r.top-lines-a - b);
+
+// int a = focused && (!hScroll->isVisible());
+ //if (r.bottom - r.top - lines > 0)
+// canvas->blit(r.left, r.top + lines, canvas, r.left, r.top, r.right - r.left, r.bottom - r.top - lines - a);
+
+ canvas->selectClipRgn(NULL);
+ if (!clip.isEmpty())
+ invalidateRgn(&clip);
+
+
+ getClientRect(&r2);
+ r2.bottom = r2.top + 1;
+ dor2 = 1;
+ r.top = r.bottom - lines - 1;
+ }
+ if (y < scrollY)
+ { // tree scrolling down, scroller going up. invalidating from the top. bitblting from top to bottom
+ int lines = scrollY - y;
+ offset = lines;
+ getClientRect(&r);
+ canvas = new WndCanvas();
+ canvas->attachToClient(this);
+
+ RegionI reg;
+ makeWindowOverlayMask(&reg);
+ RegionI clip(&r);
+ reg.offset(0, offset);
+ clip.subtractRegion(&reg);
+ canvas->selectClipRgn(&clip);
+
+ int c = vScroll.isVisible() ? vScroll.getWidth() : 0;
+ canvas->blit(r.left, r.top+focused, canvas, r.left, r.top+lines+focused, r.right-r.left-c, r.bottom-r.top-lines-focused);
+ //canvas->blit(r.left, r.top + focused, canvas, r.left, r.top + lines + focused, r.right - r.left, r.bottom - r.top - lines - focused);
+
+ canvas->selectClipRgn(NULL);
+ if (!clip.isEmpty())
+ invalidateRgn(&clip);
+
+ getClientRect(&r2);
+ r2.top = r2.bottom - 1;
+ dor2 = 1;
+ r.bottom = r.top + lines + 1;
+ }
+ if (canvas)
+ {
+ delete canvas;
+ scrollY = y;
+
+ // in case we have a virtualCanvas, we need to tell BaseWnd to call us to paint on it next time it's needed coz we blited directly to the screen
+ RECT cr;
+ getClientRect(&cr);
+ cr.top -= getHeaderHeight();
+ RECT screenblit;
+ SubtractRect(&screenblit, &cr, &r);
+
+ // invalidate what's needed
+ if (dor2 && focused)
+ cascadeRepaintRect(&r2, 0);
+ cascadeRepaintRect(&r);
+
+ deferedInvalidateRect(&screenblit);
+
+ //dbbuffer = 1;
+ //repaint();
+ }
+
+ if (signal)
+ updateVScroll(y);
+
+ onScrollY(y);
+}
+
+// Scroll to a specified X-pixel
+void ScrlBkgWnd::scrollToX(int x, int signal)
+{
+ WndCanvas *canvas = NULL;
+ RECT r;
+ int offset;
+ int dor2 = 0;
+ RECT r2 = {0, 0, 0, 0};
+ int focused = gotFocus();
+
+ if (isVirtual() || ABS(getRenderRatio() - 1.0) > 0.01)
+ {
+ scrollX = x;
+ getClientRect(&r);
+ invalidateRect(&r);
+ return ;
+ }
+
+ if (x > scrollX)
+ { // tree scrolling left, scroller going right. invalidating from the right. bitblting from right to left
+ int lines = x - scrollX;
+ offset = -lines;
+ getClientRect(&r);
+ r.top -= getHeaderHeight();
+ canvas = new WndCanvas();
+ canvas->attachToClient(this);
+
+ RegionI reg;
+ makeWindowOverlayMask(&reg);
+ RegionI clip(&r);
+ reg.offset(offset, 0);
+ clip.subtractRegion(&reg);
+ canvas->selectClipRgn(&clip);
+
+ int c = vScroll.isVisible() ? vScroll.getWidth() : 0;
+ canvas->blit(r.left+lines, r.top, canvas, r.left, r.top, r.right-r.left-lines-focused-c, r.bottom-r.top);
+ //canvas->blit(r.left + lines, r.top, canvas, r.left, r.top, r.right - r.left - lines - focused, r.bottom - r.top);
+
+ canvas->selectClipRgn(NULL);
+ if (!reg.isEmpty())
+ invalidateRgn(&reg);
+
+ getClientRect(&r2);
+ r2.right = r2.left + 1;
+ dor2 = 1;
+ r.left = r.right - lines - 1;
+ }
+ if (x < scrollX)
+ { // tree scrolling right, scroller going left. invalidating from the left. bitblting from left to right
+ int lines = scrollX - x;
+ offset = lines;
+ getClientRect(&r);
+ r.top -= getHeaderHeight();
+ canvas = new WndCanvas();
+ canvas->attachToClient(this);
+
+ RegionI reg;
+ makeWindowOverlayMask(&reg);
+ RegionI clip(&r);
+ reg.offset(offset, 0);
+ clip.subtractRegion(&reg);
+ canvas->selectClipRgn(&clip);
+
+ int a = focused && (!vScroll.isVisible());
+ int c = hScroll.isVisible() ? hScroll.getHeight()-focused : 0;
+ canvas->blit(r.left+a, r.top, canvas, r.left+lines, r.top, r.right-r.left-lines-a, r.bottom-r.top-c);
+
+ //int a = focused && (!vScroll->isVisible());
+// canvas->blit(r.left + a, r.top, canvas, r.left + lines, r.top, r.right - r.left - lines - a, r.bottom - r.top);
+
+ canvas->selectClipRgn(NULL);
+ if (!reg.isEmpty())
+ invalidateRgn(&reg);
+
+ getClientRect(&r2);
+ r2.left = r2.right - 1;
+ dor2 = 1;
+ r.right = r.left + lines + 1;
+ }
+ if (canvas)
+ {
+ delete canvas;
+ scrollX = x;
+
+ // in case we have a virtualCanvas, we need to tell BaseWnd to call us to paint on it next time it's needed coz we blited directly to the screen
+ RECT cr;
+ getClientRect(&cr);
+ cr.top -= getHeaderHeight();
+ RECT screenblit;
+ SubtractRect(&screenblit, &cr, &r);
+ deferedInvalidateRect(&screenblit);
+
+ if (dor2 && focused)
+ cascadeRepaintRect(&r2, 0);
+ // invalidate what's needed
+ cascadeRepaintRect(&r);
+
+ //dbbuffer = 1;
+ //repaint();
+ }
+
+ if (signal)
+ updateHScroll(x);
+}
+
+void ScrlBkgWnd::setSlidersPosition()
+{
+ if (in_set_slider_position) return ;
+ in_set_slider_position = 1;
+ _setSlidersPosition();
+ in_set_slider_position = 0;
+}
+
+void ScrlBkgWnd::_setSlidersPosition()
+{
+
+ if (!isInited()) return ;
+
+ RECT d;
+ getClientRect(&d);
+ if ((d.left >= d.right) || (d.top >= d.bottom))
+ return ;
+
+ RECT r;
+ if (inDestroy) return ;
+ if (!isVisible())
+ {
+ needSetSliders = TRUE;
+ return ;
+ }
+
+ needSetSliders = FALSE;
+
+ if (needHScroll())
+ {
+ SCRLBKGWND_PARENT::getClientRect(&r);
+ r.top = r.bottom - getScrollbarWidth();
+ if (needVScroll())
+ r.right -= getScrollbarWidth() + (wantsep ? SCROLLBAR_SEP : 0);
+ RECT z; hScroll.getClientRect(&z);
+ if (!Wasabi::Std::rectEqual(r, z))
+ { // assumes ScrollBars are virtual
+ hScroll.resizeToRect(&r);
+ RECT s = r;
+ s.bottom = s.top;
+ s.top -= (wantsep ? SCROLLBAR_SEP : 0);
+ hSep.resizeToRect(&s);
+ }
+ if (!hScroll.isVisible())
+ {
+ hScroll.setVisible(TRUE);
+ if (wantsep) hSep.setVisible(TRUE);
+ onHScrollToggle(1);
+ }
+ hScroll.setNPages(((int)(getContentsWidth() / (r.right - r.left))) + 1);
+ hScroll.setUpDownValue((int)(((float)lineHeight / (getContentsWidth() - (r.right - r.left)))*SCROLLBAR_FULL));
+ hScroll.setPosition((int)((float)scrollX / getMaxScrollX() * SCROLLBAR_FULL));
+ }
+ else
+ {
+ if (hScroll.isVisible())
+ {
+ hScroll.setVisible(FALSE);
+ if (wantsep) hSep.setVisible(FALSE);
+ onHScrollToggle(0);
+ }
+ hScroll.setPosition(0);
+ scrollToX(0);
+ }
+
+ if (needVScroll())
+ {
+ SCRLBKGWND_PARENT::getClientRect(&r);
+ r.left = r.right - getScrollbarWidth();
+ if (needHScroll())
+ r.bottom -= getScrollbarWidth();
+ RECT z; vScroll.getNonClientRect(&z);
+ if (!Wasabi::Std::rectEqual(r, z))
+ {
+ vScroll.resizeToRect(&r);
+ RECT s = r;
+ s.right = s.left;
+ s.left -= (wantsep ? SCROLLBAR_SEP : 0);
+ vSep.resizeToRect(&s);
+ }
+ if (!vScroll.isVisible())
+ {
+ vScroll.setVisible(TRUE);
+ if (wantsep) vSep.setVisible(TRUE);
+ onVScrollToggle(1);
+ }
+ vScroll.setNPages(((int)(getContentsHeight() / (r.bottom - r.top))) + 1);
+ vScroll.setUpDownValue((int)(((float)lineHeight / (getContentsHeight() - (r.bottom - r.top)))*SCROLLBAR_FULL));
+ vScroll.setPosition((int)((float)scrollY / getMaxScrollY() * SCROLLBAR_FULL));
+ }
+ else
+ {
+ if (vScroll.isVisible())
+ {
+ vScroll.setVisible(FALSE);
+ if (wantsep) vSep.setVisible(FALSE);
+ onVScrollToggle(0);
+ }
+ vScroll.setPosition(0);
+ scrollToY(0);
+ }
+
+ hSep.invalidate();
+ vSep.invalidate();
+
+ if (needHScroll() && needVScroll())
+ {
+ getNonClientRect(&smsqr);
+ smsqr.left = smsqr.right - getScrollbarWidth();
+ smsqr.top = smsqr.bottom - getScrollbarWidth();
+ invalidateRect(&smsqr);
+ }
+ else
+ ZERO(smsqr);
+}
+
+void ScrlBkgWnd::onHScrollToggle(int set)
+{}
+
+void ScrlBkgWnd::onVScrollToggle(int set)
+{}
+
+int ScrlBkgWnd::onPaint(Canvas *canvas)
+{
+ RECT d;
+ getClientRect(&d);
+ if (d.right > d.left + 0xFFFF || d.bottom > d.top + 0xFFFF) return 1;
+ if ((d.left >= d.right) || (d.top >= d.bottom))
+ {
+ return SCRLBKGWND_PARENT::onPaint(canvas);
+ }
+
+ if (needSetSliders) setSlidersPosition();
+
+ // RECT z;
+ // GetUpdateRect(gethWnd(), &z, FALSE);
+
+ PaintCanvas paintcanvas;
+ PaintBltCanvas paintbcanvas;
+
+ if (canvas == NULL)
+ {
+ if (dbbuffer)
+ {
+ if (!paintbcanvas.beginPaintNC(this)) return 0;
+ canvas = &paintbcanvas;
+ }
+ else
+ {
+ if (!paintcanvas.beginPaint(this)) return 0;
+ canvas = &paintcanvas;
+ }
+ }
+ //dbbuffer=1;
+ SCRLBKGWND_PARENT::onPaint(canvas);
+
+ RegionI *smsq = NULL;
+
+ if (needHScroll() && needVScroll())
+ {
+ renderBaseTexture(canvas, smsqr);
+ smsq = new RegionI(&smsqr);
+ }
+
+ RECT r;
+ LabelWnd::getNonClientRect(&r);
+ RECT c = {r.left, r.top, r.right, r.top + getLabelHeight()}; // create label rect
+
+
+ RegionI *clip = new RegionI();
+ if (canvas->getClipRgn(clip) == 0)
+ {
+ delete clip;
+ clip = new RegionI(&r);
+ if (smsq) clip->subtractRegion(smsq);
+ canvas->selectClipRgn(clip);
+ }
+ else
+ {
+ RegionI reg(&c);
+ clip->subtractRegion(&reg);
+ if (smsq) clip->subtractRegion(smsq);
+ canvas->selectClipRgn(clip);
+ }
+ delete smsq;
+
+ drawBackground(canvas);
+ delete clip;
+
+if (getRenderRatio() != lastratio) { invalidate(); lastratio = getRenderRatio(); } // todo: make that an event
+ return 1;
+}
+
+int ScrlBkgWnd::needDoubleBuffer()
+{
+ return dbbuffer;
+}
+
+int ScrlBkgWnd::onEraseBkgnd(HDC dc)
+{
+
+ /* DCCanvas canvas;
+ canvas.cloneDC(dc);
+
+ drawBackground(&canvas);*/
+
+ return 1;
+}
+
+// Draws tiled background
+void ScrlBkgWnd::drawBackground(Canvas *canvas)
+{
+ RECT r(clientRect());
+ RegionI reg(&r);
+ RegionI old;
+ canvas->getClipRgn(&old);
+ reg.andRegion(&old);
+ canvas->selectClipRgn(&reg);
+ if (bmp.getBitmap() && bgColor == DEFAULT_BGCOLOR)
+ {
+ r.top -= scrollY % bmp.getBitmap()->getHeight();
+ r.left -= scrollX % bmp.getBitmap()->getWidth();
+ if (wantTileBg)
+ bmp.getBitmap()->blitTile(canvas, &r);
+ else
+ bmp.getBitmap()->stretchToRect(canvas, &r);
+ }
+ else if (bgColor != DEFAULT_BGCOLOR)
+ {
+ canvas->fillRect(&r, bgColor);
+ }
+ canvas->selectClipRgn(&old);
+
+}
+
+bool ScrlBkgWnd::needHScroll()
+{
+ if (!wantHScroll()) return FALSE;
+ RECT r;
+ getNonClientRect(&r);
+ if (vScroll.isVisible())
+ r.right -= getScrollbarWidth();
+ return (getContentsWidth() > r.right - r.left);
+}
+
+bool ScrlBkgWnd::needVScroll()
+{
+ if (!wantVScroll()) return FALSE;
+ RECT r;
+ getNonClientRect(&r);
+ r.top += getHeaderHeight();
+ if (hScroll.isVisible())
+ r.bottom -= getScrollbarWidth();
+ return (getContentsHeight() > r.bottom - r.top);
+}
+
+// Returns the current tree width in pixels
+int ScrlBkgWnd::getContentsWidth()
+{
+ /*RECT r;
+ ScrlBkgWnd::getClientRect(&r);
+ return r.right-r.left;*/
+ return 10000;
+}
+
+// Returns the current tree height in pixels
+int ScrlBkgWnd::getContentsHeight()
+{
+ /*RECT r;
+ ScrlBkgWnd::getClientRect(&r);
+ return r.bottom-r.top;*/
+ return 10000;
+}
+
+int ScrlBkgWnd::getMaxScrollY()
+{
+ RECT r;
+ getClientRect(&r);
+ return MAX<int>(0, getContentsHeight() - (r.bottom - r.top));
+}
+
+int ScrlBkgWnd::getMaxScrollX()
+{
+ RECT r;
+ getClientRect(&r);
+ return MAX<int>(0, getContentsWidth() - (r.right - r.left));
+}
+
+void ScrlBkgWnd::updateVScroll(int y)
+{
+ if (getMaxScrollY() == 0) { vScroll.setPosition(0); return ; }
+ int z = (int)((float)y / getMaxScrollY() * SCROLLBAR_FULL);
+ vScroll.setPosition(z);
+}
+
+void ScrlBkgWnd::updateHScroll(int x)
+{
+ if (getMaxScrollX() == 0) { hScroll.setPosition(0); return ; }
+ int z = (int)((float)x / getMaxScrollX() * SCROLLBAR_FULL);
+ hScroll.setPosition(z);
+}
+
+void ScrlBkgWnd::updateScrollY(bool smooth)
+{
+ if (getMaxScrollY() == 0) { scrollToY(0); return ; }
+ int y = (int)((float)(vScroll.getPosition()) / SCROLLBAR_FULL * getMaxScrollY());
+ if (!smooth)
+ scrollToY(y /*& ~3*/);
+ else
+ smoothScrollToY(y);
+}
+
+void ScrlBkgWnd::updateScrollX(bool smooth)
+{
+ if (getMaxScrollX() == 0) { scrollToX(0); return ; }
+ int x = (int)((float)(hScroll.getPosition()) / SCROLLBAR_FULL * getMaxScrollX());
+ if (!smooth)
+ scrollToX(x /*& ~3*/);
+ else
+ smoothScrollToX(x);
+}
+
+void ScrlBkgWnd::smoothScrollToX(int x)
+{
+ killSmoothXTimer();
+ smoothScrollXInc = -(float)(scrollX - x) / SMOOTH_STEPS;
+ smoothScrollXCur = (float)scrollX;
+ smoothScrollXTimerCount = 0;
+ smoothXTimer = 1;
+ setTimer(TIMER_SMOOTHSCROLLX, 25);
+}
+
+void ScrlBkgWnd::killSmoothYTimer()
+{
+ if (smoothYTimer)
+ {
+ killTimer(TIMER_SMOOTHSCROLLY);
+ smoothScrollYCur += smoothScrollYInc * (SMOOTH_STEPS - smoothScrollYTimerCount);
+ scrollToY((int)smoothScrollYCur);
+ smoothYTimer = 0;
+ updateVScroll(scrollY);
+ }
+}
+
+void ScrlBkgWnd::killSmoothXTimer()
+{
+ if (smoothXTimer)
+ {
+ killTimer(TIMER_SMOOTHSCROLLX);
+ smoothScrollXCur += smoothScrollXInc * (SMOOTH_STEPS - smoothScrollXTimerCount);
+ scrollToX((int)smoothScrollXCur);
+ smoothXTimer = 0;
+ updateHScroll(scrollX);
+ }
+}
+
+void ScrlBkgWnd::smoothScrollToY(int y)
+{
+ killSmoothYTimer();
+ smoothScrollYInc = -(float)(scrollY - y) / SMOOTH_STEPS;
+ smoothScrollYCur = (float)scrollY;
+ smoothScrollYTimerCount = 0;
+ smoothYTimer = 1;
+ setTimer(TIMER_SMOOTHSCROLLY, 25);
+}
+
+void ScrlBkgWnd::timerCallback(int id)
+{
+ switch (id)
+ {
+ case TIMER_SMOOTHSCROLLY:
+ smoothScrollYCur += smoothScrollYInc;
+ scrollToY((int)smoothScrollYCur, FALSE);
+ if (++smoothScrollYTimerCount == SMOOTH_STEPS)
+ killSmoothYTimer();
+ return ;
+ case TIMER_SMOOTHSCROLLX:
+ smoothScrollXCur += smoothScrollXInc;
+ scrollToX((int)smoothScrollXCur, FALSE);
+ if (++smoothScrollXTimerCount == SMOOTH_STEPS)
+ killSmoothXTimer();
+ return ;
+ }
+ SCRLBKGWND_PARENT::timerCallback(id);
+}
+
+// Gets notification from sliders
+int ScrlBkgWnd::childNotify(ifc_window *child, int msg, intptr_t param1, intptr_t param2)
+{
+ switch (msg)
+ {
+ case ChildNotify::SCROLLBAR_SETPOSITION:
+ if (child == &vScroll)
+ {
+ updateScrollY(!!param1);
+ return 1;
+ }
+ if (child == &hScroll)
+ {
+ updateScrollX(!!param1);
+ return 1;
+ }
+ break;
+ }
+
+ return SCRLBKGWND_PARENT::childNotify(child, msg, param1, param2);
+}
+
+int ScrlBkgWnd::onResize()
+{
+ int rt = SCRLBKGWND_PARENT::onResize();
+ if (!isInited()) return rt;
+ invalidateRect(&smsqr);
+ setSlidersPosition();
+ return 1;
+}
+
+void ScrlBkgWnd::onSetVisible(int show)
+{
+ SCRLBKGWND_PARENT::onSetVisible(show);
+ if (show)
+ setSlidersPosition();
+}
+
+void ScrlBkgWnd::getClientRect(RECT *r)
+{
+ SCRLBKGWND_PARENT::getClientRect(r);
+ if (vScroll.isVisible(1))
+ r->right -= getScrollbarWidth() + (wantsep ? SCROLLBAR_SEP : 0);
+ if (hScroll.isVisible(1))
+ r->bottom -= getScrollbarWidth() + (wantsep ? SCROLLBAR_SEP : 0);
+ r->top += getHeaderHeight();
+}
+
+/*void ScrlBkgWnd::getNonClientRect(RECT *r) {
+ SCRLBKGWND_PARENT::getClientRect(r); // my non client rect is my parent's client rect
+ return;
+}*/
+
+int ScrlBkgWnd::getHeaderHeight()
+{
+ return 0;
+}
+
+void ScrlBkgWnd::setLineHeight(int h)
+{
+ lineHeight = h;
+}
+
+int ScrlBkgWnd::getLinesPerPage()
+{
+ RECT r;
+ getClientRect(&r);
+ int h = r.bottom - r.top;
+ return h / lineHeight;
+}
+
+int ScrlBkgWnd::getScrollX()
+{
+ return scrollX;
+}
+
+int ScrlBkgWnd::getScrollY()
+{
+ return scrollY;
+}
+
+int ScrlBkgWnd::getScrollbarWidth()
+{
+ // TODO: maybe do if (hScroll.isVisible())
+ return hScroll.getWidth();
+ return vScroll.getWidth();
+ return 0;
+}
+
+/*void ScrlBkgWnd::clientToScreen(RECT *r) {
+ POINT p;
+ p.x = r->left;
+ p.y = r->top;
+ SCRLBKGWND_PARENT::clientToScreen((int *)&p.x, (int*)&p.y);
+ r->left = p.x;
+ r->top = p.y;
+
+ p.x = r->right;
+ p.y = r->bottom;
+ SCRLBKGWND_PARENT::clientToScreen((int *)&p.x, (int*)&p.y);
+ r->right = p.x;
+ r->bottom = p.y;
+}
+
+void ScrlBkgWnd::clientToScreen(int *x, int *y) {
+ SCRLBKGWND_PARENT::clientToScreen(x, y);
+}
+
+void ScrlBkgWnd::clientToScreen(POINT *p) {
+ TREEWND_PARENT::clientToScreen((int *)&p->x, (int *)&p->y);
+}*/
+
+void ScrlBkgWnd::makeWindowOverlayMask(api_region *r)
+{
+
+ return ;
+#ifdef WIN32
+ // With this routine empty, I'm just nuking the code from x-plat builds < KP
+ HDC dc = GetDC(getOsWindowHandle());
+
+ //if (getRandomRgn)
+ {
+ RECT cr;
+ getClientRect(&cr);
+ RECT wr;
+ getWindowRect(&wr);
+
+ RegionI sr;
+ Wasabi::Std::Wnd::getRandomRegion(dc, sr.getOSHandle());
+ sr.offset( -wr.left, -wr.top);
+
+ r->setRect(&cr);
+ r->subtractRegion(&sr);
+
+ }
+
+ ReleaseDC(getOsWindowHandle(), dc);
+#endif
+}
diff --git a/Src/Wasabi/api/wnd/wndclass/scbkgwnd.h b/Src/Wasabi/api/wnd/wndclass/scbkgwnd.h
new file mode 100644
index 00000000..549e6f90
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/scbkgwnd.h
@@ -0,0 +1,463 @@
+#ifndef __SCRLBKGWND_H
+#define __SCRLBKGWND_H
+
+#include <tataki/canvas/canvas.h>
+#include <tataki/bitmap/autobitmap.h>
+#include <api/wnd/wndclass/labelwnd.h>
+#include <api/wnd/wndclass/scrollbar.h>
+#include <api/wnd/wndclass/sepwnd.h>
+
+#define SCRLBKGWND_PARENT LabelWnd
+
+
+/**
+ Class
+
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see
+*/
+class ScrlBkgWnd : public SCRLBKGWND_PARENT {
+protected:
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ ScrlBkgWnd();
+public:
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual ~ScrlBkgWnd();
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onInit();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onPaint(Canvas *c);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void drawBackground(Canvas *canvas);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onEraseBkgnd(HDC dc);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int childNotify(ifc_window *child, int msg, intptr_t param1, intptr_t param2);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onResize();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void getClientRect(RECT *r);
+// virtual void getNonClientRect(RECT *r);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int getHeaderHeight();
+ virtual void timerCallback (int id);
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void onHScrollToggle(int set);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void onVScrollToggle(int set);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void onSetVisible(int show);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int wantHScroll() { return 1; }
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int wantVScroll() { return 1; }
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void makeWindowOverlayMask(api_region *r);
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ SkinBitmap *getBgBitmap(void);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void setBgBitmap(const wchar_t *b);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void setBgColor(ARGB32 rgb);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual ARGB32 getBgColor(void);
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int getContentsWidth(); // not safe to call getclientrect!
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int getContentsHeight(); // not safe to call getclientrect!
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void setLineHeight(int h);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int getLinesPerPage();
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int getScrollX();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int getScrollY();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int getScrollbarWidth();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void scrollToY(int y, int signal=TRUE);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void scrollToX(int x, int signal=TRUE);
+
+protected:
+
+ virtual void onScrollY(int y) { }
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void setSlidersPosition();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int needDoubleBuffer();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ bool needHScroll();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ bool needVScroll();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int getMaxScrollY();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int getMaxScrollX();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void updateScrollY(bool smooth=false);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void updateScrollX(bool smooth=false);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void smoothScrollToY(int y);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void smoothScrollToX(int x);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void updateVScroll(int y);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void updateHScroll(int x);
+
+ AutoSkinBitmap bmp;
+
+ int dbbuffer;
+ bool inDestroy;
+
+ ScrollBar hScroll;
+ ScrollBar vScroll;
+ SepWnd hSep;
+ SepWnd vSep;
+
+ ARGB32 bgColor;
+
+ int scrollX;
+ int scrollY;
+
+ bool needSetSliders;
+ bool wantsep;
+ bool wantTileBg;
+
+ int lineHeight;
+
+ float smoothScrollYInc, smoothScrollXInc;
+ float smoothScrollYCur, smoothScrollXCur;
+ int smoothScrollYTimerCount, smoothScrollXTimerCount;
+ int smoothYTimer, smoothXTimer;
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void killSmoothYTimer();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void killSmoothXTimer();
+ double lastratio;
+ RECT smsqr;
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void _setSlidersPosition();
+ int in_set_slider_position;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/scrollbar.cpp b/Src/Wasabi/api/wnd/wndclass/scrollbar.cpp
new file mode 100644
index 00000000..ce3e5b03
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/scrollbar.cpp
@@ -0,0 +1,679 @@
+#include <precomp.h>
+
+#include <bfc/wasabi_std.h>
+
+#include "scrollbar.h"
+#include <tataki/canvas/canvas.h>
+#include <api/wnd/notifmsg.h>
+#include <api/wnd/PaintCanvas.h>
+
+#define TIMER_ID 9871
+#define TIMER_ID2 9872
+
+#define FIRST_DELAY 350
+#define NEXT_DELAY 75
+
+ScrollBar::ScrollBar() {
+ leftrgn = NULL;
+ rightrgn = NULL;
+ buttonrgn = NULL;
+
+ position = 0;
+ moving = 0;
+ lefting = 0;
+ righting = 0;
+ clicked = 0;
+ height = DEFAULT_HEIGHT;
+ buttonx = 0;
+
+ shiftleft = 0;
+ shiftright = 0;
+
+ curmouseposition = POS_NONE;
+ clickmouseposition = POS_NONE;
+ pageing = 0;
+ timer = timer2 = 0;
+ npages = 100;
+ pageway = PAGE_NONE;
+ updown = 256;
+ insetpos = 0;
+ clickbuttonx = 0;
+ vertical = 0;
+ firstdelay = 0;
+ lastx = lasty = 0;
+}
+
+ScrollBar::~ScrollBar() {
+ deleteResources();
+}
+
+void ScrollBar::deleteResources() {
+ delete leftrgn; leftrgn = NULL;
+ delete buttonrgn; buttonrgn = NULL;
+ delete rightrgn; rightrgn = NULL;
+}
+
+// this one is inherited
+void ScrollBar::freeResources() {
+ SCROLLBAR_PARENT::freeResources();
+ deleteResources();
+}
+
+void ScrollBar::reloadResources() {
+ SCROLLBAR_PARENT::reloadResources();
+ loadBmps();
+}
+
+
+int ScrollBar::onMouseMove (int x, int y) {
+
+ SCROLLBAR_PARENT::onMouseMove(x, y);
+ lastx = x;
+ lasty = y;
+
+ if (clicked && clickmouseposition == POS_BUTTON) {
+
+ POINT pt={x,y};
+ int x;
+ if (!vertical)
+ x = pt.x - clickpos.x;
+ else
+ x = pt.y - clickpos.y;
+
+ RECT r;
+ getClientRect(&r);
+ int maxwidth;
+ if (!vertical)
+ maxwidth = (r.right-r.left)-(shiftright+shiftleft+bmpbutton.getWidth())+1;
+ else
+ maxwidth = (r.bottom-r.top)-(shiftright+shiftleft+bmpbutton.getHeight())+1;
+ buttonx = MIN(MAX(clickbuttonx + x, 0), maxwidth);
+ calcPosition();
+ invalidate();
+
+ } else {
+
+ int oldposition = curmouseposition;
+ curmouseposition = getMousePosition();
+ if (oldposition != curmouseposition) invalidate();
+
+ if (curmouseposition != POS_NONE && !getCapture())
+ beginCapture();
+
+ if (curmouseposition == POS_NONE && getCapture() && !clicked && !pageing)
+ endCapture();
+ }
+
+
+ return 1;
+}
+
+int ScrollBar::getWidth() {
+ if (!bmpbutton) return 0;
+ if (!vertical)
+ return bmpbutton.getHeight();
+ else
+ return bmpbutton.getWidth();
+ return 0;
+}
+
+int ScrollBar::getMousePosition() {
+ int v = POS_NONE;
+
+ POINT pt={lastx, lasty};
+
+ RECT c;
+ getClientRect(&c);
+ pt.x -= c.left;
+ pt.y -= c.top;
+
+ api_region *l, *b, *r;
+ l = leftrgn->clone();
+ b = buttonrgn->clone();
+ if (!vertical)
+ b->offset(buttonx+shiftleft, 0);
+ else
+ b->offset(0, buttonx+shiftleft);
+ r = rightrgn->clone();
+ if (!vertical)
+ r->offset(c.right-c.left-bmpleft.getWidth(), 0);
+ else
+ r->offset(0, c.bottom-c.top-bmpleft.getHeight());
+
+ if (b->ptInRegion(&pt))
+ v = POS_BUTTON;
+ if (l->ptInRegion(&pt))
+ v = POS_LEFT;
+ if (r->ptInRegion(&pt))
+ v = POS_RIGHT;
+
+ leftrgn->disposeClone(l);
+ buttonrgn->disposeClone(b);
+ rightrgn->disposeClone(r);
+
+ return v;
+}
+
+int ScrollBar::onLeftButtonDown(int x, int y) {
+ clickmouseposition = getMousePosition();
+ if (!pageing && clickmouseposition != POS_NONE) {
+ clicked = 1;
+ if (clickmouseposition == POS_LEFT || clickmouseposition == POS_RIGHT)
+ handleUpDown();
+ if (clickmouseposition) {
+ clickpos.x = lastx;
+ clickpos.y = lasty;
+ clickbuttonx = buttonx;
+ }
+ } else {
+ clicked = 0;
+ pageing = 1;
+ handlePageUpDown();
+ }
+ invalidate();
+ return 1;
+}
+
+void ScrollBar::handleUpDown() {
+ setTimer(TIMER_ID2, FIRST_DELAY);
+ timer2 = 1;
+ firstdelay = 1;
+
+ checkUpDown();
+}
+
+int ScrollBar::checkUpDown() {
+ if (!clicked) {
+ if (timer2) {
+ killTimer(TIMER_ID2);
+ timer2 = 0;
+ return 1;
+ }
+ }
+
+ if (getMousePosition() == clickmouseposition)
+ upDown(clickmouseposition);
+
+ return 1;
+
+}
+
+void ScrollBar::handlePageUpDown() {
+
+ setTimer(TIMER_ID, FIRST_DELAY);
+ timer = 1;
+ firstdelay = 1;
+
+ checkPageUpDown();
+}
+
+int ScrollBar::checkPageUpDown() {
+
+ if (!pageing) {
+ if (timer) {
+ killTimer(TIMER_ID);
+ timer = 0;
+ pageway = PAGE_NONE;
+ return 1;
+ }
+ }
+
+ POINT pt={lastx,lasty};
+ RECT c;
+ getClientRect(&c);
+ pt.x -= c.left;
+ pt.y -= c.top;
+
+ if (!vertical) {
+ int middlebutton = shiftleft + buttonx + bmpbutton.getWidth()/2;
+ api_region *r = buttonrgn->clone();
+ r->offset(buttonx+shiftleft, 0);
+ if (pt.x > middlebutton && !r->ptInRegion(&pt) && pageway != PAGE_DOWN)
+ pageUp();
+ if (pt.x < middlebutton && !r->ptInRegion(&pt) && pageway != PAGE_UP)
+ pageDown();
+ buttonrgn->disposeClone(r);
+ } else {
+ int middlebutton = shiftleft + buttonx + bmpbutton.getHeight()/2;
+ api_region *r = buttonrgn->clone();
+ r->offset(0, buttonx+shiftleft);
+ if (pt.y > middlebutton && !r->ptInRegion(&pt) && pageway != PAGE_DOWN)
+ pageUp();
+ if (pt.y < middlebutton && !r->ptInRegion(&pt) && pageway != PAGE_UP)
+ pageDown();
+ buttonrgn->disposeClone(r);
+ }
+ return 1;
+
+}
+
+int ScrollBar::onLeftButtonUp(int x, int y) {
+ clicked = 0;
+ clickmouseposition = POS_NONE;
+ curmouseposition = POS_NONE;
+ onMouseMove(x,y);
+ if (pageing) {
+ pageing = 0;
+ checkPageUpDown();
+ }
+ onSetFinalPosition();
+ invalidate();
+ return 1;
+}
+
+int ScrollBar::onRightButtonDown(int x, int y) {
+ return 1;
+}
+
+int ScrollBar::onRightButtonUp(int x, int y) {
+ return 1;
+}
+
+int ScrollBar::onMouseWheelUp(int clicked, int lines) {
+ return 1;
+}
+
+int ScrollBar::onMouseWheelDown(int clicked, int lines) {
+ return 1;
+}
+
+int ScrollBar::onPaint(Canvas *canvas) {
+ AutoSkinBitmap &thisleft = curmouseposition == POS_LEFT ? (clicked ? bmplpressed : bmplhilite) : bmpleft;
+ AutoSkinBitmap &thisbutton = curmouseposition == POS_BUTTON ? (clicked ? bmpbpressed : bmpbhilite) : bmpbutton;
+ AutoSkinBitmap &thisright = curmouseposition == POS_RIGHT ? (clicked ? bmprpressed : bmprhilite) : bmpright;
+
+ if (curmouseposition != clickmouseposition && clicked) {
+ thisleft = bmpleft;
+ thisbutton = bmpbutton;
+ thisright = bmpright;
+ }
+
+ RECT r;
+ PaintBltCanvas paintcanvas;
+
+ if (canvas == NULL) {
+ if (!paintcanvas.beginPaint(this)) return 0;
+ canvas = &paintcanvas;
+ }
+ SCROLLBAR_PARENT::onPaint(canvas);
+
+ getClientRect(&r);
+
+ renderBaseTexture(canvas, r);
+
+ if (!vertical) {
+ RECT c;
+
+ c.left = r.left;
+ c.right = r.left;
+ c.top = r.top;
+ c.bottom = r.bottom;
+ if (bmpbackgroundleft.getBitmap()) {
+ c.right = c.left + bmpbackgroundleft.getWidth();
+ bmpbackgroundleft.getBitmap()->stretchToRectAlpha(canvas, &c);
+ }
+ int l = c.right;
+ c.left = r.right;
+ c.right = r.right;
+ if (bmpbackgroundright.getBitmap()) {
+ c.left = r.right - bmpbackgroundright.getWidth();
+ bmpbackgroundright.getBitmap()->stretchToRectAlpha(canvas, &c);
+ }
+ c.right = c.left;
+ c.left = l;
+ if (bmpbackgroundmiddle.getBitmap()) {
+ bmpbackgroundmiddle.getBitmap()->stretchToRectAlpha(canvas, &c);
+ }
+
+ c.left = r.left + buttonx+shiftleft;
+ c.top = r.top + 0;
+ c.right = r.left + buttonx+thisbutton.getWidth()+shiftleft;
+ c.bottom = r.top + getWidth();
+
+ thisbutton.stretchToRectAlpha(canvas, &c);
+
+ c.left = r.left;
+ c.top = r.top;
+ c.right = r.left + thisleft.getWidth();
+ c.bottom = r.top + getWidth();
+
+ thisleft.stretchToRectAlpha(canvas, &c);
+
+ c.left = r.right-thisright.getWidth();
+ c.top = r.top;
+ c.right = r.right;
+ c.bottom = r.top+getWidth();
+
+ thisright.stretchToRectAlpha(canvas, &c);
+ } else {
+ RECT c;
+
+ c.top = r.top;
+ c.bottom = r.top;
+ c.left = r.left;
+ c.right = r.right;
+ if (bmpbackgroundleft.getBitmap()) {
+ c.bottom = c.top + bmpbackgroundleft.getHeight();
+ bmpbackgroundleft.getBitmap()->stretchToRectAlpha(canvas, &c);
+ }
+ int l = c.bottom;
+ c.top = r.bottom;
+ c.bottom = r.bottom;
+ if (bmpbackgroundright.getBitmap()) {
+ c.top = r.bottom - bmpbackgroundright.getHeight();
+ bmpbackgroundright.getBitmap()->stretchToRectAlpha(canvas, &c);
+ }
+ c.bottom = c.top;
+ c.top = l;
+ if (bmpbackgroundmiddle.getBitmap()) {
+ bmpbackgroundmiddle.getBitmap()->stretchToRectAlpha(canvas, &c);
+ }
+
+ c.left = r.right - thisleft.getWidth();
+ c.top = r.top+buttonx + shiftleft;
+ c.right = r.right;
+ c.bottom = r.top+buttonx+thisbutton.getHeight() + shiftleft;
+
+ thisbutton.stretchToRectAlpha(canvas, &c);
+
+ c.left = r.right - thisleft.getWidth();
+ c.top = r.top;
+ c.right = r.right;
+ c.bottom = r.top+thisleft.getHeight();
+
+ thisleft.stretchToRectAlpha(canvas, &c);
+
+ c.left = r.right-thisright.getWidth();
+ c.top = r.bottom-thisright.getHeight();
+ c.right = r.right;
+ c.bottom = r.bottom;
+
+ thisright.stretchToRectAlpha(canvas, &c);
+ }
+
+ return 1;
+}
+
+int ScrollBar::getHeight() {
+ return height;
+}
+
+void ScrollBar::setHeight(int newheight) {
+ height = newheight;
+}
+
+int ScrollBar::onResize() {
+ calcXPosition();
+ invalidate();
+ return 1;
+}
+
+int ScrollBar::onInit() {
+ SCROLLBAR_PARENT::onInit();
+ return 1;
+}
+
+void ScrollBar::setBitmaps(wchar_t *left, wchar_t *lpressed, wchar_t *lhilite,
+ wchar_t *right, wchar_t *rpressed, wchar_t *rhilite,
+ wchar_t *button, wchar_t *bpressed, wchar_t *bhilite) {
+
+ deleteResources();
+
+ bmpleft = left;
+ bmplpressed = lpressed;
+ bmplhilite = lhilite;
+ bmpright = right;
+ bmprpressed = rpressed;
+ bmprhilite = rhilite;
+ bmpbutton = button;
+ bmpbpressed = bpressed;
+ bmpbhilite = bhilite;
+
+ loadBmps();
+}
+
+void ScrollBar::setBackgroundBitmaps(const wchar_t *left, const wchar_t *middle, const wchar_t *right) {
+ bmpbackgroundleft = left;
+ bmpbackgroundmiddle = middle;
+ bmpbackgroundright = right;
+}
+
+void ScrollBar::loadBmps() {
+
+ if (bmpleft.getBitmap()) leftrgn = new RegionI(bmpleft);
+ if (bmpbutton.getBitmap()) buttonrgn = new RegionI(bmpbutton);
+ if (bmpright.getBitmap()) rightrgn = new RegionI(bmpright);
+
+ calcOverlapping();
+ calcXPosition();
+}
+
+void ScrollBar::setPosition(int pos) {
+ setPrivatePosition(pos, FALSE);
+}
+
+void ScrollBar::setPrivatePosition(int pos, bool signal, bool smooth) {
+ if (insetpos) return; // helps stupid people (like me)
+ insetpos = 1;
+ position = MIN(SCROLLBAR_FULL, pos);
+ position = MAX(0, position);
+ calcXPosition();
+ if (signal) onSetPosition(smooth);
+ if (isInited() && isVisible())
+ invalidate();
+ insetpos = 0;
+}
+
+int ScrollBar::getPosition() {
+ return position;
+}
+
+int ScrollBar::onSetPosition(bool smooth) {
+ notifyParent(ChildNotify::SCROLLBAR_SETPOSITION, smooth);
+ return 1;
+}
+
+int ScrollBar::onSetFinalPosition() {
+ notifyParent(ChildNotify::SCROLLBAR_SETFINALPOSITION);
+ return 1;
+}
+
+void ScrollBar::calcOverlapping() {
+
+ if (!vertical) {
+
+ shiftleft = bmpleft.getWidth();
+ if (leftrgn && buttonrgn) {
+ int i;
+ for (i=shiftleft;i>=0;i--) {
+ api_region *reg = buttonrgn->clone();
+ reg->offset(i, 0);
+ if (leftrgn->doesIntersectRgn(reg)) {
+ i++;
+ buttonrgn->disposeClone(reg);
+ break;
+ }
+ buttonrgn->disposeClone(reg);
+ }
+ if (i >= 0)
+ shiftleft = i;
+ }
+
+ shiftright = bmpright.getWidth();
+ if (rightrgn && buttonrgn) {
+ int i;
+ for (i=0;i>=-shiftright;i--) {
+ api_region *reg = rightrgn->clone();
+ reg->offset(i+bmpbutton.getWidth(), 0);
+ if (reg->doesIntersectRgn(buttonrgn)) {
+ i++;
+ rightrgn->disposeClone(reg);
+ break;
+ }
+ rightrgn->disposeClone(reg);
+ }
+ if (i >= -shiftright)
+ shiftright += i;
+ }
+
+ } else {
+
+ shiftleft = bmpleft.getHeight();
+ if (leftrgn && buttonrgn) {
+ int i;
+ for (i=shiftleft;i>=0;i--) {
+ api_region *reg = buttonrgn->clone();
+ reg->offset(0, i);
+ if (leftrgn->doesIntersectRgn(reg)) {
+ i++;
+ buttonrgn->disposeClone(reg);
+ break;
+ }
+ buttonrgn->disposeClone(reg);
+ }
+ if (i >= 0)
+ shiftleft = i;
+ }
+
+ shiftright = bmpright.getHeight();
+ if (rightrgn && buttonrgn) {
+ int i;
+ for (i=0;i>=-shiftright;i--) {
+ api_region *reg = rightrgn->clone();
+ reg->offset(0, i+bmpbutton.getHeight());
+ if (reg->doesIntersectRgn(buttonrgn)) {
+ i++;
+ rightrgn->disposeClone(reg);
+ break;
+ }
+ rightrgn->disposeClone(reg);
+ }
+ if (i >= -shiftright)
+ shiftright += i;
+ }
+
+ }
+
+}
+
+void ScrollBar::calcXPosition() {
+
+ if (!isInited()) return;
+
+ RECT r;
+ getClientRect(&r);
+
+ int maxwidth;
+
+ if (!vertical)
+ maxwidth = (r.right-r.left)-(bmpbutton.getWidth()+shiftleft+shiftright)+1;
+ else
+ maxwidth = (r.bottom-r.top)-(bmpbutton.getHeight()+shiftleft+shiftright)+1;
+ int oldx = buttonx;
+ buttonx = (int)(((float)getPosition() / SCROLLBAR_FULL) * maxwidth);
+ if (buttonx != oldx)
+ invalidate();
+}
+
+void ScrollBar::calcPosition() {
+
+ if (!isInited()) return;
+
+ RECT r;
+ getClientRect(&r);
+
+ int maxwidth;
+
+ if (!vertical)
+ maxwidth = r.right-r.left-(bmpbutton.getWidth()+shiftleft+shiftright)+1;
+ else
+ maxwidth = r.bottom-r.top-(bmpbutton.getHeight()+shiftleft+shiftright)+1;
+ setPrivatePosition((int)((float)buttonx / maxwidth * SCROLLBAR_FULL));
+ //invalidate();
+}
+
+void ScrollBar::timerCallback(int id) {
+ switch (id) {
+ case TIMER_ID:
+ if (firstdelay) {
+ killTimer(TIMER_ID);
+ setTimer(TIMER_ID, NEXT_DELAY);
+ timer = 1;
+ firstdelay = 0;
+ }
+ checkPageUpDown();
+ break;
+ case TIMER_ID2:
+ if (firstdelay) {
+ killTimer(TIMER_ID2);
+ setTimer(TIMER_ID2, NEXT_DELAY);
+ timer2 = 1;
+ firstdelay = 0;
+ }
+ checkUpDown();
+ break;
+ default:
+ SCROLLBAR_PARENT::timerCallback(id);
+ }
+}
+
+// FG> smooth scrolling forced on, sorry, microsoft does it too so the user perceives IE scrolling as faster than it actually is
+// eventho they tell you "The smooth-scrolling effect for list boxes should be disabled when this setting is FALSE. Your application must do this if it creates customized list boxes", they
+// break their own rule so people don't bitch too much. ergo there is no reason we should not do that too.
+
+int ScrollBar::pageUp() {
+
+ pageway = PAGE_UP;
+
+ setPrivatePosition((int)MAX(0.f, (float)getPosition() + (float)SCROLLBAR_FULL / (npages-1)), TRUE, 1/*Std::osparam_getSmoothScroll()*/);
+
+ return 1;
+};
+
+int ScrollBar::pageDown() {
+
+ pageway = PAGE_DOWN;
+
+ setPrivatePosition((int)MIN((float)SCROLLBAR_FULL, (float)getPosition() - (float)SCROLLBAR_FULL / (npages-1)), TRUE, 1/*Std::osparam_getSmoothScroll()*/);
+
+ return 1;
+};
+
+void ScrollBar::setNPages(int n) {
+ //ASSERT(n >= 2);
+ if (n < 2) n = 2;
+ npages = n;
+}
+
+void ScrollBar::gotoPage(int page) {
+
+ page = MIN(page, npages-1);
+ page = MAX(page, 0);
+
+ setPrivatePosition((int)((float)SCROLLBAR_FULL / (npages-1) * page), TRUE, FALSE);
+
+}
+
+void ScrollBar::setUpDownValue(int newupdown) {
+ updown = newupdown;
+}
+
+int ScrollBar::upDown(int which) {
+ switch (which) {
+ case POS_LEFT:
+ setPrivatePosition(getPosition()-updown);
+ break;
+ case POS_RIGHT:
+ setPrivatePosition(getPosition()+updown);
+ break;
+ }
+ return 1;
+}
+
+void ScrollBar::setVertical(bool isvertical) {
+ vertical = isvertical;
+ calcOverlapping();
+ if (isInited())
+ invalidate();
+}
+
diff --git a/Src/Wasabi/api/wnd/wndclass/scrollbar.h b/Src/Wasabi/api/wnd/wndclass/scrollbar.h
new file mode 100644
index 00000000..98be5400
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/scrollbar.h
@@ -0,0 +1,423 @@
+#ifndef __SCROLLBAR_H
+#define __SCROLLBAR_H
+
+#include <api/wnd/virtualwnd.h>
+#include <tataki/region/region.h>
+#include <api/wnd/usermsg.h>
+#include <tataki/bitmap/autobitmap.h>
+
+#define SCROLLBAR_FULL 65535
+
+#define POS_NONE 0
+#define POS_LEFT 1
+#define POS_BUTTON 2
+#define POS_RIGHT 3
+
+#define PAGE_NONE 0
+#define PAGE_DOWN 1
+#define PAGE_UP 2
+
+#define DEFAULT_HEIGHT 16
+
+#define SCROLLBAR_PARENT VirtualWnd
+
+/**
+ Class
+
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see
+*/
+class ScrollBar : public SCROLLBAR_PARENT {
+public:
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ ScrollBar();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual ~ScrollBar();
+
+ virtual int onMouseMove (int x, int y);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onLeftButtonDown(int x, int y);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onLeftButtonUp(int x, int y);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onRightButtonDown(int x, int y);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onRightButtonUp(int x, int y);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onMouseWheelUp(int clicked, int lines);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onMouseWheelDown(int clicked, int lines);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onPaint(Canvas *canvas);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onResize();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onInit();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void timerCallback(int id);
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int wantDoubleClicks() { return 0; };
+
+
+ virtual int onSetPosition(bool smooth=false);
+
+ virtual int onSetFinalPosition();
+
+ void setBitmaps(wchar_t *left, wchar_t *lpressed, wchar_t *lhilite,
+ wchar_t *right, wchar_t *rpressed, wchar_t *rhilite,
+ wchar_t *button, wchar_t *bpressed, wchar_t *bhilite);
+
+ void setBackgroundBitmaps(const wchar_t *left, const wchar_t *middle, const wchar_t *right);
+
+ void setPosition(int pos);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int getPosition();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int getHeight();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void setHeight(int newheight);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void setNPages(int n);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void gotoPage(int n);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void setUpDownValue(int newupdown);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void setVertical(bool isvertical);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int getWidth();
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void freeResources();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void reloadResources();
+
+private:
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void deleteResources();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int getMousePosition();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void calcOverlapping();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void calcXPosition();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void calcPosition();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void handlePageUpDown();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int checkPageUpDown();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void handleUpDown();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int checkUpDown();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int pageUp();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int pageDown();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ int upDown(int which);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void setPrivatePosition(int pos, bool signal=true, bool smooth=false);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void loadBmps();
+
+ AutoSkinBitmap bmpleft, bmplpressed, bmplhilite,
+ bmpright, bmprpressed, bmprhilite,
+ bmpbutton, bmpbpressed, bmpbhilite,
+ bmpbackgroundleft, bmpbackgroundmiddle, bmpbackgroundright;
+
+ RegionI *leftrgn, *rightrgn, *buttonrgn;
+ int position;
+
+ int moving;
+ int lefting;
+ int righting;
+ int clicked;
+
+ int buttonx;
+
+ int curmouseposition;
+ int clickmouseposition;
+ int height;
+
+ int shiftleft, shiftright;
+ POINT clickpos;
+ int clickbuttonx;
+ int pageing;
+ int firstdelay;
+ int timer;
+ int npages;
+ int pageway;
+ int updown;
+ int timer2;
+ int insetpos;
+
+ int vertical;
+ int lastx, lasty;
+};
+
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/sepwnd.cpp b/Src/Wasabi/api/wnd/wndclass/sepwnd.cpp
new file mode 100644
index 00000000..da45b11b
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/sepwnd.cpp
@@ -0,0 +1,63 @@
+#include <precomp.h>
+
+#include <tataki/bitmap/bitmap.h>
+#include <api/wnd/basewnd.h>
+#include "sepwnd.h"
+#include <tataki/canvas/canvas.h>
+#include <api/wnd/PaintCanvas.h>
+
+SepWnd::SepWnd() {
+ bitmap = NULL;
+ orientation = SEP_UNKNOWN;
+}
+
+SepWnd::~SepWnd() {
+ if (bitmap) delete bitmap;
+}
+
+int SepWnd::onPaint(Canvas *canvas) {
+
+ PaintBltCanvas paintcanvas;
+ if (canvas == NULL) {
+ if (!paintcanvas.beginPaintNC(this)) return 0;
+ canvas = &paintcanvas;
+ }
+
+
+ if (!bitmap) {
+ switch (orientation) {
+ case SEP_VERTICAL:
+ bitmap = new SkinBitmap(L"studio.FrameVerticalDivider");
+ break;
+ case SEP_HORIZONTAL:
+ bitmap = new SkinBitmap(L"studio.FrameHorizontalDivider");
+ break;
+ case SEP_UNKNOWN:
+ return 1;
+ }
+ ASSERT(bitmap != NULL);
+ }
+ RECT r;
+ getClientRect(&r);
+ RenderBaseTexture(canvas, r);
+ if (bitmap) {
+ bitmap->stretchToRectAlpha(canvas, &r, 128);
+ }
+ return 1;
+}
+
+int SepWnd::setOrientation(int which) {
+ orientation = which;
+ return 1;
+}
+
+int SepWnd::onInit() {
+ SEPWND_PARENT::onInit();
+ return 1;
+}
+
+void SepWnd::freeResources() {
+ SEPWND_PARENT::freeResources();
+ if (bitmap) delete bitmap;
+ bitmap = NULL;
+} \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/wndclass/sepwnd.h b/Src/Wasabi/api/wnd/wndclass/sepwnd.h
new file mode 100644
index 00000000..60f55b72
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/sepwnd.h
@@ -0,0 +1,27 @@
+#ifndef __SEPWND_H
+#define __SEPWND_H
+
+#include <tataki/bitmap/bitmap.h>
+#include <api/wnd/virtualwnd.h>
+
+#define SEP_UNKNOWN -1
+#define SEP_VERTICAL 0
+#define SEP_HORIZONTAL 1
+
+#define SEPWND_PARENT VirtualWnd
+
+class SepWnd : public VirtualWnd {
+public:
+ SepWnd();
+ ~SepWnd();
+ virtual int onPaint(Canvas *c);
+ virtual int setOrientation(int which);
+ virtual int onInit();
+ virtual void freeResources();
+private:
+ SkinBitmap *bitmap;
+ int orientation;
+};
+
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/slider.cpp b/Src/Wasabi/api/wnd/wndclass/slider.cpp
new file mode 100644
index 00000000..51157d7f
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/slider.cpp
@@ -0,0 +1,705 @@
+#include <precomp.h>
+#include "slider.h"
+
+#include <tataki/canvas/canvas.h>
+#include <api/wnd/notifmsg.h>
+#include <api/wnd/PaintCanvas.h>
+
+#define DEFAULT_THUMBWIDTH 16
+#define DEFAULT_THUMBHEIGHT 16
+
+SliderWnd::SliderWnd()
+{
+ seeking = 0;
+ enabled = 1;
+ hilite = 0;
+ pos = 0;
+ oldpos = -1;
+ thumbwidth = DEFAULT_THUMBWIDTH;
+ captured = 0;
+ xShift = 0;
+ yShift = 0;
+
+ base_texture = NULL;
+ use_base_texture = 0;
+ no_default_background = 0;
+
+ drawOnBorders = 0;
+ hotPosition = -1;
+ origPos = 0;
+
+ vertical = 0;
+
+ thumbCentered = 1;
+ thumbOffset = 0;
+ thumbStretched = 0;
+ hotposrange = -1;
+ setLimits(START, END);
+}
+
+SliderWnd::~SliderWnd()
+{}
+
+
+int SliderWnd::onPaint(Canvas *canvas)
+{
+ if (canvas == NULL)
+ {
+ PaintBltCanvas paintcanvas;
+ if (!paintcanvas.beginPaint(this))
+ return 0;
+ SliderWnd::onPaint(&paintcanvas);
+ }
+
+ SLIDERWND_PARENT::onPaint(canvas);
+
+ RECT r, origr;
+ getClientRect(&r);
+ origr = r;
+
+ if (use_base_texture)
+ {
+ if (!base_texture)
+ {
+ renderBaseTexture(canvas, r);
+ }
+ else
+ {
+ RECT cr;
+ cr.left = xShift;
+ cr.top = yShift;
+ cr.right = cr.left + (r.right - r.left);
+ cr.bottom = cr.top + (r.bottom - r.top);
+ base_texture->blitToRect(canvas, &cr, &r);
+ }
+ }
+
+ if (vertical)
+ {
+ RECT br;
+ br.left = r.left;
+ br.right = r.right;
+
+ if (left.getBitmap())
+ {
+ br.top = r.top;
+ br.bottom = left.getHeight();
+ left.getBitmap()->stretchToRectAlpha(canvas, &br, getPaintingAlpha());
+ }
+
+ if (right.getBitmap())
+ {
+ br.top = r.bottom - right.getHeight();
+ br.bottom = r.bottom;
+ right.stretchToRectAlpha(canvas, &br, getPaintingAlpha());
+ }
+
+ if (middle.getBitmap())
+ {
+ br.top = r.top + (left.getBitmap() ? left.getHeight() : 0);
+ br.bottom = r.bottom - (right.getBitmap() ? right.getHeight() : 0);
+ middle.getBitmap()->stretchToRectAlpha(canvas, &br, getPaintingAlpha());
+ }
+ }
+ else
+ {
+ RECT br;
+ br.top = r.top;
+ br.bottom = r.bottom;
+
+ if (left.getBitmap())
+ {
+ br.left = r.left;
+ br.right = br.left + left.getWidth();
+ left.getBitmap()->stretchToRectAlpha(canvas, &br, getPaintingAlpha());
+ }
+
+ if (right.getBitmap())
+ {
+ br.left = r.right - right.getWidth();
+ br.right = r.right;
+ right.getBitmap()->stretchToRectAlpha(canvas, &br, getPaintingAlpha());
+ }
+
+ if (middle.getBitmap())
+ {
+ br.left = r.left + (left.getBitmap() ? left.getWidth() : 0);
+ br.right = r.right - (right.getBitmap() ? right.getWidth() : 0);
+ middle.getBitmap()->stretchToRectAlpha(canvas, &br, getPaintingAlpha());
+ }
+ }
+
+ if (vertical)
+ {
+ int w = (r.bottom - r.top) - thumbHeight();
+ // ASSERT(w > 0); // if the control paints off the edge of the screen, this will needlessly assert.
+ if (w < 0) w = 0;
+ r.top += (pos * w) / length;
+ r.bottom = r.top + thumbHeight();
+ if (!thumbStretched)
+ {
+ if (!thumbCentered)
+ {
+ r.left = origr.left + thumbOffset;
+ r.right = origr.left + thumbWidth() + thumbOffset;
+ }
+ else
+ {
+ int w = ((r.right - r.left) - thumbWidth()) / 2;
+ r.left = origr.left + w + thumbOffset;
+ r.right = origr.right - w + thumbOffset;
+ }
+ }
+ else
+ {
+ r.left = origr.left;
+ r.right = origr.right;
+ }
+
+ }
+ else
+ {
+ // offset for left bitmap
+ if (!drawOnBorders)
+ {
+ if (left.getBitmap() != NULL) r.left += left.getWidth();
+ if (right.getBitmap() != NULL) r.right -= right.getWidth();
+ }
+
+ int w = (r.right - r.left) - thumbWidth();
+ if (w < 0) w = 0;
+ r.left += (pos * w) / length;
+ r.right = r.left + thumbWidth();
+ if (r.right > origr.right)
+ {
+ r.left -= r.right - origr.right;
+ r.right = origr.right;
+ }
+
+ if (!thumbStretched)
+ {
+ int thumbh = thumb.getBitmap() ? thumb.getHeight() : DEFAULT_THUMBWIDTH;
+ if (thumbCentered)
+ {
+ int h = ((r.bottom - r.top) - thumbh) / 2;
+ r.top = origr.top + h;
+ r.bottom = origr.bottom - h;
+ }
+ else
+ {
+ r.top = origr.top + thumbOffset;
+ r.bottom = origr.top + thumbh + thumbOffset;
+ }
+ }
+ else
+ {
+ r.top = origr.top;
+ r.bottom = origr.bottom;
+ }
+ }
+
+ SkinBitmap *sb = getSeekStatus() ? (thumbdown.getBitmap() ? thumbdown.getBitmap() : thumb.getBitmap()) : ((hilite && thumbhilite.getBitmap()) ? thumbhilite.getBitmap() : thumb.getBitmap());
+
+ if (sb != NULL)
+ sb->stretchToRectAlpha(canvas, &r, getPaintingAlpha());
+ else
+ canvas->fillRect(&r, RGB(255, 0, 0));
+
+ return 1;
+}
+
+int SliderWnd::onInit()
+{
+ SLIDERWND_PARENT::onInit();
+ if (!no_default_background)
+ {
+ if (vertical)
+ {
+ // Please note that these bitmaps here do not yet exist.
+ if (left.getBitmapName() == NULL) setLeftBmp(L"wasabi.slider.vertical.top");
+ if (middle.getBitmapName() == NULL) setMiddleBmp(L"wasabi.slider.vertical.middle");
+ if (right.getBitmapName() == NULL) setRightBmp(L"wasabi.slider.vertical.bottom");
+ if (thumb.getBitmapName() == NULL) setThumbBmp(L"wasabi.slider.vertical.button");
+ if (thumbdown.getBitmapName() == NULL) setThumbDownBmp(L"wasabi.slider.vertical.button.pressed");
+ }
+ else
+ {
+ if (left.getBitmapName() == NULL) setLeftBmp(L"wasabi.slider.horizontal.left");
+ if (middle.getBitmapName() == NULL) setMiddleBmp(L"wasabi.slider.horizontal.middle");
+ if (right.getBitmapName() == NULL) setRightBmp(L"wasabi.slider.horizontal.right");
+ if (thumb.getBitmapName() == NULL) setThumbBmp(L"wasabi.slider.horizontal.button");
+ if (thumbdown.getBitmapName() == NULL) setThumbDownBmp(L"wasabi.slider.horizontal.button.pressed");
+ }
+ }
+
+
+ return 1;
+}
+
+int SliderWnd::onLeftButtonDown(int x, int y)
+{
+ SLIDERWND_PARENT::onLeftButtonDown(x, y);
+ if (!enabled) return 0;
+ seeking = 1;
+
+ origPos = 0;
+ RECT r;
+ getClientRect(&r);
+ if (vertical)
+ {
+ int w = (r.bottom - r.top) - thumbHeight();
+ if (w < 0) w = 0;
+ r.top += (pos * w) / length;
+ origPos = (y - r.top) - 1;
+ /*if(origPos<0 || origPos>thumbHeight())*/ origPos = (thumbHeight() / 2) - 2;
+ }
+ else
+ {
+ if (!drawOnBorders)
+ {
+ if (left.getBitmap() != NULL) r.left += left.getWidth();
+ if (right.getBitmap() != NULL) r.right -= right.getWidth();
+ }
+ int w = (r.right - r.left) - thumbWidth();
+ if (w < 0) w = 0;
+ r.left += (pos * w) / length;
+ origPos = (x - r.left) - 1;
+ if (origPos < 0 || origPos > thumbWidth()) origPos = (thumbWidth() / 2) - 2;
+ }
+
+ if (!captured)
+ {
+ captured = 1;
+ beginCapture();
+ }
+ oldpos = pos;
+ onMouseMove(x, y);
+ return 1;
+}
+
+//FG>
+//removed cross-hierarchy deletion (crashs due to ancestor in common.dll trying to delete pointers in a different
+//heap scope than the one in which they were allocated)
+void SliderWnd::setBitmaps(const wchar_t *thumbbmp, const wchar_t *thumbdownbmp, const wchar_t *thumbhighbmp, const wchar_t *leftbmp, const wchar_t *middlebmp, const wchar_t *rightbmp)
+{
+ setThumbBmp(thumbbmp);
+ setThumbDownBmp(thumbdownbmp);
+ setThumbHiliteBmp(thumbhighbmp);
+ setLeftBmp(leftbmp);
+ setRightBmp(rightbmp);
+ setMiddleBmp(middlebmp);
+}
+
+void SliderWnd::setLeftBmp(const wchar_t *name)
+{
+ left = name;
+ invalidate();
+}
+
+void SliderWnd::setMiddleBmp(const wchar_t *name)
+{
+ middle = name;
+ invalidate();
+}
+
+void SliderWnd::setRightBmp(const wchar_t *name)
+{
+ right = name;
+ invalidate();
+}
+
+void SliderWnd::setThumbBmp(const wchar_t *name)
+{
+ thumb = name;
+ invalidate();
+}
+
+void SliderWnd::setThumbDownBmp(const wchar_t *name)
+{
+ thumbdown = name;
+ invalidate();
+}
+
+void SliderWnd::setThumbHiliteBmp(const wchar_t *name)
+{
+ thumbhilite = name;
+ invalidate();
+}
+
+SkinBitmap *SliderWnd::getLeftBitmap()
+{
+ return left;
+}
+
+SkinBitmap *SliderWnd::getRightBitmap()
+{
+ return right;
+}
+
+SkinBitmap *SliderWnd::getMiddleBitmap()
+{
+ return middle;
+}
+
+SkinBitmap *SliderWnd::getThumbBitmap()
+{
+ return thumb;
+}
+
+SkinBitmap *SliderWnd::getThumbDownBitmap()
+{
+ return thumbdown;
+}
+
+SkinBitmap *SliderWnd::getThumbHiliteBitmap()
+{
+ return thumbhilite;
+}
+
+int SliderWnd::getWidth()
+{
+ if (vertical)
+ return (getThumbBitmap() ? getThumbBitmap()->getWidth() : 0);
+ else
+ {
+ return 64;
+ }
+}
+
+int SliderWnd::getHeight()
+{
+ if (!vertical)
+ return (getThumbBitmap() ? getThumbBitmap()->getHeight() : 0);
+ else
+ {
+ return 64;
+ }
+}
+
+void SliderWnd::setEnable(int en)
+{
+ if (enabled != en) invalidate();
+ enabled = en;
+}
+
+int SliderWnd::getEnable(void)
+{
+ return enabled;
+}
+
+void SliderWnd::setPosition(int newpos, int wantcb)
+{
+ if (newpos < minlimit) newpos = minlimit;
+ else if (newpos > maxlimit) newpos = maxlimit;
+
+ if (vertical) pos = maxlimit - newpos;
+ else /* horizontal */ pos = newpos - minlimit;
+
+ if (wantcb)
+ onSetPosition();
+
+ invalidate();
+}
+
+int SliderWnd::onMouseMove(int x, int y)
+{
+ int p, w, mouseover;
+
+ SLIDERWND_PARENT::onMouseMove(x, y);
+
+ POINT po = {x, y};
+ clientToScreen(&po);
+ mouseover = (WASABI_API_WND->rootWndFromPoint(&po) == this);
+ if (mouseover && !seeking && !captured)
+ {
+ beginCapture();
+ captured = 1;
+ onEnterArea();
+ }
+ int lasthilite = hilite;
+ hilite = enabled && mouseover;
+ if (hilite != lasthilite)
+ {
+ if (!mouseover && !seeking && captured)
+ {
+ endCapture();
+ captured = 0;
+ onLeaveArea();
+ invalidate();
+ return 0;
+ }
+ invalidate();
+ }
+
+ if (!enabled) return 1;
+
+ RECT r, origr;
+ getClientRect(&r);
+ x -= r.left;
+ y -= r.top;
+
+ origr = r;
+ if (vertical)
+ {
+ w = (r.bottom - r.top) - thumbHeight();
+ // p = (y - (r.top-origr.top)) - (thumbHeight()/2-2);
+ p = (y - (r.top - origr.top)) - origPos;
+ }
+ else
+ {
+ if (!drawOnBorders)
+ {
+ if (left != NULL) r.left += left.getWidth();
+ if (right != NULL) r.right -= right.getWidth();
+ }
+ w = (r.right - r.left) - thumbWidth();
+ // p = (x - (r.left - origr.left)) - (thumbWidth()/2-2);
+ p = (x - (r.left - origr.left)) - origPos;
+ }
+
+ if (seeking)
+ {
+ pos = (p * length) / w;
+ if (pos < 0) pos = 0;
+ else if (pos > length) pos = length;
+
+ if (hotPosition != -1)
+ {
+ int a, c;
+ if (vertical) a = r.bottom - r.top;
+ else a = r.right - r.left;
+ c = getHotPosRange();
+ if (c == -1)
+ {
+ int b = (int)(a * 0.075);
+ c = (b * length) / a;
+ }
+
+ /**
+ EQBand: minlimit -127, maxlimit 127, hotpos 0
+ PanBar: minlimit 0, maxlimit 225, hotpos 127
+
+ VSliders pos starts from top by 0 (winamp behaviour reversed!)
+ */
+
+ if (vertical)
+ {
+ //if (pos > (hotPosition - c) && pos < (hotPosition + c)) pos = hotPosition;
+ if ((maxlimit - pos) > (hotPosition - c) && (maxlimit - pos) < (hotPosition + c)) pos = hotPosition - minlimit; // Hehe, now it works ;)
+ }
+ else
+ {
+ if (pos > (hotPosition - c) && pos < (hotPosition + c)) pos = hotPosition;
+ //if ((pos - maxlimit)> (hotPosition - c) && (pos - maxlimit) < (hotPosition + c)) pos = hotPosition - minlimit;
+ }
+ }
+
+ onSetPosition();
+ invalidate();
+ }
+
+ return 1;
+}
+
+void SliderWnd::onCancelCapture()
+{
+ SLIDERWND_PARENT::onCancelCapture();
+ if (seeking && captured)
+ abort();
+}
+
+int SliderWnd::onLeftButtonUp(int x, int y)
+{
+ SLIDERWND_PARENT::onLeftButtonUp(x, y);
+ int wasseeking = seeking;
+ seeking = 0;
+ captured = 0;
+ oldpos = -1;
+ endCapture();
+ if (wasseeking)
+ onSetFinalPosition();
+ invalidate();
+ return 1;
+}
+
+int SliderWnd::onRightButtonDown(int x, int y)
+{
+ SLIDERWND_PARENT::onRightButtonDown(x, y);
+ if (seeking && captured)
+ {
+ abort();
+ }
+ return 1;
+}
+
+int SliderWnd::onChar(unsigned int c)
+{
+ SLIDERWND_PARENT::onChar(c);
+ if (seeking && captured && (c == 27))
+ {
+ abort();
+ }
+ return 1;
+}
+
+int SliderWnd::onSetPosition()
+{
+ if (!isInited()) return 0;
+ notifyParent(ChildNotify::SLIDER_INTERIM_POSITION, getSliderPosition());
+ return 0;
+}
+
+int SliderWnd::onSetFinalPosition()
+{
+ if (!isInited()) return 0;
+ notifyParent(ChildNotify::SLIDER_FINAL_POSITION, getSliderPosition());
+ return 0;
+}
+
+int SliderWnd::getSliderPosition()
+{
+ if (vertical) return maxlimit -pos;
+ else return pos + minlimit;
+}
+
+int SliderWnd::getSeekStatus()
+{
+ return seeking;
+}
+
+int SliderWnd::thumbWidth()
+{
+ if (thumb.getBitmap() == NULL) return DEFAULT_THUMBWIDTH;
+ return thumb.getWidth();
+}
+
+int SliderWnd::thumbHeight()
+{
+ if (thumb.getBitmap() == NULL) return DEFAULT_THUMBHEIGHT;
+ return thumb.getHeight();
+}
+
+void SliderWnd::setUseBaseTexture(int useit)
+{
+ use_base_texture = useit;
+ invalidate();
+}
+
+void SliderWnd::setBaseTexture(SkinBitmap *bmp, int x, int y)
+{
+ base_texture = bmp;
+ use_base_texture = TRUE;
+ xShift = x;
+ yShift = y;
+ invalidate();
+}
+
+void SliderWnd::setNoDefaultBackground(int no)
+{
+ no_default_background = no;
+}
+
+void SliderWnd::setDrawOnBorders(int draw)
+{
+ drawOnBorders = draw;
+}
+
+void SliderWnd::onEnterArea()
+{
+ SLIDERWND_PARENT::onEnterArea();
+}
+
+void SliderWnd::onLeaveArea()
+{
+ SLIDERWND_PARENT::onLeaveArea();
+}
+
+void SliderWnd::setOrientation(int o)
+{
+ vertical = o;
+}
+
+void SliderWnd::setHotPosition(int h)
+{
+ hotPosition = h;
+}
+
+void SliderWnd::setThumbCentered(int c)
+{
+ thumbCentered = c;
+}
+
+void SliderWnd::setThumbStretched(int c)
+{
+ thumbStretched = c;
+}
+
+
+void SliderWnd::setThumbOffset(int o)
+{
+ thumbOffset = o;
+}
+
+void SliderWnd::abort()
+{
+ if (oldpos != -1)
+ {
+ seeking = 0;
+ captured = 0;
+ endCapture();
+ pos = oldpos;
+ onSetPosition();
+ invalidate();
+ oldpos = -1;
+ }
+ return ;
+}
+
+void SliderWnd::setLimits(int pminlimit, int pmaxlimit)
+{
+ minlimit = pminlimit;
+ maxlimit = pmaxlimit;
+ length = maxlimit - minlimit;
+}
+
+int SliderWnd::onKeyDown(int vkcode)
+{
+ switch (vkcode)
+ {
+ case VK_LEFT: move_left(Std::keyModifier(STDKEY_CONTROL)); return 1;
+ case VK_RIGHT: move_right(Std::keyModifier(STDKEY_CONTROL)); return 1;
+ case VK_HOME: move_start(); return 1;
+ case VK_END: move_end(); return 1;
+ default: return SLIDERWND_PARENT::onKeyDown(vkcode);
+ }
+}
+
+void SliderWnd::move_left(int bigstep)
+{
+ int pos = getSliderPosition();
+ if (!bigstep) pos--; else pos -= (ABS(maxlimit - minlimit) / 10);
+ if (pos < minlimit) pos = minlimit;
+ setPosition(pos);
+}
+
+void SliderWnd::move_right(int bigstep)
+{
+ int pos = getSliderPosition();
+ if (!bigstep)
+ pos++;
+ else
+ pos += (ABS(maxlimit - minlimit) / 10);
+ if (pos > maxlimit)
+ pos = maxlimit;
+ setPosition(pos);
+}
+
+void SliderWnd::move_start()
+{
+ setPosition(minlimit);
+}
+
+void SliderWnd::move_end()
+{
+ setPosition(maxlimit);
+}
diff --git a/Src/Wasabi/api/wnd/wndclass/slider.h b/Src/Wasabi/api/wnd/wndclass/slider.h
new file mode 100644
index 00000000..55c451ea
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/slider.h
@@ -0,0 +1,451 @@
+#ifndef _SLIDER_H
+#define _SLIDER_H
+
+#include <bfc/common.h>
+#include <tataki/bitmap/autobitmap.h>
+#include <api/wnd/wndclass/guiobjwnd.h>
+
+#define SLIDERWND_PARENT GuiObjectWnd
+/**
+ Slider style control.
+
+ @short Slider style control.
+ @author Nullsoft
+ @ver 1.0
+*/
+class SliderWnd : public SLIDERWND_PARENT
+{
+public:
+ /**
+ Sets the defaults for the slider. Defaults to a horizontal
+ slider with the thumb in the center and is enabled.
+ */
+ SliderWnd();
+
+ /**
+ Nothing is handled by the destructor.
+ */
+ virtual ~SliderWnd();
+
+ /**
+ Event is triggered when the window requires a repaint.
+ Override this to implement your own behavior.
+
+ Paints the slider on canvas according to current
+ state of the slider.
+
+ @ret 0, Failed; 1, Success;
+ @param canvas The canvas on which to paint.
+ */
+ virtual int onPaint(Canvas *canvas);
+
+ /**
+ Event is triggered when the left mouse button is pressed while
+ the slider has focus. Override this to implement your
+ own behavior.
+
+ @ret
+ @param x X coordinate of the mouse pointer.
+ @param y Y coordinate of the mouse pointer.
+ */
+ virtual int onLeftButtonDown(int x, int y);
+
+ /**
+ Event is triggered when the mouse has capture on the slider
+ and is being moved. Override this to implement your own
+ behavior.
+
+ @ret 0, Failed; 1, Success;
+ @param x The X position of the mouse.
+ @param y The Y position of the mouse.
+ */
+ virtual int onMouseMove(int x, int y); // only called when mouse captured
+
+ /**
+ Event is triggered when the left mouse button is released.
+ Note that the mouse button must have been previously pressed
+ for this event to happen. Override this to implement your
+ own behavior.
+
+ @ret 1, If you handle the event; 0, If you don't handle the event;
+ @param x The X position of the mouse.
+ @param y The Y position of the mouse.
+ */
+ virtual int onLeftButtonUp(int x, int y);
+
+ /**
+ Event is triggered when the right mouse button is pressed.
+ Override this to implement your own behavior.
+ */
+ virtual int onRightButtonDown(int x, int y);
+
+ /**
+ Event is triggered when a key is pressed and the slider
+ has focus. Override this to implement your own behavior.
+
+ @ret 1, If you handle the event; 0, If you don't handle the event;
+ @param c The key that was pressed.
+ */
+ virtual int onChar(unsigned int c);
+
+ /**
+ Event is triggered when the mouse enters the region
+ of the slider. Override this to implement your
+ own behavior.
+ */
+ virtual void onEnterArea();
+
+ /**
+ Event is triggered when the mouse leaves the region
+ of the slider. Override this to implement your
+ own behavior.
+ */
+ virtual void onLeaveArea();
+
+ /**
+ Event is triggered then the slider is about to be initialized.
+ Override this event to implement your own behavior.
+
+ By default this will render the slider according the it's current settings
+ and position of the thumb.
+
+ @ret 1, Success; 0, Failure;
+ */
+ virtual int onInit();
+
+ /**
+ Constants for positioning of the thumb.
+ */
+ enum {
+ START = 0,
+ END = 65535,
+ FULL = END
+ };
+
+ /**
+ Set the sliders position.
+
+ @param newpos The sliders new position.
+ @param wantcb !0, Generate a callback after the position has been set; 0, No callback;
+ */
+ virtual void setPosition(int newpos, int wantcb=1);
+
+ /**
+ Get the sliders current position. The range is from
+ START (0) to END (65535).
+
+ @ret The sliders position (ranges from 0 to 65535).
+ */
+ int getSliderPosition();
+
+ //void cancelSeek();
+
+ /**
+ Use a base texture when rendering the slider.
+
+ @see setBaseTexture()
+ @param useit 0, Do not use; 1, Use base texture;
+ */
+ void setUseBaseTexture(int useit);
+
+ /**
+ Set the base texture of the slider.
+
+ @see setUseBaseTexture()
+ @see SkinBitmap
+ @param bmp The bitmap to use as a texture.
+ @param x The X position of the base texture.
+ @param y The Y position of the base texture.
+ */
+ void setBaseTexture(SkinBitmap *bmp, int x, int y);
+
+ /**
+ Set the draw area to include the edge borders.
+
+ @param draw 0, Do not include the edges; 1, Include the edges;
+ */
+ void setDrawOnBorders(int draw);
+
+ /**
+ Do not use the default background provided
+ by the current skin?
+
+ If you set this to 1, you MUST specify your bitmaps.
+
+ @param no 0, Use default background; 1, Do not use default;
+ */
+ void setNoDefaultBackground(int no);
+
+ /**
+ Set the bitmaps to be used to render the slider.
+ These include bitmaps for the left, middle, right of
+ the slider. For the thumb, we have bitmaps for the
+ normal, hilited and pushed thumb.
+
+ The bitmaps are set using their xml id or "name".
+ The name should resemble something like this:
+ "studio.seekbar.left".
+
+ @see setLeftBmp()
+ @see setMiddleBmp()
+ @see setRightBmp()
+ @see setThumbBmp()
+ @see setThumbDownBmp()
+ @see setThumbHiliteBmp()
+ @param thumbbmp The normal thumb bitmap name.
+ @param thumbdownbmp The thumb down bitmap name.
+ @param thumbhighbmp The hilited thumb bitmap name.
+ @param leftbmp The left bitmap of the slider name.
+ @param middlebmp The middle bitmap of the slider name.
+ @param rightbmp The right bitmap of the slider name.
+ */
+ void setBitmaps(const wchar_t *thumbbmp, const wchar_t *thumbdownbmp, const wchar_t *thumbhighbmp, const wchar_t *leftbmp, const wchar_t *middlebmp, const wchar_t *rightbmp);
+
+ /**
+ Set the left bitmap of the slider.
+
+ @param name The left bitmap name.
+ */
+ void setLeftBmp(const wchar_t *name);
+
+ /**
+ Set the middle bitmap of the slider.
+
+ @param name The middle bitmap name.
+ */
+ void setMiddleBmp(const wchar_t *name);
+
+ /**
+ Set the right bitmap of the slider.
+
+ @param name The right bitmap name.
+ */
+ void setRightBmp(const wchar_t *name);
+
+ /**
+ Set the normal thumb bitmap of the slider.
+
+ @param name The normal thumb bitmap name.
+ */
+ void setThumbBmp(const wchar_t *name);
+
+ /**
+ Set the thumb down bitmap of the slider.
+
+ @param name The thumb down bitmap name.
+ */
+ void setThumbDownBmp(const wchar_t *name);
+
+ /**
+ Set the hilited thumb bitmap of the slider.
+
+ @param name The hilited thumb bitmap name.
+ */
+ void setThumbHiliteBmp(const wchar_t *name);
+
+ /**
+ Get the height of the slider in pixels.
+
+ @ret The height of the slider (in pixels).
+ */
+ virtual int getHeight();
+
+ /**
+ Get the width of the slider in pixels.
+
+ @ret The width of the slider (in pixels).
+ */
+ virtual int getWidth();
+
+ /**
+ Get the left bitmap of the slider.
+
+ @see SkinBitmap
+ @ret The left SkinBitmap.
+ */
+ SkinBitmap *getLeftBitmap();
+
+ /**
+ Get the right bitmap of the slider.
+
+ @see SkinBitmap
+ @ret The right SkinBitmap.
+ */
+ SkinBitmap *getRightBitmap();
+
+ /**
+ Get the middle bitmap of the slider.
+
+ @see SkinBitmap
+ @ret The middle SkinBitmap.
+ */
+ SkinBitmap *getMiddleBitmap();
+
+ /**
+ Get the thumb bitmap of the slider.
+
+ @see SkinBitmap
+ @ret The thumb SkinBitmap.
+ */
+ SkinBitmap *getThumbBitmap();
+
+ /**
+ Get the thumb down bitmap of the slider.
+
+ @see SkinBitmap
+ @ret The thumb down SkinBitmap.
+ */
+ SkinBitmap *getThumbDownBitmap();
+
+ /**
+ Get the thumb hilite bitmap of the slider.
+
+ @see SkinBitmap
+ @ret The thumb hilite SkinBitmap.
+ */
+ SkinBitmap *getThumbHiliteBitmap();
+
+ /**
+ Set the sliders enable state.
+
+ @param en 1, Enabled; 0, Disabled;
+ */
+
+ virtual void setEnable(int en);
+
+ /**
+ Get the sliders enable state.
+
+ @ret 1, Enabled; 0, Disabled;
+ */
+ virtual int getEnable(void);
+
+ /**
+ Set the orientation of the slider
+ (horizontal or vertical).
+
+ @param o 0, Horizontal; 1, Vertical;
+ */
+ virtual void setOrientation(int o);
+
+ /**
+ This will set a "jump-to" position (like "center" for a balance slider).
+ The parameter is in thumb coordinates (0 to 65535).
+
+ @param h The jump-to position (ranges from 0 to 65535, or START to END).
+ */
+ virtual void setHotPosition(int h);
+ virtual int getHotPosRange() { return hotposrange; }
+ virtual void setHotPosRange(int range) { hotposrange = range; }
+
+ /**
+ Set the thumb center flag. If on, this flag will
+ cause the thumb of the slider to be centered
+ automatically.
+
+ @param c 1, Centered; 0, No centering;
+ */
+ virtual void setThumbCentered(int c);
+ virtual void setThumbStretched(int c);
+
+ /**
+ Set the thumb offset (from the left hand side).
+ This offset will be added to the zero position of the thumb.
+ Note, if you're using centering also, this will cause the slider
+ thumb to be passed the middle of the slider.
+
+ @param o The offset of the thumb (in pixels).
+ */
+ virtual void setThumbOffset(int o);
+
+ /**
+ Set the minimum and maximum limit for the slider.
+
+ @param minlimit The minimum value.
+ @param maxlimit The maximum value.
+ */
+ virtual void setLimits(int minlimit, int maxlimit);
+
+ virtual int getMaxLimit() { return maxlimit; }
+ virtual int getMinLimit() { return minlimit; }
+ virtual int getRange() { return maxlimit-minlimit; }
+
+ virtual int onKeyDown(int vkcode);
+
+ virtual void onCancelCapture();
+protected:
+ /**
+ Abort the current seek and end capture.
+ */
+ void abort();
+
+ // override this to get position change notification
+ /**
+ Event is triggered when the mouse is moving the thumb
+ is being moved. Override this to implment your own behavior.
+
+ @ret The thumb's position (ranges from 0 to 65535 or START to END).
+ */
+ virtual int onSetPosition(); // called constantly as mouse moves
+
+ /**
+ Event is triggered when the thumb is released and the final position
+ is about to be set.
+
+ @ret The thumb's position (ranges from 0 to 65535 or START to END).
+ */
+ virtual int onSetFinalPosition(); // called once after move done
+
+ /**
+ Get the seeking status.
+
+ @ret 1, User is seeking; 0, User is not seeking;
+ */
+ int getSeekStatus(); // returns 1 if user is sliding tab
+
+ int vertical; // set to 1 for up-n-down instead
+
+ /**
+ Get the width of the thumb bitmap, in pixels.
+
+ @ret The thumb's width (in pixels).
+ */
+ int thumbWidth();
+
+ /**
+ Get the height of the thumb bitmap, in pixels.
+
+ @ret The thumb's width (in pixels).
+ */
+ int thumbHeight();
+ // keyboard
+ void move_left(int bigstep);
+ void move_right(int bigstep);
+ void move_start();
+ void move_end();
+
+ int minlimit, maxlimit, length;
+
+private:
+ int seeking;
+ int enabled;
+ int hilite;
+ int pos;
+ int oldpos;
+ int thumbwidth;
+ int captured;
+ int xShift, yShift;
+ SkinBitmap *base_texture;
+ int use_base_texture;
+ int no_default_background;
+ int drawOnBorders;
+ int hotPosition;
+ int origPos;
+ int thumbCentered, thumbOffset, thumbStretched;
+ int hotposrange;
+
+ AutoSkinBitmap left, middle, right;
+ AutoSkinBitmap thumb, thumbdown, thumbhilite;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/status.cpp b/Src/Wasabi/api/wnd/wndclass/status.cpp
new file mode 100644
index 00000000..9ef5af9a
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/status.cpp
@@ -0,0 +1,242 @@
+#include <precomp.h>
+#include "status.h"
+
+#include <tataki/color/skinclr.h>
+#include <tataki/canvas/canvas.h>
+
+#include <api/wnd/wndclass/buttbar.h>
+#include <api/wnd/wndclass/buttwnd.h>
+#include <api/wndmgr/appcmds.h>
+#include <bfc/parse/paramparser.h>
+
+#include <api/script/objects/c_script/c_text.h>
+
+#define STATUS_TIMER_DECAY 1
+
+#define COMPLETED_WIDTH 96
+
+static SkinColor textcolor(L"wasabi.statusbar.text");
+
+class CmdButton : public ButtonWnd
+{
+public:
+ CmdButton(const wchar_t *name, AppCmds *_cmd, int _id) : ButtonWnd(name), cmd(_cmd), id(_id) {}
+
+ virtual void onLeftPush(int x, int y) {
+ cmd->appcmds_onCommand(id, &windowRect(), AppCmds::LEFT_CLICK);
+ }
+
+ virtual void onRightPush(int x, int y) {
+ cmd->appcmds_onCommand(id, &windowRect(), AppCmds::RIGHT_CLICK);
+ }
+
+ virtual int wantAutoContextMenu() { return 0; }
+
+ AppCmds *cmd;
+ int id;
+};
+
+StatusBar::StatusBar() {
+ overtimer = 0;
+ max = 0;
+ completed = 0;
+ progress_width = 0;
+ bg.setContent(L"wasabi.statusbar");
+ bbleft = bbright = NULL;
+}
+
+StatusBar::~StatusBar()
+{
+ killTimer(STATUS_TIMER_DECAY);
+ delete bbleft;
+ delete bbright;
+}
+
+int StatusBar::onInit() {
+ STATUSBAR_PARENT::onInit();
+
+ bg.init(this);
+
+ #ifdef WASABI_COMPILE_WNDMGR
+ getGuiObject()->guiobject_registerStatusCB(this); // watched
+ #endif
+
+ regenerate();
+
+ return 1;
+}
+
+void StatusBar::timerCallback(int id) {
+ switch (id) {
+ case STATUS_TIMER_DECAY: {
+ killTimer(STATUS_TIMER_DECAY);
+ onSetStatusText(status_text, FALSE); // revert to main text
+ }
+ break;
+ default:
+ STATUSBAR_PARENT::timerCallback(id);
+ break;
+ }
+}
+
+void StatusBar::pushCompleted(int _max) {
+ max = MAX(_max, 0);
+ completed = 0;
+
+ GuiObject *outer = bg.findObject(L"wasabi.statusbar.progress.outline");
+ outer->guiobject_setXmlParam(L"visible", L"0");
+ ASSERT(outer != NULL);
+ ifc_window *outerw = outer->guiobject_getRootWnd();
+ RECT cr;
+ outerw->getClientRect(&cr);
+ progress_width = cr.right - cr.left;
+
+ outerw->setVisible(TRUE);//CUT
+ outer->guiobject_setTargetA(255);
+ outer->guiobject_setTargetSpeed(0.1f);
+ outer->guiobject_gotoTarget();
+
+ GuiObject *inner = bg.findObject(L"wasabi.statusbar.progress.inside");
+ inner->guiobject_setTargetA(255);
+ inner->guiobject_setTargetSpeed(1.0f);
+ inner->guiobject_gotoTarget();
+ inner->guiobject_setXmlParam(L"visible", L"0");
+
+ incCompleted(0);
+}
+
+void StatusBar::incCompleted(int add) {
+ setCompleted(completed + add);
+}
+
+void StatusBar::setCompleted(int _completed) {
+ completed = _completed;
+ GuiObject *inner = bg.findObject(L"wasabi.statusbar.progress.inside");
+ ASSERT(inner != NULL);
+ if (!inner->guiobject_getRootWnd()->isVisible(1)) {
+ inner->guiobject_setXmlParam(L"visible", L"1");
+ inner->guiobject_setTargetA(255);
+ inner->guiobject_setTargetSpeed(0.75);
+ inner->guiobject_gotoTarget();
+ }
+ int pos = (int)(((float)completed / (float)max)*(float)progress_width);
+ inner->guiobject_setXmlParam(L"w", StringPrintfW(L"%d", pos));
+}
+
+void StatusBar::popCompleted() {
+ completed = 0;
+ max = 0;
+ GuiObject *inner = bg.findObject(L"wasabi.statusbar.progress.inside");
+ inner->guiobject_setXmlParam(L"w", L"0");
+ inner->guiobject_setTargetA(0);
+ inner->guiobject_setTargetSpeed(0.75);
+ inner->guiobject_gotoTarget();
+
+//CUT later
+ inner->guiobject_setXmlParam(L"visible", L"0");
+ GuiObject *outer = bg.findObject(L"wasabi.statusbar.progress.outline");
+ outer->guiobject_setXmlParam(L"visible", L"0");
+}
+
+int StatusBar::onResize() {
+ STATUSBAR_PARENT::onResize();
+
+ RECT cr = clientRect();
+
+ bbleft->resize(cr.left, cr.top, bbleft->getWidth(), cr.bottom - cr.top);
+
+ bbright->resize(cr.right-bbright->getWidth(), cr.top, bbright->getWidth(), cr.bottom - cr.top);
+
+ cr.left += bbleft->getWidth();
+ cr.right -= bbright->getWidth();
+
+ bg.resizeToRect(&cr); // put bg group in place
+
+ invalidate();
+ return 1;
+}
+
+void StatusBar::onSetStatusText(const wchar_t *text, int overlay)
+{
+ killTimer(STATUS_TIMER_DECAY);
+ if (!overlay)
+ status_text = text;
+ else setTimer(STATUS_TIMER_DECAY, 4000);
+ ScriptObject *tx = bg.findScriptObject(L"wasabi.statusbar.text");
+ if (tx == NULL) return;
+ C_Text(tx).setText(text ? text : L"");
+}
+
+void StatusBar::onAddAppCmds(AppCmds *commands) {
+ if (appcmds.haveItem(commands)) appcmds.removeItem(commands);
+ appcmds.addItem(commands);
+ regenerate();
+}
+
+void StatusBar::onRemoveAppCmds(AppCmds *commands) {
+ if (appcmds.haveItem(commands)) {
+ appcmds.removeItem(commands);
+ regenerate();
+ }
+}
+
+void StatusBar::regenerate() {
+ if (!isInited()) return;
+
+ delete bbleft; bbleft = new ButtBar;
+ delete bbright; bbright = new ButtBar;
+ bbleft->init(this);
+ bbright->init(this);
+
+ ParamParser exclude(exclude_list, L";");
+ ParamParser showonly(include_only, L";");
+
+ foreach(appcmds)
+ int n = appcmds.getfor()->appcmds_getNumCmds();
+ for (int i = 0; i < n; i++) {
+ int side, id;
+ const wchar_t *name = appcmds.getfor()->appcmds_enumCmd(i, &side, &id);
+ if (name == NULL) break;
+ if (exclude.hasString(name)) continue; // exclusion list
+ if (showonly.getNumItems()) {
+ if (!showonly.hasString(name)) continue; // include-only list
+ }
+ CmdButton *cb = new CmdButton(name, appcmds.getfor(), id);
+// cb->setXmlParam("wantfocus", "1");
+ if (side == AppCmds::SIDE_LEFT) bbleft->addChild(cb);
+ else bbright->addChild(cb);
+ }
+ endfor
+ if (isPostOnInit())
+ onResize();
+}
+
+void StatusBar::fakeButtonPush(const wchar_t *name) {
+ if (!fakeButtonPush(bbleft, name))
+ fakeButtonPush(bbright, name);
+}
+
+int StatusBar::fakeButtonPush(ButtBar *bb, const wchar_t *name)
+{
+ for (int i = 0; i < bb->getNumChildren(); i++) {
+ ButtonWnd *cmdb = bb->enumChild(i);
+ if (!WCSICMP(cmdb->getName(), name)) {
+ int x, y;
+ Wasabi::Std::getMousePos(&x, &y);
+ cmdb->screenToClient(&x, &y);
+ cmdb->onLeftPush(x, y);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void StatusBar::setExclude(const wchar_t *val) {
+ exclude_list = val;
+ regenerate();
+}
+
+void StatusBar::setIncludeOnly(const wchar_t *val) {
+ include_only = val;
+ regenerate();
+}
diff --git a/Src/Wasabi/api/wnd/wndclass/status.h b/Src/Wasabi/api/wnd/wndclass/status.h
new file mode 100644
index 00000000..426c0723
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/status.h
@@ -0,0 +1,178 @@
+#ifndef _STATUS_H
+#define _STATUS_H
+
+#include <api/wnd/wndclass/guiobjwnd.h>
+#include <bfc/string/StringW.h>
+#include <api/wndmgr/guistatuscb.h>
+#include <bfc/depend.h>
+
+class ButtBar;
+class AppCmds;
+
+#define STATUSBAR_PARENT GuiObjectWnd
+
+/**
+ Class
+
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see
+*/
+class StatusBar : public STATUSBAR_PARENT, public GuiStatusCallbackI {
+public:
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ StatusBar();
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual ~StatusBar();
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onInit();
+
+ // completeness indicator
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void pushCompleted(int max);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void incCompleted(int add);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void setCompleted(int pos);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void popCompleted();
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void timerCallback(int id);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual int onResize();
+
+ virtual api_dependent *status_getDependencyPtr() { return this; }
+
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void onSetStatusText(const wchar_t *text, int overlay);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void onAddAppCmds(AppCmds *commands);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ virtual void onRemoveAppCmds(AppCmds *commands);
+
+ /**
+ Method
+
+ @see
+ @ret
+ @param
+ */
+ void fakeButtonPush(const wchar_t *name);
+
+protected:
+
+ int fakeButtonPush(ButtBar *bb, const wchar_t *name);
+ void setExclude(const wchar_t *val);
+
+ void setIncludeOnly(const wchar_t *val);
+ StringW exclude_list, include_only;
+
+protected:
+ void regenerate();
+
+private:
+ StringW contentgroupname;
+
+ StringW status_text;
+ int overtimer;
+
+ // completeness
+ int max;
+ int completed;
+ int progress_width;
+
+ GuiObjectWnd bg;
+
+ ButtBar *bbleft, *bbright;
+
+ PtrList<AppCmds> appcmds;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/svcwndhold.cpp b/Src/Wasabi/api/wnd/wndclass/svcwndhold.cpp
new file mode 100644
index 00000000..9620ce4d
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/svcwndhold.cpp
@@ -0,0 +1,53 @@
+#include <precomp.h>
+
+#include "svcwndhold.h"
+
+#include <bfc/common.h>
+
+#include <api/service/svcs/svc_wndcreate.h>
+
+#include <api/wnd/wndclass/blankwnd.h>
+
+ServiceWndHolder::ServiceWndHolder(ifc_window *_child, svc_windowCreate *_svc) :
+ child(NULL), svc(NULL)
+ {
+ setChild(_child, _svc);
+}
+
+ServiceWndHolder::~ServiceWndHolder()
+{
+ if (svc != NULL)
+ {
+ svc->destroyWindow(child);
+ if (!svc->refcount())
+ WASABI_API_SVC->service_release(svc);
+ } else {
+ delete static_cast<BaseWnd*>(child);
+ }
+}
+
+int ServiceWndHolder::setChild(ifc_window *_child, svc_windowCreate *_svc)
+{
+ if (child == _child && svc == _svc) return 0;
+
+ if (child != NULL) {
+ if (svc != NULL) {
+ svc->destroyWindow(child);
+ if (!svc->refcount())
+ WASABI_API_SVC->service_release(svc);
+ svc = NULL;
+ } else {
+ delete static_cast<BaseWnd*>(child);
+ }
+ child = NULL;
+ }
+
+ child = _child;
+ svc = _svc;
+
+ return 1;
+}
+
+ifc_window *ServiceWndHolder::rootwndholder_getRootWnd() {
+ return child ? child : SERVICEWNDHOLDER_PARENT::rootwndholder_getRootWnd();
+}
diff --git a/Src/Wasabi/api/wnd/wndclass/svcwndhold.h b/Src/Wasabi/api/wnd/wndclass/svcwndhold.h
new file mode 100644
index 00000000..d671951e
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/svcwndhold.h
@@ -0,0 +1,51 @@
+#ifndef _SVCWNDHOLD_H
+#define _SVCWNDHOLD_H
+
+#include <api/wnd/wndclass/rootwndholder.h>
+#include <bfc/common.h>
+
+class svc_windowCreate;
+
+// for some reason if this derives from virtualwnd typesheet won't show it
+#define SERVICEWNDHOLDER_PARENT RootWndHolder
+
+/**
+ class ServiceWndHolder .
+
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see
+*/
+class ServiceWndHolder : public SERVICEWNDHOLDER_PARENT {
+public:
+ /**
+ ServiceWndHolder constructor .
+
+ @param _child A pointer to the child we want to set.
+ @param _svc A pointer to the window creation service associated with the window we want to set as a child.
+ */
+ ServiceWndHolder(ifc_window *child=NULL, svc_windowCreate *svc=NULL);
+
+ /**
+ ServiceWndHolder destructor
+ */
+ virtual ~ServiceWndHolder();
+
+ /**
+ ServiceWndHolder method setChild .
+
+ @ret 1
+ @param _child A pointer to the child we want to set.
+ @param _svc A pointer to the window creation service associated with the window we want to set as a child.
+ */
+ int setChild(ifc_window *child, svc_windowCreate *svc);
+
+ virtual ifc_window *rootwndholder_getRootWnd();
+
+private:
+ ifc_window *child;
+ svc_windowCreate *svc;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/tabsheet.cpp b/Src/Wasabi/api/wnd/wndclass/tabsheet.cpp
new file mode 100644
index 00000000..6323fcc2
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/tabsheet.cpp
@@ -0,0 +1,544 @@
+#include "precomp.h"
+#include "tabsheet.h"
+#include "buttwnd.h"
+#include "buttbar.h"
+#include "tabsheetbar.h"
+
+#include <bfc/wasabi_std.h>
+#include <api/wnd/notifmsg.h>
+#include <api/script/objects/c_script/c_text.h>
+#include <api/script/objects/c_script/c_group.h>
+#include <api/wnd/PaintCanvas.h>
+
+TabSheet::TabSheet(int bbtype) {
+ leftscroll = rightscroll = NULL;
+ background = NULL;
+ tabrowmargin = 0;
+ active = NULL;
+ type = bbtype;
+ bb = NULL;
+ tsb = NULL;
+ content_margin_top = content_margin_right = content_margin_left = content_margin_bottom = 0;
+ contentwnd = NULL;
+
+ if (bbtype == TABSHEET_GROUPS) {
+ tsb = new TabSheetBar();
+ tsb->setParent(this);
+ } else { // schweitn rulz
+ bb = new ButtBar((bbtype == -1) ? ButtBar::NORMAL : bbtype);
+ bb->setParent(this);
+ if (bbtype == TABSHEET_NOTABS)
+ bb->setStartHidden(1);
+ }
+}
+
+TabSheet::~TabSheet() {
+ delete bb; // kills tabs and child wnds
+ delete tsb;
+ delete leftscroll;
+ delete rightscroll;
+ delete background;
+ delete contentwnd;
+}
+
+void TabSheet::setButtonType(int _type) {
+ type = _type;
+ if (contentwnd != NULL) {
+ if (type == ButtBar::STACK)
+ contentwnd->setContent(L"wasabi.tabsheet.content.noborder");
+ else if (type != TABSHEET_NOTABS)
+ contentwnd->setContent(L"wasabi.tabsheet.content");
+ else
+ contentwnd->setContent(NULL);
+ }
+ if (_type == TABSHEET_GROUPS && bb != NULL) {
+ PtrList<BaseWnd> l;
+ foreach(tabs)
+ l.addItem(tabs.getfor()->getBaseWnd());
+ tabs.getfor()->setNoDeleteLinked(1);
+ endfor;
+ delete bb; bb = NULL;
+ tabs.removeAll();
+ tsb = new TabSheetBar();
+ tsb->setParent(this);
+ if (isInited())
+ tsb->init(this);
+ foreach(l)
+ addChild(l.enumItem(foreach_index));
+ endfor;
+ } else if (_type != TABSHEET_GROUPS && tsb != NULL) {
+ PtrList<BaseWnd> l;
+ foreach(tabs)
+ l.addItem(tabs.getfor()->getBaseWnd());
+ tabs.getfor()->setNoDeleteLinked(1);
+ endfor;
+ delete tsb; tsb = NULL;
+ tabs.removeAll();
+ bb = new ButtBar((type == -1) ? ButtBar::NORMAL : type);
+ bb->setParent(this);
+ if (type == TABSHEET_NOTABS)
+ bb->setStartHidden(1);
+ if (isInited())
+ bb->init(this);
+ foreach(l)
+ addChild(l.enumItem(foreach_index));
+ endfor;
+ }
+ if (bb != NULL) bb->setResizeMode(type);
+}
+
+void TabSheet::killChildren() {
+ if (bb) {
+ delete bb; // kills tabs and child wnds
+ bb = new ButtBar((type == -1) ? ButtBar::NORMAL : type);
+ bb->setParent(this);
+ if (type == TABSHEET_NOTABS)
+ bb->setStartHidden(1);
+ bb->init(this);
+ }
+ if (tsb) {
+ delete tsb; // kills tabs and child wnds
+ tsb = new TabSheetBar;
+ tsb->setParent(this);
+ tsb->init(this);
+ }
+
+ // mig: if you don't do this, you crash changing tabsheets at runtime.
+ tabs.removeAll();
+ active = NULL;
+}
+
+int TabSheet::onInit() {
+ TABSHEET_PARENT::onInit();
+
+ contentwnd = new GuiObjectWnd;
+ if (type == ButtBar::STACK)
+ contentwnd->setContent(L"wasabi.tabsheet.content.noborder");
+ else if (type != TABSHEET_NOTABS)
+ contentwnd->setContent(L"wasabi.tabsheet.content");
+ else
+ contentwnd->setContent(NULL);
+ contentwnd->setParent(this);
+ contentwnd->init(this);
+ rootwndholder_setRootWnd(contentwnd);
+
+ if (leftscroll != NULL) {
+ leftscroll->init(this);
+ leftscroll->setParent(this);
+ }
+ if (rightscroll != NULL) {
+ rightscroll->init(this);
+ rightscroll->setParent(this);
+ }
+
+ // init the windows
+ foreach(tabs)
+ if (foreach_index != 0) tabs.getfor()->getBaseWnd()->setStartHidden(TRUE);
+ tabs.getfor()->getBaseWnd()->init(this);
+ endfor
+
+ if (bb) {
+ bb->setParent(this);
+ if (type == TABSHEET_NOTABS)
+ bb->setStartHidden(1);
+ bb->init(this); // inits the tabs
+ }
+ if (tsb) {
+ tsb->setParent(this);
+ tsb->init(this); // inits the tabs
+ }
+
+ if (tabs.getNumItems() > 0) {
+ active = tabs[0]->getBaseWnd();
+ //tabs[0]->setHilite(TRUE); // FG: FIX!
+ }
+
+ if (isPostOnInit())
+ onResize();
+
+ return 1;
+}
+
+void TabSheet::getClientRect(RECT *r) {
+ TABSHEET_PARENT::getClientRect(r);
+ if (bb) {
+ if (type != TABSHEET_NOTABS)
+ r->top += bb->getHeight();
+ } else
+ r->top += tsb->getHeight();
+
+ r->left += content_margin_left;
+ r->top += content_margin_top;
+ r->right -= content_margin_right;
+ r->bottom -= content_margin_bottom;
+}
+
+#ifdef WASABI_COMPILE_IMGLDR
+void TabSheet::setBackgroundBmp(const wchar_t *name)
+{
+ if (background) delete background;
+ background = NULL;
+ if (name && *name)
+ background = new SkinBitmap(name);
+}
+#endif
+
+SkinBitmap *TabSheet::getBackgroundBitmap() {
+ return background;
+}
+
+int TabSheet::onPaint(Canvas *canvas) {
+
+ PaintBltCanvas paintcanvas;
+ if (canvas == NULL) {
+ if (!paintcanvas.beginPaintNC(this)) return 0;
+ canvas = &paintcanvas;
+ }
+ TABSHEET_PARENT::onPaint(canvas);
+
+ RECT r;
+ TABSHEET_PARENT::getClientRect(&r);
+
+ if (bb) {
+ if (type != TABSHEET_NOTABS)
+ r.bottom = r.top + bb->getHeight();
+ }
+ else if (tsb)
+ r.bottom = r.top + tsb->getHeight();
+
+ RECT br = r;
+ if (leftscroll) br.left += leftscroll->getWidth();
+ if (rightscroll) br.right -= rightscroll->getWidth();
+
+ if (br.right <= br.left) return 1;
+
+ if (background != NULL) {
+#if 0
+ int i, x = tilex;
+ for (i = 0; ; i++) {
+ tile->stretch(canvas, x, 0, tile->getWidth(), tabrowheight);
+ x += tile->getWidth();
+ if (x >= r.right) break;
+ }
+#else
+#if 0
+ if (background->getAlpha()) api->skin_renderBaseTexture(canvas, br);
+ background->stretchToRectAlpha(canvas, &br);
+#else
+ background->stretchToRect(canvas, &br);
+#endif
+#endif
+ } else {
+#if 0
+ r.top = 0;
+ r.bottom = tabrowheight;
+ r.left = tilex;
+ r.right = tilex + tilew;
+ canvas->fillRect(&r, RGB(64, 64, 64));
+#else
+// api->skin_renderBaseTexture(canvas, r);
+#endif
+ }
+
+ return 1;
+}
+
+void TabSheet::setTabRowMargin(int newmargin) {
+ ASSERT(newmargin >= 0);
+ tabrowmargin = newmargin;
+ onResize();
+}
+
+int TabSheet::addChild(BaseWnd *newchild, const wchar_t *tip) {
+
+ ASSERT(newchild != NULL);
+
+ int first=0;
+ if (tabs.getNumItems() == 0) first = 1;
+
+ if (isInited() && !newchild->isInited()) {
+ if (!first) newchild->setStartHidden(TRUE);
+
+ ifc_window *holder = this;
+ if (contentwnd != NULL) {
+ if (contentwnd->getContentRootWnd() != NULL) {
+ GuiObject *o = contentwnd->getContent()->guiobject_findObject(L"content");
+ if (o != NULL)
+ holder = o->guiobject_getRootWnd();
+ }
+ }
+ newchild->setParent(holder);
+ newchild->init(holder);
+ }
+
+ if (bb)
+ {
+ TabButton *tab = new TabButton(newchild, this, tip);
+ tabs.addItem(tab);
+ bb->addChild(tab);
+ }
+ else if (tsb)
+ {
+ GroupTabButton *tab = new GroupTabButton(newchild, this, tip);
+ tabs.addItem(tab);
+ tsb->addChild(tab);
+ }
+ if (isInited()) {
+ if (first) {
+ activateChild(newchild);
+ }
+ }
+ if (isPostOnInit()) onResize();
+ return tabs.getNumItems()-1;
+}
+
+void TabSheet::activateChild(BaseWnd *newactive) {
+ BaseWnd *prevactive = active;
+ if (newactive == NULL) newactive = active;
+
+ if (prevactive == newactive) return; // not a switch
+
+#if 0
+ RECT r = clientRect();
+
+ int w = r.right - r.left + 1;
+ int h = r.bottom - r.top + 1;
+#endif
+
+ int prevpos=-1, nextpos=-1;
+
+ for (int i = 0; i < tabs.getNumItems(); i++) {
+ if (prevactive == tabs[i]->getBaseWnd()) prevpos = i;
+ if (newactive == tabs[i]->getBaseWnd()) nextpos = i;
+ }
+
+ if (prevpos != -1) tabs[prevpos]->btn_setHilite(FALSE);
+ if (nextpos < tabs.getNumItems()) tabs[nextpos]->btn_setHilite(TRUE);
+
+#if 0
+ // reveal tha new winder
+ if (newactive!= NULL) newactive->setVisible(TRUE);
+
+ enable(FALSE);
+ if (prevactive!= NULL) prevactive->enable(FALSE);
+ if (newactive!= NULL) newactive->enable(FALSE);
+
+#define STEPS 6
+
+ // find which window is now active
+ for (int c = 0; c < STEPS; c++) {
+ int x;
+ if (prevpos > nextpos) x = (w * c) / STEPS; // right to left
+ else x = (w * (STEPS - c)) / STEPS; // left to right
+ int y = r.top;
+ if (prevpos > nextpos) {
+ if (newactive!= NULL) newactive->move(x - w, y);
+ if (prevactive!= NULL) prevactive->move(x, y);
+ } else {
+ if (newactive!= NULL) newactive->move(x, y);
+ if (prevactive!= NULL) prevactive->move(x - w, y);
+ }
+ if (newactive!= NULL) newactive->repaint();
+ if (prevactive!= NULL) prevactive->repaint();
+ Sleep(15);
+ }
+#endif
+
+ if (newactive!= NULL) newactive->setVisible(TRUE);
+
+ if (prevactive!= NULL) prevactive->setVisible(FALSE);
+
+#if 0
+ enable(TRUE);
+ if (prevactive!= NULL) prevactive->enable(TRUE);
+ if (newactive!= NULL) newactive->enable(TRUE);
+#endif
+
+ if (bb && newactive)
+ bb->setGroupLabel(newactive->getName());
+ active = newactive;
+ onSetPage(nextpos);
+}
+
+int TabSheet::onResize() {
+ TABSHEET_PARENT::onResize();
+
+ if (!isInited()) return 1;
+
+ RECT r = clientRect();
+
+ // put buttbar at the top
+ if (bb) bb->resize(r.left, r.top-bb->getHeight(), r.right-r.left, bb->getHeight()+1);
+ if (tsb) tsb->resize(r.left, r.top-tsb->getHeight(), r.right-r.left, tsb->getHeight()+1);
+
+ // resize content group if it's there
+ if (contentwnd) {
+ contentwnd->resize(&r);
+ // since its holder is not resizing its content, we need to do it ourselves
+ foreach(tabs)
+ BaseWnd *c = tabs.getfor()->getBaseWnd();
+ if (c->getParent() != NULL && c->getParent() != this && c->getParent()->getParent() == contentwnd->getContentRootWnd()) {
+ RECT r;
+ c->getParent()->getClientRect(&r);
+ c->resize(&r);
+ } else {
+ // if we're holding it directly, resize it to our rect
+ c->resize(&r);
+ }
+ endfor
+ }
+
+ invalidate();
+ if (leftscroll)
+ leftscroll->invalidate();
+ if (rightscroll)
+ rightscroll->invalidate();
+
+ return 1;
+}
+
+BaseWnd *TabSheet::enumChild(int child) {
+ TabButtonBase *tb = tabs[child];
+ if (tb == NULL) return NULL;
+ return tb->getBaseWnd();
+}
+
+int TabSheet::getNumChild() {
+ return tabs.getNumItems();
+}
+
+void TabSheet::setCurPage(int page) {
+ BaseWnd *e = enumChild(page);
+ if (e != NULL) activateChild(e);
+}
+
+TabButtonBase *TabSheet::enumButton(int i) {
+ if (i < tabs.getNumItems())
+ return tabs[i];
+ else
+ return NULL;
+}
+
+int TabSheet::childNotify(ifc_window *child, int msg, intptr_t param1, intptr_t param2) {
+ if (msg == ChildNotify::NAMECHANGED)
+ {
+ foreach(tabs)
+ ifc_window *w = tabs.getfor()->getBaseWnd();
+ if (w == child || w == child->getParent()) {
+ const wchar_t *name = child->getRootWndName();
+ tabs.getfor()->btn_setText(name && *name ? name : L"[?]");
+ }
+ endfor;
+ }
+ if (msg == ChildNotify::GROUPRELOAD && child == contentwnd) {
+ foreach(tabs)
+ ifc_window *holder = this;
+ if (contentwnd->getContentRootWnd() != NULL) {
+ GuiObject *o = contentwnd->getContent()->guiobject_findObject(L"content");
+ if (o != NULL)
+ holder = o->guiobject_getRootWnd();
+ }
+ tabs.getfor()->getBaseWnd()->reparent(holder);
+ endfor;
+ }
+ return TABSHEET_PARENT::childNotify(child, msg, param1, param2);
+}
+
+
+void TabSheet::setContentMarginLeft(int cm) {
+ content_margin_left = cm;
+ if (isInited())
+ onResize();
+}
+
+void TabSheet::setContentMarginTop(int cm) {
+ content_margin_top = cm;
+ if (isInited())
+ onResize();
+}
+
+void TabSheet::setContentMarginRight(int cm) {
+ content_margin_right = cm;
+ if (isInited())
+ onResize();
+}
+
+void TabSheet::setContentMarginBottom(int cm) {
+ content_margin_bottom = cm;
+ if (isInited())
+ onResize();
+}
+
+int TabSheet::onAction(const wchar_t *action, const wchar_t *param, int x, int y, intptr_t p1, intptr_t p2, void *data, size_t datalen, ifc_window *source) {
+ if (!WCSICMP(action, L"Tabsheet:NextPage")) { nextPage(); return 1; }
+ if (!WCSICMP(action, L"Tabsheet:PreviousPage")) { previousPage(); return 1; }
+ return TABSHEET_PARENT::onAction(action, param, x, y, p1, p2, data, datalen, source);
+}
+
+// TabButton
+
+TabButtonBase::TabButtonBase(BaseWnd *linkwnd, TabSheet *par, const wchar_t *tip)
+: linked(linkwnd), parent(par) {
+ nodeletelinked = 0;
+ ASSERT(linked != NULL);
+}
+
+TabButtonBase::~TabButtonBase() {
+ if (!nodeletelinked) delete linked;
+}
+
+int TabButton::onInit()
+{
+ TABBUTTON_PARENT::onInit();
+ setButtonText(linked->getNameSafe(L"[?]"));
+ return 1;
+}
+
+void TabButton::onLeftPush(int x, int y) {
+ ASSERT(parent != NULL);
+ ASSERT(linked != NULL);
+ parent->activateChild(linked);
+}
+
+void TabButton::btn_setHilite(int tf) {
+ setHilite(tf);
+}
+
+void TabButton::btn_setText(const wchar_t *text)
+{
+ setButtonText(text);
+}
+
+// GroupTabButton
+
+void GroupTabButton::grouptoggle_onLeftPush() {
+ GROUPTABBUTTON_PARENT::grouptoggle_onLeftPush();
+ ASSERT(parent != NULL);
+ ASSERT(linked != NULL);
+ parent->activateChild(linked);
+}
+
+void GroupTabButton::btn_setHilite(int tf) {
+ setStatus(tf ? STATUS_ON : STATUS_OFF);
+}
+
+void GroupTabButton::btn_setText(const wchar_t *text)
+{
+ for (int i=0;i<getNumGroups();i++) {
+ GuiObject *grp = enumGroups(i)->getContent();
+ if (grp != NULL) {
+ GuiObject *o = grp->guiobject_findObject(L"text");
+ if (o != NULL) {
+ C_Text txt(o->guiobject_getScriptObject());
+ txt.setText(text);
+ }
+ }
+ }
+}
+
+int GroupTabButton::onInit() {
+ int rt = GROUPTABBUTTON_PARENT::onInit();
+ btn_setText(linked->getNameSafe(L"[?]"));
+ return rt;
+}
+
diff --git a/Src/Wasabi/api/wnd/wndclass/tabsheet.h b/Src/Wasabi/api/wnd/wndclass/tabsheet.h
new file mode 100644
index 00000000..73426ec9
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/tabsheet.h
@@ -0,0 +1,268 @@
+#ifndef _TABSHEET_H
+#define _TABSHEET_H
+
+#include <api/skin/widgets/grouptgbutton.h>
+#include <api/wnd/wndclass/buttwnd.h>
+#include <bfc/common.h>
+#include <api/wnd/wndclass/guiobjwnd.h>
+#include <bfc/ptrlist.h>
+
+class ButtonWnd;
+class SkinBitmap;
+class TabButtonBase;
+class ButtBar;
+class TabSheetBar;
+
+#define TABSHEET_GROUPS -2
+#define TABSHEET_NOTABS -3
+
+#define TABSHEET_PARENT GuiObjectWnd
+/**
+ class TabSheet
+
+ @short A TabSheet Control.
+ @author Nullsoft
+ @ver 1.0
+ @see
+ @cat SDK
+*/
+class TabSheet : public TABSHEET_PARENT
+{
+public:
+ /**
+ TabSheet constructor
+
+ @see ~TabSheet()
+ @param bbtype The type of button bar to use in the tabsheet.
+ */
+ TabSheet(int bbtype=-1);
+
+ /**
+ TabSheet destructor
+ @see TabSheet()
+ */
+ virtual ~TabSheet();
+
+ /**
+ TabSheet method onInit
+ @ret 1
+ */
+ virtual int onInit();
+
+ /**
+ TabSheet method getClientRect
+
+ @param r A pointer to the RECT that will be filled.
+ */
+ virtual void getClientRect(RECT *);
+
+ /**
+ TabSheet method onPaint
+
+ @ret 1
+ @param canvas The canvas upon which we'll paint ourself.
+ */
+ virtual int onPaint(Canvas *canvas);
+
+ /**
+ TabSheet method onResize
+
+ @ret 1
+ */
+ virtual int onResize();
+
+ /**
+ TabSheet method setButtonType .
+
+ @param type The button type.
+ */
+ void setButtonType(int type);
+
+ /**
+ TabSheet method setTabRowMargin
+
+ @assert newmargin is non-negative
+ @param newmargin The new margin width in pixels.
+ */
+ void setTabRowMargin(int pixels);
+
+ /**
+ TabSheet method addChild
+
+ @ret One less than the number of tabs
+ @param newchild A pointer to the new child window to add.
+ @param tip The tooltip for the button associated with this child.
+ */
+ int addChild(BaseWnd *newchild, const wchar_t *tooltip=NULL);
+
+ /**
+ TabSheet method activateChild
+
+ @see addChild()
+ @see killChildren()
+ @ret None
+ @param newactive A pointer to the child window to render active.
+ */
+ virtual void activateChild(BaseWnd *activechild);
+
+ /**
+ TabSheet method killChildren .
+ */
+ virtual void killChildren();
+
+ /**
+ TabSheet method childNotify .
+
+ @ret Returns 1 when complete.
+ @param child The child that's being notified.
+ @param msg The message.
+ @param param1 Custom parameter 1.
+ @param param2 Custom parameter 2.
+ */
+ virtual int childNotify(ifc_window *child, int msg,
+ intptr_t param1=0, intptr_t param2=0);
+
+ void setContentMarginLeft(int cm);
+ void setContentMarginTop(int cm);
+ void setContentMarginRight(int cm);
+ void setContentMarginBottom(int cm);
+
+ /**
+ TabSheet method enumChild
+ @ret The base window of the specified tab button, or NULL if there is none.
+ */
+ BaseWnd *enumChild(int child);
+
+ /**
+ TabSheet method getNumChild
+ @ret The number of tabs
+ */
+ int getNumChild();
+
+ BaseWnd *getActiveChild() { return active; }
+ virtual void onSetPage(int n) { lastpage = n; }
+ int getCurPage() { return lastpage; }
+ void setCurPage(int page);
+ int getNumPages() { return tabs.getNumItems(); }
+ void nextPage() { int n = getCurPage()+1; if (n >= getNumPages()) n = 0; setCurPage(n); }
+ void previousPage() { int n = getCurPage()-1; if (n < 0) n = getNumPages()-1; setCurPage(n); }
+ int onAction(const wchar_t *action, const wchar_t *param, int x, int y, intptr_t p1, intptr_t p2, void *data, size_t datalen, ifc_window *source);
+
+protected:
+ /** TabSheet method enumButton
+ @ret The specified tab, or NULL if there is none. */
+ TabButtonBase *enumButton(int button);
+
+public:
+ /**
+ TabSheet method setBackgroundBmp
+
+ @param name The name of the bitmap to use.
+ */
+#ifdef WASABI_COMPILE_IMGLDR
+ void setBackgroundBmp(const wchar_t *name); //FG
+#endif
+ SkinBitmap *getBackgroundBitmap(); //FG
+
+protected:
+ // you can set these in your constructor, they will be deleted for you
+ ButtonWnd *leftscroll, *rightscroll;
+ SkinBitmap *background;
+
+private:
+ int tabrowheight, tabrowwidth, tabrowmargin;
+ PtrList<TabButtonBase> tabs;
+
+ ButtBar *bb;
+ TabSheetBar *tsb;
+ GuiObjectWnd *contentwnd;
+
+ int tilex, tilew;
+
+ BaseWnd *active;
+ int type;
+ int content_margin_left, content_margin_top, content_margin_right, content_margin_bottom;
+ int lastpage;
+};
+
+class TabButtonBase
+{
+ public:
+ TabButtonBase(BaseWnd *linkWnd, TabSheet *par, const wchar_t *tip=NULL);
+ virtual ~TabButtonBase();
+
+ BaseWnd *getBaseWnd() const { return linked; }
+ void setNoDeleteLinked(int i) { nodeletelinked = i; }
+
+ virtual void btn_setHilite(int tf)=0;
+ virtual void btn_setText(const wchar_t *txt)=0;
+
+ protected:
+ BaseWnd *linked;
+ TabSheet *parent;
+ int nodeletelinked;
+};
+
+#define TABBUTTON_PARENT ButtonWnd
+
+/**
+ Class TabButton
+
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see TabButtonBase
+ @cat SDK
+*/
+class TabButton : public TABBUTTON_PARENT, public TabButtonBase {
+public:
+ /**
+ TabButton constructor
+
+ @assert The BaseWnd passed to this method must previously be linked.
+ @param linkwnd The window to associate with this button.
+ @param par A pointer to the parent tabsheet.
+ @param tip The tooltip for the window associated with this button.
+ */
+ TabButton(BaseWnd *linkWnd, TabSheet *par, const wchar_t *tip=NULL) : TabButtonBase(linkWnd, par, tip)
+ {
+ if (tip != NULL)
+ setTip(tip);
+ }
+
+ /**
+ TabButton method onInit
+
+ @ret 1
+ */
+ virtual int onInit();
+
+ /**
+ TabButton method onLeftPush .
+
+ @assert parent and linked both exist.
+ @param x The X position, of the mouse pointer, in the client screen.
+ @param y The Y position, of the mouse pointer, in the client screen.
+ */
+ virtual void onLeftPush(int x, int y);
+ virtual void btn_setHilite(int tf);
+ virtual void btn_setText(const wchar_t *text);
+};
+
+
+#define GROUPTABBUTTON_PARENT GroupToggleButton
+class GroupTabButton : public GROUPTABBUTTON_PARENT, public TabButtonBase {
+public:
+ GroupTabButton(BaseWnd *linkWnd, TabSheet *par, const wchar_t *tip=NULL) : TabButtonBase(linkWnd, par, tip)
+ {
+ setGroups(L"wasabi.tabsheet.button.selected.group", L"wasabi.tabsheet.button.unselected.group");
+ }
+ virtual int wantFullClick() { return 0; }
+ virtual int wantAutoToggle() { return 0; }
+ virtual int onInit();
+ virtual void grouptoggle_onLeftPush();
+ virtual void btn_setHilite(int tf);
+ virtual void btn_setText(const wchar_t *text);
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/tabsheetbar.cpp b/Src/Wasabi/api/wnd/wndclass/tabsheetbar.cpp
new file mode 100644
index 00000000..f31dbc73
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/tabsheetbar.cpp
@@ -0,0 +1,130 @@
+#include "precomp.h"
+#include "tabsheetbar.h"
+#include "tabsheet.h"
+#include "../notifmsg.h"
+
+TabSheetBar::TabSheetBar() {
+ margin = 0;
+ spacing = -4;
+ maxheightsofar = 0;
+ bottombar.setParent(this);
+}
+
+TabSheetBar::~TabSheetBar()
+{
+ btns.deleteAll();
+}
+
+int TabSheetBar::onInit() {
+ int rt = TABSHEETBAR_PARENT::onInit();
+
+ bottombar.setContent(L"wasabi.tabsheet.nobutton.group");
+ bottombar.init(this);
+
+ foreach(btns)
+ GroupTabButton *gtb = btns.getfor();
+ gtb->setParent(this);
+ if (!gtb->isInited()) {
+ gtb->init(this);
+ }
+ if (foreach_index == 0)
+ gtb->setStatus(STATUS_ON);
+ else
+ gtb->setStatus(STATUS_OFF);
+ int h = gtb->getPreferences(SUGGESTED_H);
+ if (h == AUTOWH) h = maxheightsofar;
+ maxheightsofar = MAX(maxheightsofar, h);
+ endfor;
+
+ return rt;
+}
+
+void TabSheetBar::addChild(GroupTabButton *child) {
+ ASSERT(!btns.haveItem(child));
+ btns.addItem(child);
+ if (isInited()) {
+ child->setParent(this);
+ if (!child->isInited()) {
+ child->init(this);
+ }
+ int h = child->getPreferences(SUGGESTED_H);
+ if (h == AUTOWH) h = maxheightsofar;
+ maxheightsofar = MAX(maxheightsofar, h);
+ onResize();
+ }
+ if (btns.getNumItems() == 1)
+ child->setStatus(STATUS_ON);
+ else
+ child->setStatus(STATUS_OFF);
+}
+
+int TabSheetBar::getHeight() {
+ return maxheightsofar;
+}
+
+int TabSheetBar::onResize() {
+ int rt = TABSHEETBAR_PARENT::onResize();
+ GroupTabButton *selected=NULL;
+ foreach(btns)
+ if (btns.getfor()->getStatus() == STATUS_ON) {
+ selected = btns.getfor();
+ break;
+ }
+ endfor;
+ if (selected == NULL) selected = btns.getFirst();
+
+ RECT r;
+ getClientRect(&r);
+
+ int x = margin;
+
+ foreach(btns)
+ GroupTabButton *gtb = btns.getfor();
+
+ int w = gtb->getPreferences(SUGGESTED_W);
+ if (w == AUTOWH) w = 66;
+
+ RECT dr;
+ dr.left = r.left + x;
+ dr.top = r.top;
+ dr.right = dr.left + w;
+ dr.bottom = dr.top + getHeight();
+
+ gtb->resize(&dr);
+
+ x += w + spacing;
+ endfor;
+
+ x -= spacing;
+ RECT dr;
+ dr.left = r.left + x;
+ dr.top = r.top;
+ dr.right = r.right;
+ dr.bottom = r.top + getHeight();
+ bottombar.resize(&dr);
+
+ if (selected != NULL)
+ selected->bringToFront();
+
+ return rt;
+}
+
+int TabSheetBar::childNotify(ifc_window *child, int msg, intptr_t param1/* =0 */, intptr_t param2/* =0 */) {
+ if (msg == ChildNotify::GROUPCLICKTGBUTTON_CLICKED && btns.haveItem(static_cast<GroupTabButton *>(child))) {
+ GroupToggleButton *but = NULL;
+ foreach(btns)
+ if (btns.getfor() != child)
+ btns.getfor()->setStatus(STATUS_OFF);
+ else
+ but = btns.getfor();
+ endfor;
+ if (but != NULL)
+ but->setStatus(STATUS_ON);
+ else
+ (static_cast<GroupToggleButton *>(child))->setStatus(STATUS_ON);
+ onResize();
+ }
+ if (msg == ChildNotify::AUTOWHCHANGED && btns.haveItem(static_cast<GroupTabButton *>(child)) && isPostOnInit())
+ onResize();
+ return TABSHEETBAR_PARENT::childNotify(child, msg, param1, param2);
+} \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/wndclass/tabsheetbar.h b/Src/Wasabi/api/wnd/wndclass/tabsheetbar.h
new file mode 100644
index 00000000..3070e8eb
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/tabsheetbar.h
@@ -0,0 +1,39 @@
+#ifndef __TABSHEETBAR_H
+#define __TABSHEETBAR_H
+
+#include <api/wnd/wndclass/guiobjwnd.h>
+
+class GroupTabButton;
+
+#define TABSHEETBAR_PARENT GuiObjectWnd
+
+
+/**
+ Class
+
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see
+*/
+class TabSheetBar : public TABSHEETBAR_PARENT
+{
+public:
+ TabSheetBar();
+ virtual ~TabSheetBar();
+ virtual int onInit();
+ virtual int onResize();
+ virtual void addChild(GroupTabButton *child);
+ virtual int getHeight();
+ virtual int childNotify(ifc_window *child, int msg, intptr_t param1 = 0, intptr_t param2 = 0);
+ void setMargin(int m) { margin = m; if (isInited()) onResize(); }
+ void setSpacing(int s) { spacing = s; if (isInited()) onResize(); }
+
+private:
+ int maxheightsofar;
+ PtrList<GroupTabButton> btns;
+ int margin, spacing;
+ GuiObjectWnd bottombar;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/textbar.cpp b/Src/Wasabi/api/wnd/wndclass/textbar.cpp
new file mode 100644
index 00000000..ae695419
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/textbar.cpp
@@ -0,0 +1,148 @@
+#include "precomp.h"
+
+#include "textbar.h"
+
+#include <bfc/ifc_canvas.h>
+#include <bfc/string/string.h>
+#include <bfc/skinclr.h>
+#include <bfc/autobitmap.h>
+#include <common/checkwnd.h>
+
+static SkinColor bgcolor("wasabi.textBar.background", "Text backgrounds");
+static SkinColor fgcolor("wasabi.textBar.text");
+
+TextBar::TextBar() {
+ size = 16;
+ usebt = 0;
+ alignment = TEXTALIGN_LEFT; //set default alignment
+ checkwndtarget = NULL;
+
+ textshadowed = 1; // display a shadow of the text in bgcolor. default: on
+ textoutlined = 0; // draw an outline of the text in bgcolor. default: off
+ drawbox = 0; // draw a box of bgcolor the size of the boundsrect. default: off
+
+// bgbitmap = "studio.textBar.background";
+}
+
+int TextBar::onLeftButtonDown(int x, int y) {
+ TEXTBAR_PARENT::onLeftButtonDown(x, y);
+ if (checkwndtarget) checkwndtarget->toggle();
+ return 1;
+}
+
+void TextBar::setUseBaseTexture(int u) {
+ usebt = u;
+ invalidate();
+}
+
+int TextBar::onPaint(Canvas *canvas) {
+ RECT r;
+
+ PaintCanvas paintcanvas;
+ if (canvas == NULL) {
+ if (!paintcanvas.beginPaint(this)) return 0;
+ canvas = &paintcanvas;
+ }
+ TEXTBAR_PARENT::onPaint(canvas);
+
+ getClientRect(&r);
+
+ if (!usebt) {
+ if (drawbox) {
+ canvas->fillRect(&r, bgcolor);
+ }
+/*
+ if (bgbitmap.getBitmap()->isInvalid())
+ canvas->fillRect(&r, bgcolor);
+ else {
+ RECT br;
+ br.left = 0;
+ br.top = 0;
+ br.right = bgbitmap.getWidth();
+ br.bottom = bgbitmap.getHeight();
+ bgbitmap.getBitmap()->blitToRect(canvas, &br, &r, 255);
+ }
+*/
+ } else
+ renderBaseTexture(canvas, r);
+
+ const char *name = getName();
+
+ if (name != NULL) {
+ canvas->setTextOpaque(FALSE);
+ canvas->pushTextSize(size);
+ int w, h;
+ canvas->getTextExtent(name, &w, &h);
+ int y = (r.bottom-r.top - h) / 2;
+// int x = centered ? (r.right-r.left - w) / 2 : TEXTBAR_LEFTMARGIN; //teh old code
+
+ int x = 0;
+ switch (alignment) {
+ default:
+ case TEXTALIGN_LEFT: x = TEXTBAR_LEFTMARGIN; break;
+ case TEXTALIGN_CENTER: x = (r.right-r.left - w) / 2; break;
+ case TEXTALIGN_RIGHT: x = (r.right-r.left - w); break;
+ }
+
+ if (!drawbox && textoutlined) {
+ canvas->setTextColor(bgcolor);
+ canvas->textOut(r.left+x+1, r.top+y+1, getName());
+ canvas->setTextColor(bgcolor);
+ canvas->textOut(r.left+x+1, r.top+y-1, getName());
+ canvas->setTextColor(bgcolor);
+ canvas->textOut(r.left+x-1, r.top+y+1, getName());
+ canvas->setTextColor(bgcolor);
+ canvas->textOut(r.left+x-1, r.top+y-1, getName());
+ } else if (!drawbox && textshadowed) {
+ canvas->setTextColor(bgcolor);
+ canvas->textOut(r.left+x+1, r.top+y+1, getName());
+ }
+ canvas->setTextColor(fgcolor);
+ canvas->textOut(r.left+x, r.top+y, getName());
+ canvas->popTextSize();
+ }
+ return 1;
+}
+
+int TextBar::setTextSize(int newsize) {
+ if (newsize < 1 || newsize > 72) return 0;
+ size = newsize;
+ invalidate();
+ return 1;
+}
+
+int TextBar::setInt(int i) {
+ setName(StringPrintf(i));
+ invalidate();
+ return 1;
+}
+
+void TextBar::onSetName() {
+ TEXTBAR_PARENT::onSetName();
+ invalidate();
+}
+
+int TextBar::getTextWidth() {
+ if (!getName()) return 0;
+ BltCanvas *c = new BltCanvas(10, 10);
+ c->pushTextSize(size);
+ int r = c->getTextWidth(getName());
+ c->popTextSize();
+ delete c;
+ return r+4;
+}
+
+int TextBar::getTextHeight() {
+ return size;
+}
+
+void TextBar::setAlign(TextAlign align) {
+ if (alignment != align) {
+ alignment = align;
+ invalidate();
+ }
+}
+
+TextAlign TextBar::getAlign() {
+ return alignment;
+}
diff --git a/Src/Wasabi/api/wnd/wndclass/textbar.h b/Src/Wasabi/api/wnd/wndclass/textbar.h
new file mode 100644
index 00000000..6c6cb97e
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/textbar.h
@@ -0,0 +1,219 @@
+//PORTABLE
+#ifndef _TEXTBAR_H
+#define _TEXTBAR_H
+
+#include <bfc/virtualwnd.h>
+#include <bfc/autobitmap.h>
+#include <bfc/textalign.h>
+
+class CheckWnd;
+
+#define TEXTBAR_PARENT VirtualWnd
+/**
+ TextBar uses the BaseWnd name field of the object as the text
+ to be displayed.
+
+ @short TextBar control.
+ @author Nullsoft
+ @ver 1.0
+ @see LabelWnd
+*/
+class TextBar : public VirtualWnd {
+public:
+ /**
+ Sets the default flags of the TextBar. Defaults to 16px fonts,
+ no background texture, left justified text, shadowed text in
+ the bgcolor, no outline, not box around the text.
+ */
+ TextBar();
+
+ /**
+ Event is triggered when the window requires a repaint.
+ Override this to implement your own behavior.
+
+ Paints the bitmap on canvas according to current
+ options (centering, tiling, stretching, title).
+
+ @ret 0 for failure, 1 for success
+ @param canvas The canvas on which to paint.
+ */
+ virtual int onPaint(Canvas *canvas);
+
+ /**
+ Event is triggered when the name of the window is changed.
+ Override this to implement your own behavior.
+
+ @see BaseWnd::setName()
+ */
+ virtual void onSetName();
+
+ /**
+ Set the text to be displayed to an ascii representation of a numeric value.
+
+ @ret 1.
+ @param i The numeric value to be displayed.
+ */
+ int setInt(int i);
+
+ /**
+ Set the size of the text for the textbar.
+
+ @ret 1, success; 0, failure.
+ @param newsize The new text size, range is from 1 to 72 pixels.
+ */
+ int setTextSize(int newsize);
+
+ /**
+ Get the width of the text displayed, in pixels.
+
+ @ret Width of the displayed text (in pixels).
+ */
+ int getTextWidth();
+
+ /**
+ Get the height of the text displayed, in pixels.
+
+ @ret Height of the displayed text.
+ */
+ int getTextHeight();
+
+ /**
+ Use the base texture when rendering the TextBar?
+ If the base texture is used, it will be rendered as
+ the background of the textbar.
+
+ @param u !0, Use base texture; 0, Do not use base texture;
+ */
+ void setUseBaseTexture(int u);
+
+ /**
+ Event is triggered when the left mouse button is pressed while
+ the textbar has focus. Override this to implement your
+ own behavior.
+
+ @param x X coordinate of the mouse pointer.
+ @param y Y coordinate of the mouse pointer.
+ */
+ virtual int onLeftButtonDown(int x, int y);
+
+ /**
+ Center the text in the textbar? If not,
+ it will be left justified by default.
+
+ @param center !0, Center text; 0, Do not center text;
+ */
+// void setCenter(int center); //old code
+
+ /**
+ Get the center text flag.
+
+ @see setCenter()
+ @ret TRUE, Text is being centered; FALSE, No centering (left justified);
+ */
+// bool getCentered();
+
+ /**
+ Sets the alignment of the text to left, center, or right aligned
+ (possibly more later on, not too sure yet)
+ */
+ void setAlign(TextAlign alignment);
+
+ /**
+ @ret returns the alignment of the text
+ */
+ TextAlign getAlign();
+
+
+ // The following three options have ascending overriding priority --
+
+ /**
+ Sets the shadowed text flag. If enabled, the text will be shadowed
+ with the "bgcolor" value.
+
+ @see getTextShadowed()
+ @param settextshadowed !0, Shadow the text; 0, Do not shadow the text;
+ */
+ void setTextShadowed(int settextshadowed) {
+ textshadowed = !!settextshadowed;
+ }
+
+ /**
+ Get the shadowed text flag. If enabled, the text will be shadowed
+ with the "bgcolor" value.
+
+ @see setTextShadowed()
+ @ret !0, Shadow the text; 0, Do not shadow the text;
+ */
+ int getTextShadowed() {
+ return textshadowed;
+ }
+
+ /**
+ Sets the outline text flag. If enabled, the text will be
+ outlined with the "bgcolor" value.
+
+ @param settextoutlined !0, Outline the text; 0, Do not outline the text;
+ */
+ void setTextOutlined(int settextoutlined) {
+ textoutlined = !!settextoutlined;
+ }
+
+ /**
+ Get the outline text flag. If enabled, the text will be
+ outlined with the "bgcolor" value.
+
+ @ret !0, Outline the text; 0, Do not outline the text;
+ */
+ int getTextOutlined() {
+ return textoutlined;
+ }
+
+ /**
+ Set the drawbox flag. If true, the drawbox flag will cause
+ a box to be drawn around the text in the textbar.
+
+ @param setdrawbox !0, Drawbox around the text; 0, No drawbox;
+ */
+ void setDrawBox(int setdrawbox) {
+ drawbox = !!setdrawbox;
+ }
+
+ /**
+ Get the drawbox flag. If true, the drawbox flag will cause
+ a box to be drawn around the text in the textbar.
+
+ @ret !0, Drawbox around the text; 0, No drawbox;
+ */
+ int getDrawBox() {
+ return drawbox;
+ }
+
+ /**
+ Associate a checkbox with the textbar. When a textbar is linked
+ to a checkbox, it will toggle the checkbox when it receives
+ left clicks.
+
+ @param target A pointer to the CheckWnd to link.
+ */
+ void setAutoToggleCheckWnd(CheckWnd *target) {
+ checkwndtarget = target;
+ }
+
+
+private:
+ int size;
+ int usebt;
+ TextAlign alignment; //i changed this from centered, to a set text alignment thingie
+
+
+ int textshadowed; // display a shadow of the text in bgcolor. default: on
+ int textoutlined; // draw an outline of the text in bgcolor. default: off
+ int drawbox; // draw a box of bgcolor the size of the boundsrect. default: off
+
+ AutoSkinBitmap bgbitmap;
+ CheckWnd *checkwndtarget;
+};
+
+const int TEXTBAR_LEFTMARGIN = 2;
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/tooltip.cpp b/Src/Wasabi/api/wnd/wndclass/tooltip.cpp
new file mode 100644
index 00000000..a619ab45
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/tooltip.cpp
@@ -0,0 +1,47 @@
+//#include <precomp.h>
+#include "./api.h"
+#include <api/wnd/api_wnd.h>
+#include "tooltip.h"
+
+#ifdef WASABI_COMPILE_CONFIG
+#include <api/config/items/attrint.h>
+#include <api/config/items/cfgitem.h>
+#endif
+#include <api/service/svc_enum.h>
+
+Tooltip::Tooltip(const wchar_t *txt)
+{
+ WASABI_API_WND->appdeactivation_push_disallow(NULL);
+ svc = NULL;
+
+ if (!txt || !*txt) return ;
+
+#ifdef WASABI_COMPILE_CONFIG
+ // {9149C445-3C30-4e04-8433-5A518ED0FDDE}
+ const GUID uioptions_guid =
+ { 0x9149c445, 0x3c30, 0x4e04, { 0x84, 0x33, 0x5a, 0x51, 0x8e, 0xd0, 0xfd, 0xde } };
+ if (!_intVal(WASABI_API_CONFIG->config_getCfgItemByGuid(uioptions_guid), L"Enable tooltips"))
+ {
+ // tooltips disabled
+ return ;
+ }
+#endif
+
+ waServiceFactory *svf = WASABI_API_SVC->service_enumService(WaSvc::TOOLTIPSRENDERER, 0);
+ svc = castService<svc_toolTipsRenderer>(svf);
+
+ if (!svc)
+ {
+ // no tooltips available!
+ return ;
+ }
+
+ svc->spawnTooltip(txt);
+}
+
+Tooltip::~Tooltip()
+{
+ if (svc != NULL)
+ WASABI_API_SVC->service_release(svc);
+ WASABI_API_WND->appdeactivation_pop_disallow(NULL);
+} \ No newline at end of file
diff --git a/Src/Wasabi/api/wnd/wndclass/tooltip.h b/Src/Wasabi/api/wnd/wndclass/tooltip.h
new file mode 100644
index 00000000..18122a40
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/tooltip.h
@@ -0,0 +1,18 @@
+#ifndef __TOOLTIP_H
+#define __TOOLTIP_H
+
+#include <api/service/svcs/svc_tooltips.h>
+
+class Tooltip {
+
+ public:
+
+ Tooltip(const wchar_t *txt);
+ virtual ~Tooltip();
+
+ private:
+
+ svc_toolTipsRenderer *svc;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/treewnd.cpp b/Src/Wasabi/api/wnd/wndclass/treewnd.cpp
new file mode 100644
index 00000000..99b03c85
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/treewnd.cpp
@@ -0,0 +1,1645 @@
+#include "precomp.h"
+
+#include "treewnd.h"
+
+#include <tataki/canvas/ifc_canvas.h>
+#include <bfc/stack.h>
+#include <api/wnd/wndclass/scrollbar.h>
+#include <tataki/color/skinclr.h>
+#include <api/wnd/notifmsg.h>
+#include <api/wnd/accessible.h>
+#include <api/wnd/PaintCanvas.h>
+
+#define DEF_TEXT_SIZE 14
+#define CHILD_INDENT itemHeight
+#define X_SHIFT 2
+#define Y_SHIFT 2
+#define DRAG_THRESHOLD 4
+
+#define TIMER_EDIT_DELAY 1000
+#define TIMER_EDIT_ID 1249
+
+///////////////////////////////////////////////////////////////////////////////
+// TreeWnd
+///////////////////////////////////////////////////////////////////////////////
+
+static SkinColor textcolor(L"wasabi.tree.text");
+static SkinColor drophilitecolor(L"wasabi.tree.hiliteddrop");
+static SkinColor selectedcolor(L"wasabi.tree.selected");
+
+int CompareTreeItem::compareItem(TreeItem *p1, TreeItem *p2) {
+ return p1->getTree()->compareItem(p1, p2);
+}
+
+TreeWnd::TreeWnd() {
+ tabClosed = NULL;
+ tabOpen = NULL;
+ linkTopBottom = NULL;
+ linkTopRight = NULL;
+ linkTopRightBottom = NULL;
+ linkTabTopBottom = NULL;
+ linkTabTopRight = NULL;
+ linkTabTopRightBottom = NULL;
+ curSelected = NULL;
+ mousedown_item = NULL;
+ hitItem = NULL;
+ draggedItem = NULL;
+ tipitem = NULL;
+ edited = NULL;
+ editwnd = NULL;
+ metrics_ok = FALSE;
+ setSorted(TRUE);
+ setFontSize(DEF_TEXT_SIZE);
+ redraw = TRUE;
+ prevbdownitem = NULL;
+ autoedit=0;
+ autocollapse=1;
+
+ tabClosed = L"wasabi.tree.tab.closed";
+ tabOpen = L"wasabi.tree.tab.open";
+ linkTopBottom = L"wasabi.tree.link.top.bottom";
+ linkTopRight = L"wasabi.tree.link.top.right";
+ linkTopRightBottom = L"wasabi.tree.link.top.rightBottom";
+ linkTabTopBottom = L"wasabi.tree.link.tab.top.bottom";
+ linkTabTopRight = L"wasabi.tree.link.tab.top.right";
+ linkTabTopRightBottom = L"wasabi.tree.link.tab.top.rightBottom";
+}
+
+TreeWnd::~TreeWnd() {
+ // delete all root items
+ deleteAllItems();
+ drawList.removeAll();
+}
+
+int TreeWnd::onInit() {
+ TREEWND_PARENT::onInit();
+
+ setBgBitmap(L"wasabi.tree.background");
+ setLineHeight(itemHeight);
+
+ return 1;
+}
+
+void TreeWnd::setRedraw(bool r) {
+ int old = redraw;
+ redraw = r;
+ if (!old && redraw)
+ invalidate();
+}
+
+int TreeWnd::onPaint(Canvas *canvas) {
+
+ PaintCanvas paintcanvas;
+ PaintBltCanvas paintbcanvas;
+
+ if (canvas == NULL) {
+ if (needDoubleBuffer()) {
+ if (!paintbcanvas.beginPaintNC(this)) return 0;
+ canvas = &paintbcanvas;
+ } else {
+ if (!paintcanvas.beginPaint(this)) return 0;
+ canvas = &paintcanvas;
+ }
+ }
+ TREEWND_PARENT::onPaint(canvas);
+
+/* uncomment if you add columns or anything that should be not be drawn over by onPaint in which case you'll have to clip->subtract(your_region)
+ api_region *clip = new RegionI();
+ canvas->getClipRgn(clip); */
+
+ /*RECT r;
+ getNonClientRect(&r);
+
+ int y = -getScrollY()+Y_SHIFT+r.top;
+ int x = -getScrollX()+X_SHIFT;*/
+
+ Wasabi::FontInfo fontInfo;
+ fontInfo.color = textcolor;
+ fontInfo.opaque=false;
+ fontInfo.pointSize = getFontSize();
+
+ firstItemVisible = NULL;
+ lastItemVisible = NULL;
+
+ ensureMetricsValid();
+
+ //drawSubItems(canvas, x, &y, items, r.top, r.bottom, 0);
+ drawItems(canvas, &fontInfo);
+
+ canvas->selectClipRgn(NULL); // reset cliping region - NEEDED;
+
+// delete clip; uncomment if necessary
+
+ return 1;
+}
+
+void TreeWnd::drawItems(Canvas *canvas, const Wasabi::FontInfo *fontInfo)
+{
+ RECT r, c, ir;
+ RegionI *orig=NULL;
+ getClientRect(&r);
+ if (!canvas->getClipBox(&c)) {
+ getClientRect(&c);
+ orig = new RegionI(&c);
+ } else
+ orig = new RegionI(canvas);
+
+ int first = ((c.top-r.top) + getScrollY() - Y_SHIFT) / itemHeight;
+ int last = ((c.bottom-r.top) + getScrollY() - Y_SHIFT) / itemHeight + 1;
+ POINT pt;
+ TreeItem *item;
+ bool hastab;
+
+ for (int i=first;i<=last;i++)
+ {
+
+ if (i >= drawList.getNumItems()) break;
+
+ item = drawList[i];
+ if (!item) continue;
+ item->getCurRect(&ir);
+ pt.x = r.left + X_SHIFT+item->getIndent()*itemHeight - getScrollX();//ir.left;
+ pt.y = ir.top;
+
+ // if we need the +/- icon and any of the link lines, draw them
+ if (item->needTab()) {
+// pt.x += itemHeight;
+ RECT _r={pt.x-itemHeight, pt.y, pt.x, pt.y+itemHeight};
+ (item->isCollapsed() ? tabClosed : tabOpen).stretchToRectAlpha(canvas, &_r);
+ hastab=TRUE;
+ } else hastab = FALSE;
+
+ int indent = item->getIndent();
+
+ for (int j=0;j<indent;j++)
+ {
+ RECT _r={pt.x-itemHeight*(j+1), pt.y, pt.x-itemHeight*j, pt.y+itemHeight};
+ int l = getLinkLine(item, j);
+ if (l == (LINK_RIGHT | LINK_TOP)) {
+ ((hastab && j == 0) ? linkTabTopRight : linkTopRight).stretchToRectAlpha(canvas, &_r);
+ }
+ if (l == (LINK_RIGHT | LINK_TOP | LINK_BOTTOM)) {
+ ((hastab && j == 0) ? linkTabTopRightBottom : linkTopRightBottom).stretchToRectAlpha(canvas, &_r);
+ }
+ if (l == (LINK_BOTTOM | LINK_TOP)) {
+ ((hastab && j == 0) ? linkTabTopBottom : linkTopBottom).stretchToRectAlpha(canvas, &_r);
+ }
+ }
+
+ item->customDraw(canvas, pt, itemHeight, (pt.x+getScrollX())-r.left-X_SHIFT, r, fontInfo);
+ }
+
+ delete orig;
+}
+
+TreeItem *TreeWnd::hitTest(int x, int y) {
+ POINT pt={x,y};
+ return hitTest(pt);
+}
+
+TreeItem *TreeWnd::hitTest(POINT pt) {
+ RECT r, ir;
+ getClientRect(&r);
+
+ int first = (getScrollY() - Y_SHIFT) / itemHeight;
+ int last = ((r.bottom-r.top) + getScrollY() - Y_SHIFT) / itemHeight + 1;
+
+ for (int i=first;i<=last;i++) {
+
+ if (i >= drawList.getNumItems()) break;
+
+ TreeItem *item = drawList.enumItem(i);
+
+ if (item) {
+ item->getCurRect(&ir);
+ if (Wasabi::Std::pointInRect(ir, pt) && item->isHitTestable())
+ return item;
+ }
+ }
+
+ return NULL;
+}
+
+void TreeWnd::getMetrics(int *numItemsShown, int *mWidth) {
+ *mWidth=0;
+ *numItemsShown=0;
+ drawList.removeAll();
+ countSubItems(drawList, &items, X_SHIFT, numItemsShown, mWidth, 0);
+}
+
+void TreeWnd::countSubItems(PtrList<TreeItem> &drawlist, TreeItemList *_list, int indent, int *count, int *maxwidth, int z) {
+
+ TreeItemList &list = *_list;
+
+ for (int i=0;i<list.getNumItems();i++) {
+
+ TreeItem *nextitem = list[i];
+
+ int w = nextitem->getItemWidth(itemHeight, indent-X_SHIFT);
+ if (indent+w > *maxwidth) *maxwidth = w+indent;
+
+ int j = indent-(nextitem->needTab() ? itemHeight : 0);
+ int k;
+ k = indent + w;
+
+ nextitem->setCurRect(j, Y_SHIFT+(*count * itemHeight), k, Y_SHIFT+((*count+1) * itemHeight), z);
+ (*count)++;
+
+ drawlist.addItem(nextitem);
+
+ if (nextitem->isExpanded())
+ countSubItems(drawlist, &nextitem->subitems, indent+CHILD_INDENT, count, maxwidth, z+1);
+ }
+}
+
+void TreeWnd::timerCallback(int c) {
+ switch (c) {
+ case TIMER_EDIT_ID:
+ prevbdownitem = NULL;
+ killTimer(TIMER_EDIT_ID);
+ break;
+ default:
+ TREEWND_PARENT::timerCallback(c);
+ }
+}
+
+int TreeWnd::onLeftButtonDown(int x, int y) {
+
+ if (edited)
+ {
+ delete editwnd; editwnd = NULL;
+ endEditLabel(editbuffer);
+ }
+
+ POINT pt={x,y};
+ TreeItem *item = hitTest(pt);
+
+ if (item) {
+ mousedown_item = item;
+ mousedown_anchor.x = pt.x;
+ mousedown_anchor.y = pt.y;
+ mousedown_dragdone = FALSE;
+ // only do expand/collapse if was already selected
+ setCurItem(item, autocollapse?(curSelected == item):0, FALSE);
+ beginCapture();
+ }
+
+ return 1;
+}
+
+int TreeWnd::onLeftButtonUp(int x, int y) {
+ if (getCapture())
+ endCapture();
+ TREEWND_PARENT::onLeftButtonUp(x, y);
+ POINT pt={x,y};
+ TreeItem *item = hitTest(pt);
+ if (autoedit && item == mousedown_item && item == prevbdownitem)
+ setCurItem(item, FALSE, TRUE);
+ else
+ if (autoedit) {
+ prevbdownitem = getCurItem();
+ setTimer(TIMER_EDIT_ID, TIMER_EDIT_DELAY);
+ }
+
+ mousedown_item = NULL;
+ return 1;
+}
+
+int TreeWnd::onRightButtonUp(int x, int y){
+ TREEWND_PARENT::onRightButtonUp(x, y);
+ POINT pos={x,y};
+
+ TreeItem *ti = hitTest(pos);
+ if (ti != NULL) {
+ selectItem(ti);
+ if (onPreItemContextMenu(ti, x, y) == 0) {
+ int ret = ti->onContextMenu(x, y);
+ onPostItemContextMenu(ti, x, y, ret);
+ return ret;
+ }
+ return 1;
+ } else {
+ return onContextMenu(x, y);
+ }
+}
+
+int TreeWnd::onMouseMove(int x, int y) {
+
+ TREEWND_PARENT::onMouseMove(x, y);
+
+ POINT pt={x,y};
+
+ if (mousedown_item) {
+ if (!mousedown_dragdone && (ABS(pt.x - mousedown_anchor.x) > DRAG_THRESHOLD || ABS(pt.y - mousedown_anchor.y) > DRAG_THRESHOLD)) {
+ mousedown_dragdone = TRUE;
+ if (getCapture())
+ endCapture();
+ onBeginDrag(mousedown_item);
+ }
+ }
+ else
+ {
+ TreeItem *item = hitTest(pt);
+ if (item) {
+ if (tipitem != item) {
+ tipitem = item;
+ RECT r;
+ RECT c;
+ getClientRect(&c);
+ item->getCurRect(&r);
+ const wchar_t *tt = item->getTip();
+ if (tt != NULL && *tt != '\0')
+ setLiveTip(tt);
+ else if (r.right > c.right || r.bottom > c.bottom || r.top < c.top || r.left < c.left)
+ setLiveTip(item->getLabel());
+ else
+ setLiveTip(NULL);
+ }
+ } else {
+ setLiveTip(NULL);
+ }
+ }
+
+ return 1;
+}
+
+int TreeWnd::onLeftButtonDblClk(int x, int y) {
+ TreeItem *item = hitTest(x, y);
+ if (item == NULL) return 0;
+ return item->onLeftDoubleClick();
+}
+
+int TreeWnd::onRightButtonDblClk(int x, int y) {
+ TreeItem *item = hitTest(x, y);
+ if (item == NULL) return 0;
+ return item->onRightDoubleClick();
+}
+
+void TreeWnd::setLiveTip(const wchar_t *tip)
+{
+ if (!tip)
+ {
+ setTip(oldtip);
+ oldtip = L"";
+ return;
+ }
+ oldtip = TREEWND_PARENT::getTip();
+ setTip(tip);
+}
+
+int TreeWnd::onBeginDrag(TreeItem *treeitem)
+{
+ wchar_t title[WA_MAX_PATH]=L"";
+ // item calls addDragItem()
+ if (!treeitem->onBeginDrag(title)) return 0;
+ ASSERT(draggedItem == NULL);
+ draggedItem = treeitem;
+ if (*title != 0) setSuggestedDropTitle(title);
+ handleDrag();
+ return 1;
+}
+
+int TreeWnd::dragEnter(ifc_window *sourceWnd) {
+ // uh... we don't know yet, but we can accept drops in general
+ hitItem = NULL;
+ return 1;
+}
+
+int TreeWnd::dragOver(int x, int y, ifc_window *sourceWnd) {
+ POINT pos={x,y};
+ screenToClient(&pos);
+ TreeItem *prevItem;
+
+ prevItem = hitItem;
+ hitItem = hitTest(pos);
+
+ // no dropping on yourself! :)
+ if (hitItem == draggedItem) hitItem = NULL;
+
+ // unselect previous item
+ if (prevItem != hitItem && prevItem != NULL) {
+ unhiliteDropItem(prevItem);
+ repaint(); // commit invalidation of unhilited item so no trouble with scrolling
+ prevItem->dragLeave(sourceWnd);
+ }
+
+
+ RECT r;
+ getClientRect(&r);
+ if (pos.y < r.top + 16) {
+ if (getScrollY() >= 0) {
+ scrollToY(MAX(0, getScrollY()-itemHeight));
+ }
+ } else if (pos.y > r.bottom - 16) {
+ if (getScrollY() < getMaxScrollY()) {
+ scrollToY(MIN(getMaxScrollY(), getScrollY()+itemHeight));
+ }
+ }
+
+ if (hitItem != NULL) {
+ // hilight it
+ if (prevItem != hitItem) {
+ hiliteDropItem(hitItem);
+ repaint(); // commit invalidation of hilited so no trouble with scrolling
+ }
+ }
+
+ if (hitItem == NULL) return defaultDragOver(x, y, sourceWnd);
+
+ // ask the item if it can really accept such a drop
+ return hitItem->dragOver(sourceWnd);
+}
+
+int TreeWnd::dragLeave(ifc_window *sourceWnd) {
+ if (hitItem != NULL) {
+ unhiliteDropItem(hitItem);
+ hitItem->dragLeave(sourceWnd);
+ }
+ hitItem = NULL;
+ return 1;
+}
+
+int TreeWnd::dragDrop(ifc_window *sourceWnd, int x, int y) {
+ int res;
+ if (hitItem == NULL) return defaultDragDrop(sourceWnd, x, y);
+ // unhilite the dest
+ unhiliteDropItem(hitItem);
+ // the actual drop
+ res = hitItem->dragDrop(sourceWnd);
+ if (res) {
+ onItemRecvDrop(hitItem);
+ }
+ hitItem = NULL;
+ return res;
+}
+
+int TreeWnd::dragComplete(int success) {
+ int ret;
+ ASSERT(draggedItem != NULL);
+ ret = draggedItem->dragComplete(success);
+ draggedItem = NULL;
+ return ret;
+}
+
+void TreeItem::setTip(const wchar_t *tip)
+{
+ tooltip = tip;
+}
+
+const wchar_t *TreeItem::getTip()
+{
+ return tooltip;
+}
+
+void TreeWnd::hiliteDropItem(TreeItem *item) {
+ if (item)
+ item->setHilitedDrop(TRUE);
+}
+
+void TreeWnd::hiliteItem(TreeItem *item) {
+ if (item)
+ item->setHilited(TRUE);
+}
+
+void TreeWnd::selectItem(TreeItem *item) {
+ setCurItem(item, FALSE);
+}
+
+void TreeWnd::selectItemDeferred(TreeItem *item) {
+ postDeferredCallback(DC_SETITEM, (intptr_t)item);
+}
+
+void TreeWnd::delItemDeferred(TreeItem *item) {
+ postDeferredCallback(DC_DELITEM, (intptr_t)item);
+}
+
+void TreeWnd::unhiliteItem(TreeItem *item) {
+ if (item)
+ item->setHilited(FALSE);
+}
+
+void TreeWnd::unhiliteDropItem(TreeItem *item) {
+ if (item)
+ item->setHilitedDrop(FALSE);
+}
+
+void TreeWnd::setCurItem(TreeItem *item, bool expandCollapse, bool editifselected) {
+ if (curSelected && curSelected != item) {
+ onDeselectItem(curSelected);
+ curSelected->setSelected(FALSE);
+ }
+ if (item) {
+ curSelected = item;
+ onSelectItem(curSelected);
+ item->setSelected(TRUE, expandCollapse, editifselected);
+ setSlidersPosition();
+ }
+}
+
+// Returns the current tree width in pixels
+int TreeWnd::getContentsWidth() {
+ ensureMetricsValid();
+ return maxWidth;
+}
+
+// Returns the current tree height in pixels
+int TreeWnd::getContentsHeight() {
+ ensureMetricsValid();
+ return maxHeight;
+}
+
+void TreeWnd::ensureMetricsValid() {
+ if (metrics_ok) return;
+ int n;
+ getMetrics(&n, &maxWidth);
+ maxWidth += X_SHIFT*2;
+ maxHeight = n*itemHeight+Y_SHIFT*2;
+ metrics_ok = TRUE;
+ setSlidersPosition();
+}
+
+// Gets notification from sliders
+int TreeWnd::childNotify(ifc_window *child, int msg, intptr_t param1, intptr_t param2) {
+ switch (msg) {
+ case ChildNotify::EDITWND_ENTER_PRESSED:
+ if (child == editwnd && editwnd != NULL) {
+ endEditLabel(editbuffer);
+ return 1;
+ }
+ break;
+ case ChildNotify::EDITWND_CANCEL_PRESSED:
+ if (child == editwnd && editwnd != NULL) {
+ cancelEditLabel();
+ return 1;
+ }
+ break;
+ case ChildNotify::EDITWND_DATA_MODIFIED:
+ if (child == editwnd && editwnd != NULL) {
+ editUpdate();
+ return 1;
+ }
+ break;
+ }
+
+ return TREEWND_PARENT::childNotify(child, msg, param1, param2);
+}
+
+void TreeWnd::editUpdate() {
+ ASSERT(edited != NULL && editwnd != NULL);
+ if (!edited || !editwnd) return;
+ int w = editwnd->getTextLength()+16;
+ RECT i, r, e;
+ edited->getCurRect(&i);
+ getClientRect(&r);
+ editwnd->getClientRect(&e);
+ e.left += i.left;
+ e.right += i.left;
+ e.top += i.top;
+ e.bottom += i.top;
+ e.right = i.left+w;
+ e.right = MIN<int>(r.right - X_SHIFT, e.right);
+ editwnd->resize(&e);
+ editwnd->invalidate();
+}
+
+TreeItem *TreeWnd::addTreeItem(TreeItem *item, TreeItem *par, int _sorted, int haschildtab) {
+
+ ASSERT(item != NULL);
+ ASSERTPR(item->getTree() == NULL, "can't transplant TreeItems");
+ ASSERTPR(item->getLabel() != NULL, "tree items must have a label to be inserted");
+
+ item->setSorted(_sorted);
+ item->setChildTab(haschildtab ? TAB_AUTO : TAB_NO/*&& par != NULL*/);
+ item->setTree(this);
+ item->linkTo(par);
+
+ if (par == NULL)
+ items.addItem(item);
+
+ all_items.addItem(item);
+
+ metrics_ok = FALSE;
+
+ if (redraw)
+ invalidate();
+
+ item->onTreeAdd();
+
+ return item;
+}
+
+int TreeWnd::removeTreeItem(TreeItem *item) {
+ ASSERT(item != NULL);
+ ASSERT(item->getTree() == this);
+ if (item->isSelected()) item->setSelected(FALSE);
+ if (curSelected == item) curSelected = NULL;
+//CUT item->deleteSubitems();
+ TreeItem *par = item->getParent();
+ if (!par) { // is root item ?
+ ASSERT(items.haveItem(item));
+ items.removeItem(item);
+ } else {
+ if (!par->removeSubitem(item))
+ return 0;
+ }
+ all_items.removeItem(item);
+ metrics_ok = FALSE;
+ drawList.removeItem(item);
+ if (redraw)
+ invalidate();
+
+ item->setTree(NULL);
+ item->onTreeRemove();
+
+ if (par != NULL) par->onChildItemRemove(item);
+
+ return 1;
+}
+
+void TreeWnd::moveTreeItem(TreeItem *item, TreeItem *newparent) {
+ ASSERT(item != NULL);
+ ASSERTPR(item->getTree() == this, "can't move between trees (fucks up Freelist)");
+ removeTreeItem(item);
+ addTreeItem(item, newparent, item->subitems.getAutoSort(), item->childTab);
+}
+
+void TreeWnd::deleteAllItems() {
+ bool save_redraw = redraw;
+ setRedraw(FALSE);
+
+ TreeItem *item;
+ while ((item = enumRootItem(0)) != NULL)
+ delete item;
+
+ setRedraw(save_redraw);
+}
+
+void TreeWnd::setSorted(bool dosort) {
+ items.setAutoSort(dosort);
+}
+
+bool TreeWnd::getSorted() {
+ return items.getAutoSort();
+}
+
+void TreeWnd::sortTreeItems() {
+ items.sort(TRUE);
+ metrics_ok = FALSE;
+ if (redraw)
+ invalidate();
+}
+
+TreeItem *TreeWnd::getSibling(TreeItem *item) {
+ for (int i=0;i<items.getNumItems();i++) {
+ if (items[i] == item) {
+ if (i == items.getNumItems()-1) return NULL;
+ return items[i+1];
+ }
+ }
+ return NULL;
+}
+
+void TreeWnd::setAutoCollapse(bool doautocollase) {
+ autocollapse=doautocollase;
+}
+
+int TreeWnd::onContextMenu(int x, int y) {
+ POINT pos={x,y};
+ screenToClient(&pos);
+ TreeItem *ti = hitTest(pos);
+ if (ti != NULL) {
+ selectItem(ti);
+ return ti->onContextMenu(x, y);
+ }
+ return 0;
+}
+
+int TreeWnd::onDeferredCallback(intptr_t param1, intptr_t param2) {
+ switch (param1) {
+ case DC_SETITEM:
+ setCurItem((TreeItem *)param2, FALSE);
+ return 1;
+ case DC_DELITEM:
+ delete (TreeItem *)param2;
+ return 1;
+ case DC_EXPAND:
+ expandItem((TreeItem *)param2);
+ return 1;
+ case DC_COLLAPSE:
+ collapseItem((TreeItem *)param2);
+ return 1;
+ }
+ return 0;
+}
+
+int TreeWnd::getNumRootItems() {
+ return items.getNumItems();
+}
+
+TreeItem *TreeWnd::enumRootItem(int which) {
+ return items[which];
+}
+
+void TreeWnd::invalidateMetrics() {
+ metrics_ok = FALSE;
+}
+
+int TreeWnd::getLinkLine(TreeItem *item, int level) {
+
+ ASSERT(item != NULL);
+
+ int l = 0;
+ int r = 0;
+
+ if (item->parent == NULL)
+ return 0;
+
+ TreeItem *cur=item;
+
+ while (cur->getParent() && l < level) {
+ cur = cur->getParent();
+ l++;
+ }
+
+ if (cur->getSibling()) r |= LINK_BOTTOM | LINK_TOP;
+ if (level == 0) r |= LINK_RIGHT;
+ if (level == 0 && cur->getParent()) r |= LINK_TOP;
+
+ return r;
+
+}
+
+int TreeWnd::onMouseWheelDown(int clicked, int lines) {
+ if (!clicked)
+ scrollToY(MIN(getMaxScrollY(), getScrollY()+itemHeight));
+ else
+ scrollToX(MIN(getMaxScrollX(), getScrollX()+itemHeight));
+ return 1;
+}
+
+int TreeWnd::onMouseWheelUp(int clicked, int lines) {
+ if (!clicked)
+ scrollToY(MAX(0, getScrollY()-itemHeight));
+ else
+ scrollToX(MAX(0, getScrollX()-itemHeight));
+ return 1;
+}
+
+int TreeWnd::expandItem(TreeItem *item) {
+ ASSERT(item != NULL);
+
+ return item->expand();
+}
+
+void TreeWnd::expandItemDeferred(TreeItem *item) {
+ postDeferredCallback(DC_EXPAND, (intptr_t)item);
+}
+
+int TreeWnd::collapseItem(TreeItem *item) {
+ ASSERT(item != NULL);
+
+ return item->collapse();
+}
+
+void TreeWnd::collapseItemDeferred(TreeItem *item) {
+ postDeferredCallback(DC_COLLAPSE, (intptr_t)item);
+}
+
+TreeItem *TreeWnd::getCurItem() {
+ return curSelected;
+}
+
+int TreeWnd::getItemRect(TreeItem *item, RECT *r) {
+ ASSERT(item != NULL);
+
+ return item->getCurRect(r);
+}
+
+void TreeWnd::editItemLabel(TreeItem *item) {
+
+ if (edited) {
+ edited->setEdition(FALSE);
+ edited->invalidate();
+ }
+
+
+ ASSERT(item != NULL);
+ if (item == NULL) return;
+
+ if (item->onBeginLabelEdit()) return;
+ item->setEdition(TRUE);
+ edited = item;
+
+ editwnd = new EditWnd();
+ editwnd->setModal(TRUE);
+ editwnd->setAutoSelect(TRUE);
+ editwnd->setStartHidden(TRUE);
+ editwnd->init(getOsModuleHandle(), getOsWindowHandle());
+ editwnd->setParent(this);
+ RECT r;
+ edited->getCurRect(&r);
+ RECT cr;
+ getClientRect(&cr);
+ r.right = cr.right;
+ if (r.bottom - r.top < 24) r.bottom = r.top + 24;
+ editwnd->resize(&r);
+ wcsncpy(editbuffer, edited->getLabel(), 256);
+ editwnd->setBuffer(editbuffer, 255);
+ editUpdate();
+ editwnd->setVisible(TRUE);
+}
+
+void TreeWnd::endEditLabel(const wchar_t *newlabel)
+{
+ editwnd = NULL; // editwnd self destructs
+ if (edited->onEndLabelEdit(newlabel))
+ edited->setLabel(newlabel);
+ edited->setEdition(FALSE);
+ edited->invalidate();
+ onLabelChange(edited);
+ edited = NULL;
+ invalidateMetrics();
+ setSlidersPosition();
+}
+
+void TreeWnd::cancelEditLabel(int destroyit) {
+ ASSERT(edited != NULL);
+ if (!edited) return;
+
+ if (destroyit)
+ delete editwnd;
+
+ editwnd = NULL; // editwnd self destructs (update> except if destroyit for cancelling from treewnd)
+ edited->setEdition(FALSE);
+ edited->invalidate();
+ edited = NULL;
+}
+
+void TreeWnd::setAutoEdit(int ae) {
+ autoedit = ae;
+}
+
+int TreeWnd::getAutoEdit() {
+ return autoedit;
+}
+
+TreeItem *TreeWnd::getByLabel(TreeItem *item, const wchar_t *name)
+{
+ TreeItem *ti;
+ // handle root-level searching
+ if (item == NULL) {
+ int n = getNumRootItems();
+ for (int i = 0; i < n; i++) {
+ ti = enumRootItem(i);
+ if (!wcscmp(name, ti->getLabel())) return ti;
+ ti = getByLabel(ti, name);
+ if (ti) return ti;
+ }
+ return NULL;
+ }
+
+ // check the given item
+ if (!wcscmp(name, item->getLabel())) return item;
+
+ // depth first search
+ ti = item->getChild();
+ if (ti != NULL) {
+ ti = getByLabel(ti, name);
+ if (ti != NULL) return ti;
+ }
+
+ // recursively check siblings
+ ti = item->getSibling();
+ if (ti != NULL) ti = getByLabel(ti, name);
+
+ return ti;
+}
+
+int TreeWnd::onGetFocus() {
+ int r = TREEWND_PARENT::onGetFocus();
+
+#if 0
+DebugString("yay got focus");
+ TreeItem *ti = getCurItem();
+ if (ti != NULL) {
+ ti->setSelected(FALSE);
+ selectItemDeferred(ti);
+ }
+#endif
+
+ return r;
+}
+
+int TreeWnd::onKillFocus() {
+
+ TREEWND_PARENT::onKillFocus();
+ mousedown_item=NULL;
+/* if (edited)
+ cancelEditLabel();*/
+#if 0
+DebugString("no mo focus");
+#endif
+
+ return 1;
+}
+
+int TreeWnd::onChar(unsigned int c)
+{
+ int r = 0;
+
+ if (c == 27) {
+ if (edited)
+ cancelEditLabel(1);
+ }
+
+ if (curSelected != NULL && (r = curSelected->onChar(c)) != 0) return r;
+
+ wchar_t b = TOUPPERW(c);
+ if (b >= 'A' && b <= 'Z')
+ {
+ jumpToNext(b);
+ r = 1;
+ }
+
+ return r ? r : TREEWND_PARENT::onChar(c);
+}
+
+int TreeWnd::getNumVisibleChildItems(TreeItem *c) {
+ int nb=0;
+ for(int i=0;i<c->getNumChildren();i++) {
+ TreeItem *t=c->getNthChild(i);
+ if(t->hasSubItems() && t->isExpanded())
+ nb+=getNumVisibleChildItems(t);
+ nb++;
+ }
+ return nb;
+}
+
+int TreeWnd::getNumVisibleItems() {
+ int nb=0;
+ for(int i=0;i<items.getNumItems();i++) {
+ TreeItem *t=items.enumItem(i);
+ if(t->hasSubItems() && t->isExpanded())
+ nb+=getNumVisibleChildItems(t);
+ nb++;
+ }
+ return nb;
+}
+
+TreeItem *TreeWnd::enumVisibleChildItems(TreeItem *c, int n) {
+ int nb=0;
+ for(int i=0;i<c->getNumChildren();i++) {
+ TreeItem *t=c->getNthChild(i);
+ if(nb==n) return t;
+ if(t->hasSubItems() && t->isExpanded()) {
+ TreeItem *t2=enumVisibleChildItems(t, n-nb-1);
+ if(t2) return t2;
+ nb+=getNumVisibleChildItems(t);
+ }
+ nb++;
+ }
+ return NULL;
+}
+
+TreeItem *TreeWnd::enumVisibleItems(int n) {
+ int nb=0;
+ for(int i=0;i<items.getNumItems();i++) {
+ TreeItem *t=items.enumItem(i);
+ if(nb==n) return t;
+ if(t->hasSubItems() && t->isExpanded()) {
+ TreeItem *t2=enumVisibleChildItems(t, n-nb-1);
+ if(t2) return t2;
+ nb+=getNumVisibleChildItems(t);
+ }
+ nb++;
+ }
+ return NULL;
+}
+
+int TreeWnd::findChildItem(TreeItem *c, TreeItem *i, int *nb) {
+ for(int j=0;j<c->getNumChildren();j++) {
+ TreeItem *t=c->getNthChild(j); (*nb)++;
+ if (t == i) return *nb;
+ if(t->hasSubItems() && t->isExpanded()) {
+ int n = findChildItem(t, i, nb);
+ if (n != -1) return *nb;
+ }
+ }
+ return -1;
+}
+
+int TreeWnd::findItem(TreeItem *i) {
+ int nb=-1;
+ for(int j=0;j<items.getNumItems();j++) {
+ TreeItem *t=items.enumItem(j); nb++;
+ if (t == i) return nb;
+ if(t->hasSubItems() && t->isExpanded()) {
+ int n = findChildItem(t, i, &nb);
+ if (n != -1) return nb;
+ }
+ }
+ return -1;
+}
+
+
+TreeItem *TreeWnd::enumAllItems(int n) {
+ return all_items[n];
+}
+
+int TreeWnd::onKeyDown(int keycode)
+{
+ switch(keycode)
+ {
+ case 113: {
+ TreeItem *item = getCurItem();
+ if (item)
+ item->editLabel();
+ return 1;
+ }
+ case STDKEY_UP: {
+ TreeItem *t=getCurItem();
+ int l=getNumVisibleItems();
+ if (t == NULL) {
+ if (l > 0) setCurItem(enumVisibleItems(getNumVisibleItems()-1), FALSE, FALSE);
+ } else {
+ for(int i=0;i<l;i++)
+ if(enumVisibleItems(i)==t) {
+ if(i-1>=0) {
+ TreeItem *t2=enumVisibleItems(i-1);
+ if(t2) setCurItem(t2,FALSE,FALSE);
+ }
+ }
+ }
+ return 1;
+ }
+ case STDKEY_DOWN: {
+ TreeItem *t=getCurItem();
+ int l=getNumVisibleItems();
+ if (t == NULL) {
+ if (l > 0) setCurItem(enumVisibleItems(0), FALSE, FALSE);
+ } else {
+ for(int i=0;i<l;i++)
+ if(enumVisibleItems(i)==t) {
+ TreeItem *t2=enumVisibleItems(i+1);
+ if(t2) setCurItem(t2,FALSE,FALSE);
+ }
+ }
+ return 1;
+ }
+ case VK_PRIOR: {
+ TreeItem *t=getCurItem();
+ int l=getNumVisibleItems();
+ for(int i=0;i<l;i++)
+ if(enumVisibleItems(i)==t) {
+ int a=MAX(i-5,0);
+ TreeItem *t2=enumVisibleItems(a);
+ if(t2) setCurItem(t2,FALSE,FALSE);
+ }
+ return 1;
+ }
+ case VK_NEXT: {
+ TreeItem *t=getCurItem();
+ int l=getNumVisibleItems();
+ for(int i=0;i<l;i++)
+ if(enumVisibleItems(i)==t) {
+ int a=MIN(i+5,l-1);
+ TreeItem *t2=enumVisibleItems(a);
+ if(t2) setCurItem(t2,FALSE,FALSE);
+ }
+ return 1;
+ }
+ case STDKEY_HOME: {
+ TreeItem *t=enumVisibleItems(0);
+ if(t) setCurItem(t,FALSE,FALSE);
+ return 1;
+ }
+ case STDKEY_END: {
+ TreeItem *t=enumVisibleItems(getNumVisibleItems()-1);
+ if(t) setCurItem(t,FALSE,FALSE);
+ return 1;
+ }
+ case STDKEY_LEFT: {
+ TreeItem *t=getCurItem();
+ if(t) t->collapse();
+ return 1;
+ }
+ case STDKEY_RIGHT: {
+ TreeItem *t=getCurItem();
+ if(t) t->expand();
+ return 1;
+ }
+ }
+
+ return TREEWND_PARENT::onKeyDown(keycode);
+}
+
+void TreeWnd::jumpToNext(wchar_t c) {
+ firstFound=FALSE;
+ if (jumpToNextSubItems(&items, c)) return;
+ firstFound=TRUE;
+ jumpToNextSubItems(&items, c);
+}
+
+int TreeWnd::jumpToNextSubItems(TreeItemList *list, wchar_t c) {
+
+ for (int i=0;i<list->getNumItems();i++) {
+
+ TreeItem *nextitem = list->enumItem(i);
+ const wchar_t *l = nextitem->getLabel();
+ wchar_t b = l ? TOUPPERW(*l) : 0;
+ if (b == c && firstFound)
+ {
+ selectItem(nextitem);
+ nextitem->ensureVisible();
+ return 1;
+ }
+
+ if (nextitem->isSelected()) firstFound = TRUE;
+
+ if (nextitem->isExpanded())
+ if (jumpToNextSubItems(&nextitem->subitems, c)) return 1;
+ }
+ return 0;
+}
+
+void TreeWnd::ensureItemVisible(TreeItem *item) {
+ ASSERT(item != NULL);
+
+ // walk the parent tree to make sure item is visible
+ for (TreeItem *cur = item->getParent(); cur; cur = cur->getParent()) {
+ if (cur->isCollapsed()) cur->expand();
+ }
+
+ RECT r;
+ RECT c;
+ item->getCurRect(&r);
+ getClientRect(&c);
+ if (r.top < c.top || r.bottom > c.bottom) {
+ if (r.top + (c.bottom - c.top) <= getContentsHeight())
+ scrollToY(r.top);
+ else {
+ scrollToY(getContentsHeight()-(c.bottom-c.top));
+ }
+ }
+}
+
+void TreeWnd::setHilitedColor(const wchar_t *colorname) {
+ // we have to store it in a String because SkinColor does not make a copy
+ hilitedColorName = colorname;
+ hilitedColor = hilitedColorName;
+}
+
+ARGB32 TreeWnd::getHilitedColor() {
+ return hilitedColor;
+}
+
+int TreeWnd::compareItem(TreeItem *p1, TreeItem *p2)
+{
+ int r = wcscmp(p1->getLabel(), p2->getLabel());
+ if (r == 0) return CMP3(p1, p2);
+ return r;
+}
+
+int TreeWnd::setFontSize(int newsize)
+{
+ TREEWND_PARENT::setFontSize(newsize);
+ if (newsize >= 0) textsize = newsize;
+ TextInfoCanvas c(this);
+ Wasabi::FontInfo fontInfo;
+ fontInfo.pointSize = getFontSize();
+ itemHeight = c.getTextHeight(&fontInfo);
+ redraw = 1;
+ metrics_ok = 0;
+ invalidate();
+ return 1;
+}
+
+int TreeWnd::getFontSize() {
+#ifndef WASABINOMAINAPI
+ return textsize + api->metrics_getDelta();
+#else
+ //MULTIAPI-FIXME: not handling delta
+ return textsize;
+#endif
+}
+
+
+void TreeWnd::onSelectItem(TreeItem *i) {
+ Accessible *a = getAccessibleObject();
+ if (a != NULL)
+ a->onGetFocus(findItem(i));
+}
+
+void TreeWnd::onDeselectItem(TreeItem *i) {
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////
+// TreeItem
+////////////////////////////////////////////////////////////////////////////////////
+
+TreeItem::TreeItem(const wchar_t *label) {
+ parent=NULL;
+ MEMZERO(&curRect, sizeof(RECT));
+ childTab = TAB_AUTO;
+ tree = NULL;
+ expandStatus = STATUS_COLLAPSED;
+ icon = NULL;
+ _z = 0;
+
+ if (label != NULL)
+ setLabel(label);
+
+ selected = FALSE;
+ hilitedDrop = FALSE;
+ hilited = FALSE;
+ being_edited = FALSE;
+
+ setSorted(TRUE);
+}
+
+TreeItem::~TreeItem() {
+ // the subitem will call parent tree which will remove item from our list
+ deleteSubitems();
+
+ // remove from parent tree
+ if (tree) tree->removeTreeItem(this);
+
+ delete icon;
+}
+
+void TreeItem::deleteSubitems() {
+ while (subitems.getNumItems() > 0) {
+ delete subitems.enumItem(0);
+ }
+}
+
+void TreeItem::setSorted(int issorted) {
+ subitems.setAutoSort(!!issorted);
+}
+
+void TreeItem::setChildTab(int haschildtab) {
+ childTab = haschildtab;
+}
+
+void TreeItem::linkTo(TreeItem *par) {
+ parent = par;
+
+ if (par == NULL) return;
+
+ par->addSubItem(this);
+}
+
+void TreeItem::addSubItem(TreeItem *item) {
+ subitems.addItem(item);
+}
+
+int TreeItem::removeSubitem(TreeItem *item) {
+ if (subitems.searchItem(item) == -1) return 0;
+ subitems.removeItem(item);
+ if (tree->redraw)
+ tree->invalidate();
+ return 1;
+}
+
+TreeItem *TreeItem::getChild() {
+ return subitems.getFirst();
+}
+
+TreeItem *TreeItem::getChildSibling(TreeItem *item) { // locate item in children and return its sibling
+ for (int i=0;i<subitems.getNumItems();i++) {
+ if (subitems.enumItem(i) == item) {
+ if (i == subitems.getNumItems()-1) return NULL;
+ return subitems.enumItem(i+1);
+ }
+ }
+return NULL;
+}
+
+TreeItem *TreeItem::getSibling() { // returns next item
+ if (!parent)
+ return tree->getSibling(this);
+ else
+ return parent->getChildSibling(this);
+}
+
+void TreeItem::setTree(TreeWnd *newtree) {
+ tree = newtree;
+ // recursively reset tree for children, if any
+ for (int i = 0; ; i++) {
+ TreeItem *item = getNthChild(i);
+ if (item == NULL) break;
+ item->setTree(tree);
+ }
+}
+
+void TreeItem::ensureVisible()
+{
+ if (tree) tree->ensureItemVisible(this);
+}
+
+const wchar_t *TreeItem::getLabel()
+{
+ return label;
+}
+
+void TreeItem::setLabel(const wchar_t *newlabel)
+{
+ label = newlabel;
+ if (newlabel) {
+ if (tree)
+ tree->invalidateMetrics();
+ invalidate();
+ }
+}
+
+int TreeItem::customDraw(Canvas *canvas, const POINT &pt, int txtHeight, int indentation, const RECT &clientRect, const Wasabi::FontInfo *fontInfo)
+{
+ if (being_edited) return 0;
+
+ SkinBitmap *icon = getIcon();
+
+ int cw = clientRect.right - clientRect.left;
+
+ int iconw = MIN(icon ? icon->getWidth() : 0, cw);
+
+ if (isSelected() || isHilitedDrop())
+ {
+ RECT r;
+ r.left = pt.x;
+ r.top = pt.y;
+ //r.right = r.left + canvas->getTextWidth(label)+2+(icon ? txtHeight : 0);
+ r.right = r.left + canvas->getTextWidth(label, fontInfo)+2+iconw;
+ r.bottom = r.top + txtHeight;
+ canvas->fillRect(&r, isHilitedDrop() ? drophilitecolor : selectedcolor);
+ }
+
+ if (isHilited())
+ {
+ RECT r;
+ r.left = pt.x;
+ r.top = pt.y;
+ //r.right = r.left + canvas->getTextWidth(label)+2+(icon ? txtHeight : 0);
+ r.right = r.left + canvas->getTextWidth(label, fontInfo)+2+iconw;
+ r.bottom = r.top + txtHeight;
+ canvas->drawRect(&r, 1, tree->getHilitedColor());
+ }
+
+ POINT d=pt;
+
+ if (icon) {
+ RECT i;
+ i.left = pt.x+1;
+ i.right = i.left + iconw;
+// i.top = pt.y+1;
+ int lh = MIN(icon->getHeight(), txtHeight);
+ i.top = pt.y + (txtHeight - lh) / 2;
+// i.bottom = i.top + txtHeight-2;
+ i.bottom = i.top + lh;
+ icon->stretchToRectAlpha(canvas, &i);
+ //d.x += txtHeight;
+ d.x += icon->getWidth();
+ }
+
+ canvas->textOut(d.x+1, d.y, label, fontInfo);
+
+ return canvas->getTextWidth(label, fontInfo)+2+iconw;
+}
+
+int TreeItem::getItemWidth(int txtHeight, int indentation) {
+ SkinBitmap *icon = getIcon();
+ if (!label) return (icon ? txtHeight : 0);
+ TextInfoCanvas c(tree);
+ Wasabi::FontInfo fontInfo;
+ fontInfo.pointSize = getTree()->getFontSize();
+ int width = c.getTextWidth(label, &fontInfo)+2;
+ width += (icon ? txtHeight : 0);
+ return width;
+}
+
+int TreeItem::getNumChildren() {
+ return subitems.getNumItems();
+}
+
+TreeItem *TreeItem::getNthChild(int nth) {
+ if (nth >= subitems.getNumItems()) return NULL;
+ return subitems.enumItem(nth);
+}
+
+void TreeItem::setCurRect(int x1, int y1, int x2, int y2, int z) {
+ curRect.left = x1;
+ curRect.right = x2;
+ curRect.top = y1;
+ curRect.bottom = y2;
+ _z = z;
+}
+
+int TreeItem::getIndent() {
+ return _z;
+}
+
+bool TreeItem::hasSubItems() {
+ return subitems.getNumItems()>0;
+}
+
+bool TreeItem::needTab() {
+ return (childTab == TAB_YES || (childTab == TAB_AUTO && hasSubItems()));
+}
+
+bool TreeItem::isExpanded() {
+ if (!hasSubItems()) return FALSE;
+ return expandStatus == STATUS_EXPANDED;
+}
+
+bool TreeItem::isCollapsed() {
+ if (!hasSubItems()) return TRUE;
+ return expandStatus == STATUS_COLLAPSED;
+}
+
+int TreeItem::getCurRect(RECT *r) {
+ r->left = curRect.left-tree->getScrollX();
+ r->top = curRect.top-tree->getScrollY();
+ r->right = curRect.right-tree->getScrollX();
+ r->bottom = curRect.bottom-tree->getScrollY();
+ RECT c;
+ tree->getClientRect(&c);
+ r->top += c.top;
+ r->bottom += c.top;
+ r->left += c.left;
+ r->right += c.left;
+ return 1;
+}
+
+TreeWnd *TreeItem::getTree() const {
+ return tree;
+}
+
+void TreeItem::setSelected(bool isSelected, bool expandCollapse, bool editifselected) {
+ bool wasselected = selected;
+ selected = !!isSelected;
+
+ if (selected != wasselected) {
+ invalidate();
+ tree->repaint();
+ if (selected) {
+ onSelect();
+ ASSERT(tree != NULL);
+ tree->onItemSelected(this);
+ } else {
+ onDeselect();
+ ASSERT(tree != NULL);
+ tree->onItemDeselected(this);
+ }
+ } else {
+ if (selected && editifselected) {
+ editLabel();
+ }
+ }
+
+ if (expandCollapse) {
+ if (isCollapsed())
+ expand();
+ else
+ collapse();
+ }
+}
+
+void TreeItem::invalidate() {
+ if (tree) {
+ RECT r;
+ getCurRect(&r);
+ tree->invalidateRect(&r);
+ }
+}
+
+bool TreeItem::isSelected() {
+ return selected;
+}
+
+int TreeItem::collapse() {
+ int old = expandStatus;
+
+ if (hasSubItems()) {
+ if (expandStatus == STATUS_COLLAPSED)
+ return 0;
+ expandStatus = STATUS_COLLAPSED;
+ RECT c;
+ tree->getClientRect(&c);
+ RECT r;
+ getCurRect(&r);
+ r.bottom = c.bottom;
+ r.left = c.left;
+ r.right = c.right;
+ if (tree) {
+ tree->invalidateRect(&r);
+ tree->invalidateMetrics();
+ }
+ }
+
+ onCollapse();
+
+ return old != expandStatus;
+}
+
+int TreeItem::expand() {
+ int old = expandStatus;
+
+ if (hasSubItems()) {
+ if (expandStatus == STATUS_EXPANDED)
+ return 0;
+ expandStatus = STATUS_EXPANDED;
+ RECT c;
+ tree->getClientRect(&c);
+ RECT r;
+ getCurRect(&r);
+ r.bottom = c.bottom;
+ r.left = c.left;
+ r.right = c.right;
+ if (tree) {
+ tree->invalidateRect(&r);
+ tree->invalidateMetrics();
+ }
+ }
+
+ onExpand();
+
+ return old != expandStatus;
+}
+
+int TreeItem::onContextMenu(int x, int y) {
+ return 0;
+}
+
+void TreeItem::setHilitedDrop(bool ishilitedDrop) {
+ bool washilighted = hilitedDrop;
+ hilitedDrop = !!ishilitedDrop;
+
+ if (washilighted != hilitedDrop)
+ invalidate();
+}
+
+void TreeItem::setHilited(bool ishilited) {
+ bool washilighted = hilited;
+ hilited = !!ishilited;
+
+ if (washilighted != hilited)
+ invalidate();
+}
+
+TreeItem *TreeItem::getParent() {
+ return parent;
+}
+
+bool TreeItem::isHilitedDrop() {
+ return hilitedDrop;
+}
+
+bool TreeItem::isHilited() {
+ return hilited;
+}
+
+void TreeItem::setIcon(SkinBitmap *newicon) {
+ if (icon) {
+ delete icon;
+ icon = NULL;
+ }
+ icon = newicon;
+ invalidate();
+}
+
+SkinBitmap *TreeItem::getIcon() {
+ return icon;
+}
+
+void TreeItem::sortItems() {
+ subitems.sort();
+}
+
+void TreeItem::editLabel() {
+ if (!tree) return;
+ tree->editItemLabel(this);
+}
+
+int TreeItem::onBeginLabelEdit() {
+ return 1; // disable editing by default
+}
+
+int TreeItem::onEndLabelEdit(const wchar_t *newlabel)
+{
+ return 1; // accept new label by default
+}
+
+void TreeItem::setEdition(bool isedited) {
+ being_edited = !!isedited;
+ invalidate();
+}
+
+bool TreeItem::getEdition() {
+ return being_edited;
+}
+
+bool TreeItem::isSorted()
+{
+ return subitems.getAutoSort();
+}
+
diff --git a/Src/Wasabi/api/wnd/wndclass/treewnd.h b/Src/Wasabi/api/wnd/wndclass/treewnd.h
new file mode 100644
index 00000000..454b9349
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/treewnd.h
@@ -0,0 +1,624 @@
+#ifndef _TREEWND_H
+#define _TREEWND_H
+
+// BU: lots of changes
+// - all items must be deletable, and will be deleted on destructor
+// - root items list not allocated w/ new
+// - items set sorting within their PtrListSorted instead of manually calling it
+// - setting an item to auto-sort does *not* make subitems autosort too
+
+#include <api/wnd/wndclass/scbkgwnd.h>
+#include <bfc/ptrlist.h>
+#include <api/wnd/wndclass/editwnd.h>
+#include <bfc/common.h>
+#include <tataki/color/skinclr.h>
+
+#define TREEWND_PARENT ScrlBkgWnd
+
+#define STATUS_EXPANDED 0
+#define STATUS_COLLAPSED 1
+
+#define HITTEST_BEFORE 0
+#define HITTEST_IN 1
+#define HITTEST_AFTER 2
+
+#define LINK_RIGHT 1
+#define LINK_TOP 2
+#define LINK_BOTTOM 4
+
+#define TAB_NO FALSE
+#define TAB_YES TRUE
+#define TAB_AUTO 2
+
+#define WM_SETITEMDEFERRED WM_USER+6546
+
+#define DC_SETITEM 10
+#define DC_DELITEM 20
+#define DC_EXPAND 30
+#define DC_COLLAPSE 40
+
+// Forward references
+
+class TreeItemList;
+class TreeItem;
+class TreeWnd;
+
+class FontSize;
+
+// classes & structs
+class CompareTreeItem {
+public:
+ static int compareItem(TreeItem *p1, TreeItem *p2);
+};
+
+class TreeItemList : public PtrListQuickSorted<TreeItem, CompareTreeItem> { };
+
+class TreeItem
+{
+friend class TreeWnd;
+public:
+ TreeItem(const wchar_t *label=NULL);
+ virtual ~TreeItem();
+
+ virtual SkinBitmap *getIcon();
+ virtual void setIcon(SkinBitmap *newicon);
+
+ virtual void onTreeAdd() {}
+ virtual void onTreeRemove() {}
+ virtual void onChildItemRemove(TreeItem *item) {}
+ // override this to keep from being selected
+ virtual int isHitTestable() { return 1; }
+ virtual void onSelect() {}
+ virtual void onDeselect() {}
+ virtual int onLeftDoubleClick() { return 0; }
+ virtual int onRightDoubleClick() { return 0; }
+ virtual int onContextMenu(int x, int y);
+ virtual int onChar(UINT key) { return 0; } // return 1 if you eat the key
+
+ // these are called after the expand/collapse happens
+ virtual void onExpand() {}
+ virtual void onCollapse() {}
+
+ virtual int onBeginLabelEdit();
+ virtual int onEndLabelEdit(const wchar_t *newlabel);
+
+ virtual void setLabel(const wchar_t *label);
+ virtual const wchar_t *getLabel();
+
+ void setTip(const wchar_t *tip);
+ const wchar_t *getTip();
+
+ // override to draw by yourself. Return the width of what you've drawn
+ virtual int customDraw(Canvas *canvas, const POINT &pt, int defaultTxtHeight, int indentation, const RECT &clientRect, const Wasabi::FontInfo *fontInfo);
+
+ // return 0 to refuse being dragged
+ // else return 1 and install the droptype and dropitem
+ // also, write suggested title into suggestedTitle if any
+ virtual int onBeginDrag(wchar_t *suggestedTitle) { return 0; }
+
+ virtual int dragOver(ifc_window *sourceWnd) { return 0; }
+ virtual int dragLeave(ifc_window *sourceWnd) { return 0; }
+ virtual int dragDrop(ifc_window *sourceWnd) { return 0; }
+
+ virtual int dragComplete(int success) { return 0; }
+
+ void ensureVisible();
+
+ TreeItem *getNthChild(int nth); // enumerates children (zero based)
+ TreeItem *getChild();
+ TreeItem *getChildSibling(TreeItem *item);
+ TreeItem *getSibling();
+ TreeItem *getParent();
+
+ void editLabel();
+
+ int getNumChildren();
+ bool hasSubItems();
+
+ void setSorted(int issorted);
+ void setChildTab(int haschildtab);
+ bool isSorted();
+
+ bool isCollapsed();
+ bool isExpanded();
+
+ void invalidate();
+ bool isSelected();
+ bool isHilited();
+ void setHilited(bool ishilited);
+
+ int collapse();
+ int expand();
+
+ int getCurRect(RECT *r);
+
+ void setCurrent(bool tf);
+
+ TreeWnd *getTree() const;
+
+protected:
+
+ bool isHilitedDrop();
+ void setHilitedDrop(bool ishilitedDrop);
+
+ void linkTo(TreeItem *linkto);
+// void childDeleted(TreeItem *child);
+ void setTree(TreeWnd *newtree);
+ void addSubItem(TreeItem *item);
+ void setCurRect(int x1, int y1, int x2, int y2, int z);
+ int getIndent();
+
+ bool needTab();
+ void sortItems(); // sorts the children of this item
+ void setEdition(bool isedited);
+ bool getEdition();
+
+private:
+ void setSelected(bool isselected, bool expandCollapse=false, bool editifselected=false);
+ // this really calls delete on the subitems
+ void deleteSubitems();
+
+ int removeSubitem(TreeItem *item);
+
+ int getItemWidth(int txtHeight, int indentation);
+
+ StringW label;
+ class TreeItem *parent;
+ TreeItemList subitems; // children
+ RECT curRect;
+ int childTab;
+ TreeWnd *tree;
+ int expandStatus;
+ SkinBitmap *icon;
+ int _z;
+ StringW tooltip; // if empty, falls back to livetip
+
+ bool selected:1;
+ bool hilitedDrop:1;
+ bool hilited:1;
+ bool being_edited:1;
+};
+
+
+/**
+
+
+ @short Tree-like view with leaf items.
+ @ver 1.0
+ @author Nullsoft
+ @see TreeItem
+*/
+class TreeWnd : public TREEWND_PARENT {
+
+friend class TreeItem;
+
+public:
+
+ /**
+ Sets up the default values for the TreeWnd. These defaults are
+ auto collapse enabled and sets the TreeWnd bitmaps to the default Wasabi
+ values.
+ */
+ TreeWnd();
+
+ /**
+ Deletes all the root items (including subitems).
+ */
+ virtual ~TreeWnd();
+
+ /**
+ Event is triggered when the button is about to be initialized.
+ Override this event to implement your own behavior.
+
+ @ret 1
+ */
+ virtual int onInit();
+
+ /**
+ Paints the bitmap on canvas according
+ to current options (centering, tiling, stretching, title).
+
+ @ret 0 for failure, 1 for success
+ @param canvas The canvas on which to paint.
+ */
+ virtual int onPaint(Canvas *canvas);
+
+ /**
+ Notify a child window via a generic message system.
+
+ @see addChild()
+ @ret
+ @param child A pointer to the child window which will receive the notify.
+ @param msg The message you want to send to the child.
+ @param p1 A user parameter.
+ @param p2 A user parameter.
+ */
+ virtual int childNotify(ifc_window *child, int msg, intptr_t param1=0, intptr_t param2=0);
+
+ /**
+ Event triggered when the left mouse
+ button is pressed over the TreeWnd.
+
+ Override this to implement your own behavior.
+
+ Default behavior is to stop editing a TreeItem label
+ (if editing was occuring). Also will cause a collapse
+ or expansion of the subitems if an item was previously
+ selected.
+
+ @ret 1, If you handle the event.
+ @param x The X coordinate of the mouse.
+ @param y The Y coordinate of the mouse.
+ */
+ virtual int onLeftButtonDown(int x, int y);
+
+ /**
+ Event is triggered when the left mouse button
+ is released from a previously pressed state.
+
+ Override this to implement your own behavior.
+
+ @ret 1, If you handle the event.
+ @param x The X coordinate of the mouse.
+ @param y The Y coordinate of the mouse.
+ */
+ virtual int onLeftButtonUp(int x, int y);
+
+ /**
+ Event is triggered when the right mouse button
+ is released from a previously pressed state.
+
+ Override this to implement your own behavior.
+
+ @ret 1, If you handle the event.
+ @param x The X coordinate of the mouse.
+ @param y The Y coordinate of the mouse.
+ */
+ virtual int onRightButtonUp(int x, int y);
+
+ /**
+ Event is triggered when the mouse is moved
+ over the TreeWnd.
+
+ Override this to implement your own behavior.
+
+ Default is to handle drops (drag and drop).
+
+ @ret 1, If you handle the event.
+ @param x The X coordinate of the mouse.
+ @param y The Y coordinate of the mouse.
+ */
+ virtual int onMouseMove(int x, int y);
+
+ /**
+ Do we want the context command menu to pop-up
+ on right clicks?
+
+ Default is no.
+
+ @see ContextCmdI
+ @ret 0, AutoContextMenu off; 1, AutoContextMenu on;
+ */
+ virtual int wantAutoContextMenu() { return 0; }
+
+ /**
+ Event is triggered when the left mouse button
+ is double clicked and the cursor is over the
+ TreeWnd.
+
+ Default is to check if the doubleclick
+ happened over an item, if it did, it calls
+ the item's handler of this event.
+
+ @ret 1, if you handle the event.
+ @param x The X coordinate of the mouse.
+ @param y The Y coordinate of the mouse.
+ */
+ virtual int onLeftButtonDblClk(int x, int y);
+
+ /**
+ Event is triggered when the right mouse button
+ is double clicked and the cursor is over the
+ TreeWnd.
+
+ Default is to check if the doubleclick
+ happened over an item, if it did, it calls
+ the item's handler of this event.
+
+ @ret 1, If you handle the event.
+ @param x The X coordinate of the mouse.
+ @param y The y coordinate of the mouse.
+ */
+ virtual int onRightButtonDblClk(int x, int y);
+
+ /**
+ Event is triggered when the mouse wheel
+ is rolled up.
+
+ Override this to implement your own behavior.
+
+ Default is to scroll vertically as required.
+ When the wheel is clicked and rolled, the
+ TreeWnd is scrolled horizontally.
+
+ @ret 1, If you handle the event.
+ @param clicked The pushed state of the mouse wheel.
+ @param lines The number of lines to scroll (or columns if horizontally scrolling).
+ */
+ virtual int onMouseWheelUp(int clicked, int lines);
+
+ /**
+ Event is triggered when the mouse wheel
+ is rolled down.
+
+ Override this to implement your own behavior.
+
+ Default is to scroll vertically as required.
+ When the wheel is clicked and rolled, the
+ TreeWnd is scrolled horizontally.
+
+ @ret 1, If you handle the event.
+ @param clicked The pushed state of the mouse wheel.
+ @param lines The number of lines to scroll (or columns if horizontally scrolling).
+ */
+ virtual int onMouseWheelDown(int clicked, int lines);
+
+ /**
+ */
+ virtual void timerCallback(int c);
+
+ /**
+ Event is triggered when the right click occurs over
+ the TreeWnd, but not on a TreeItem.
+
+ Override this to implement your own behavior.
+
+ @ret 1, If you handle the event.
+ @param x The X coordinate of the mouse.
+ @param y The Y coordinate of the mouse.
+ */
+ virtual int onContextMenu(int x, int y);
+
+ // override and return 1 to abort calling context menu on item
+ virtual int onPreItemContextMenu(TreeItem *item, int x, int y) { return 0; }
+ // override to catch when item context menu complete
+ virtual void onPostItemContextMenu(TreeItem *item, int x, int y, int retval) { }
+
+ /**
+ Event is triggered when a scheduled deferred callback
+ occurs.
+
+ Override this to implement your own behavior.
+
+ @ret 1, If you handle this event; 0, If you do not handle this event;
+ @param param1 Generic user paramater 1.
+ @param param2 Generic user paramater 2.
+ */
+ virtual int onDeferredCallback(intptr_t param1, intptr_t param2);
+
+ /**
+ Event is triggered when a key is pressed
+ and the TreeWnd has focus.
+
+ Override this to implement your own behavior.
+
+ @ret 1, If you handle the event.
+ @param c The key that was pressed.
+ */
+ virtual int onChar(unsigned int c);
+
+ /**
+ Event is triggered when a key is pressed
+ and the TreeWnd has focus.
+
+ This method handles extended keys.
+
+ @ret 1, If you handle the event.
+ */
+ virtual int onKeyDown(int keycode);
+
+ /**
+
+ */
+ virtual void jumpToNext(wchar_t c);
+
+ /**
+ Verifies if the item received is in the
+ viewable area of the TreeWnd. If not, it
+ will make it visible by scrolling to the
+ appropriate position.
+
+ @param item A pointer to the item to verify.
+ */
+ void ensureItemVisible(TreeItem *item);
+
+ // don't need to override this: just calls thru to the treeitem
+ virtual int onBeginDrag(TreeItem *treeitem);
+
+ virtual int dragEnter(ifc_window *sourceWnd);
+ virtual int dragOver(int x, int y, ifc_window *sourceWnd);
+ virtual int dragLeave(ifc_window *sourceWnd);
+ virtual int dragDrop(ifc_window *sourceWnd, int x, int y);
+
+ virtual int dragComplete(int success);
+
+ int wantFocus() { return 1; }
+
+ // override this if you want to control the item sort order
+ virtual int compareItem(TreeItem *p1, TreeItem *p2);
+
+protected:
+ // these will be called if the pointer is not over a treeitem
+ virtual int defaultDragOver(int x, int y, ifc_window *sourceWnd) { return 0; }
+ virtual int defaultDragDrop(ifc_window *sourceWnd, int x, int y) { return 0; }
+
+ // called with item that received a drop
+ virtual void onItemRecvDrop(TreeItem *item) {}
+
+ virtual void onLabelChange(TreeItem *item) {}
+
+ virtual void onItemSelected(TreeItem *item) {}
+ virtual void onItemDeselected(TreeItem *item) {}
+
+ virtual int onGetFocus();
+ virtual int onKillFocus();
+
+public:
+
+ virtual int getContentsWidth();
+ virtual int getContentsHeight();
+
+ void setRedraw(bool r);
+
+ TreeItem *addTreeItem(TreeItem *item, TreeItem *par=NULL, int sorted=TRUE, int haschildtab=FALSE);
+
+ // just removes a TreeItem from the tree, doesn't delete it... this is for
+ // ~TreeItem to call only
+ int removeTreeItem(TreeItem *item);
+
+ void moveTreeItem(TreeItem *item, TreeItem *newparent);
+
+ void deleteAllItems();
+
+ int expandItem(TreeItem *item);
+ void expandItemDeferred(TreeItem *item);
+ int collapseItem(TreeItem *item);
+ void collapseItemDeferred(TreeItem *item);
+
+ void selectItem(TreeItem *item); // selects.
+ void selectItemDeferred(TreeItem *item);// selects. posted.
+ void delItemDeferred(TreeItem *item);
+ void hiliteItem(TreeItem *item);
+ void unhiliteItem(TreeItem *item);
+ void setHilitedColor(const wchar_t *colorname);
+ ARGB32 getHilitedColor();
+
+ TreeItem *getCurItem();
+
+ TreeItem *hitTest(POINT pos);
+ TreeItem *hitTest(int x, int y);
+
+ void editItemLabel(TreeItem *item);
+ void cancelEditLabel(int destroyit=0);
+ void setAutoEdit(int ae);
+ int getAutoEdit();
+ // use a NULL item to search all items. returns first item found
+ TreeItem *getByLabel(TreeItem *item, const wchar_t *name);
+
+ int getItemRect(TreeItem *item, RECT *r);
+
+ int ownerDraw();
+
+ int getNumRootItems();
+ TreeItem *enumRootItem(int which);
+
+ void setSorted(bool dosort);
+ bool getSorted();
+
+ void sortTreeItems();
+
+ TreeItem *getSibling(TreeItem *item);
+
+ TreeItem *getItemFromPoint(POINT *pt);
+
+ void setAutoCollapse(bool doautocollapse);
+
+ virtual int setFontSize(int newsize);
+ int getFontSize();
+
+ int getNumVisibleChildItems(TreeItem *c);
+ int getNumVisibleItems();
+ TreeItem *enumVisibleItems(int n);
+ TreeItem *enumVisibleChildItems(TreeItem *c, int n);
+ int findItem(TreeItem *i); // reverse
+ int findChildItem(TreeItem *c, TreeItem *i, int *n);
+
+ TreeItem *enumAllItems(int n); // unsorted
+
+ void onSelectItem(TreeItem *i);
+ void onDeselectItem(TreeItem *i);
+
+protected:
+ void hiliteDropItem(TreeItem *item);
+ void unhiliteDropItem(TreeItem *item);
+ void invalidateMetrics();
+
+private:
+ TreeItemList items; // root-level stuff
+
+ PtrList<TreeItem> all_items; // unsorted
+
+ TreeItem *curSelected;
+
+ BltCanvas *dCanvas;
+
+ void drawItems(Canvas *c, const Wasabi::FontInfo *fontInfo);
+ void setCurItem(TreeItem *item, bool expandCollapse=true, bool editifselected=false);
+ void countSubItems(PtrList<TreeItem> &drawlist, TreeItemList *list, int indent, int *c, int *m, int z);
+ void getMetrics(int *numItemsShow, int *maxWidth);
+ void ensureMetricsValid();
+ int getLinkLine(TreeItem *item, int level);
+ void endEditLabel(const wchar_t *newlabel);
+ void editUpdate();
+ int jumpToNextSubItems(TreeItemList *list, wchar_t c);
+
+ int itemHeight;
+
+ AutoSkinBitmap tabClosed, tabOpen;
+ AutoSkinBitmap linkTopRight, linkTopBottom, linkTopRightBottom;
+ AutoSkinBitmap linkTabTopRight, linkTabTopBottom, linkTabTopRightBottom;
+
+ TreeItem *firstItemVisible;
+ TreeItem *lastItemVisible;
+
+ TreeItem *mousedown_item, *prevbdownitem;
+ POINT mousedown_anchor;
+ bool mousedown_dragdone;
+ TreeItem *hitItem, // the dest item
+ *draggedItem; // the source item
+
+ int inHitTest;
+
+ bool metrics_ok;
+ int maxWidth;
+ int maxHeight;
+
+ StringW defaultTip;
+
+ const wchar_t *getLiveTip();
+ void setLiveTip(const wchar_t *tip);
+ TreeItem *tipitem;
+
+ bool redraw;
+
+ PtrList<TreeItem> drawList;
+ TreeItem *edited;
+
+ EditWnd *editwnd;
+ wchar_t editbuffer[256];
+
+ int deleteItems;
+ bool firstFound;
+
+ TreeItem *currentItem;
+ StringW hilitedColorName;
+ SkinColor hilitedColor;
+ int autoedit;
+ int autocollapse;
+ int textsize;
+ StringW oldtip;
+ StringW accValue;
+};
+
+template<class T> class TreeItemParam : public TreeItem {
+public:
+ TreeItemParam(T _param, const wchar_t *label=NULL) : TreeItem(label) { param = _param; }
+
+ T getParam() { return param; }
+ operator T() { return getParam(); }
+
+private:
+ T param;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/typesheet.cpp b/Src/Wasabi/api/wnd/wndclass/typesheet.cpp
new file mode 100644
index 00000000..7df91946
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/typesheet.cpp
@@ -0,0 +1,38 @@
+#include <precomp.h>
+
+#include "typesheet.h"
+#include <api/wnd/wndclass/svcwndhold.h>
+#include <api/wnd/wndclass/buttbar.h>
+#include <api/service/svcs/svc_wndcreate.h>
+
+TypeSheet::TypeSheet(const wchar_t *_windowtype) :
+ TabSheet(ButtBar::STACK), windowtype(_windowtype)
+{ }
+
+int TypeSheet::onInit() {
+ TYPESHEET_PARENT::onInit();
+ load();
+ return 1;
+}
+
+void TypeSheet::setWindowType(const wchar_t *wtype) {
+ windowtype = wtype;
+}
+
+void TypeSheet::load() {
+ if (windowtype == NULL || !*windowtype) return;
+ WindowCreateByTypeEnum se(windowtype);
+ svc_windowCreate *svc;
+ while (svc = se.getNext()) {
+ for (int i = 0; ; i++) {
+ ServiceWndHolder *svcwnd = new ServiceWndHolder;
+ ifc_window *wnd = svc->createWindowOfType(windowtype, svcwnd, i);
+ if (wnd == NULL) {
+ delete svcwnd;
+ break;
+ }
+ svcwnd->setChild(wnd, svc);
+ addChild(svcwnd);
+ }
+ }
+}
diff --git a/Src/Wasabi/api/wnd/wndclass/typesheet.h b/Src/Wasabi/api/wnd/wndclass/typesheet.h
new file mode 100644
index 00000000..8f580084
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/typesheet.h
@@ -0,0 +1,49 @@
+#ifndef _TYPESHEET_H
+#define _TYPESHEET_H
+
+#include "tabsheet.h"
+
+#define TYPESHEET_PARENT TabSheet
+/**
+ Class TypeSheet
+
+ @short A Typesheet Control.
+ @author Nullsoft
+ @ver 1.0
+ @see
+*/
+class TypeSheet : public TYPESHEET_PARENT {
+public:
+
+ /**
+ TypeSheet constructor
+
+ @param _windowtype
+ */
+ TypeSheet(const wchar_t *windowtype);
+
+ /**
+ TypeSheet method onInit .
+
+ @ret 1
+ @param None
+ */
+ virtual int onInit();
+
+ /**
+ TypeSheet method load
+ */
+ virtual void load();
+
+ /**
+ TypeSheet method setWindowType .
+
+ @param windowtype The type of the window.
+ */
+ virtual void setWindowType(const wchar_t *windowtype);
+
+private:
+ StringW windowtype;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/virtualhostwnd.cpp b/Src/Wasabi/api/wnd/wndclass/virtualhostwnd.cpp
new file mode 100644
index 00000000..ef91ebc1
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/virtualhostwnd.cpp
@@ -0,0 +1,198 @@
+#include "precomp.h"
+#include "virtualhostwnd.h"
+#include <tataki/canvas/ifc_canvas.h>
+#include <tataki/region/api_region.h>
+
+VirtualHostWnd::VirtualHostWnd() {
+ group = new GuiObjectWnd();
+ fittoclient = 0;
+ xoffset = 0;
+ yoffset = 0;
+ groupwidth = 0;
+ groupheight = 0;
+ scripts_enabled = 1;
+}
+
+VirtualHostWnd::~VirtualHostWnd() {
+ delete group;
+}
+
+int VirtualHostWnd::onInit() {
+ GuiObjectWnd::onInit();
+ group->setVirtual(0);
+ group->setStartHidden(1);
+ group->setParent(this);
+ group->init(this);
+ group->deferedInvalidate();
+ group->setCloaked(1); // magic!
+ group->setVisible(1);
+ return 1;
+}
+
+void VirtualHostWnd::virtualhostwnd_setContent(const char *_groupname) {
+ group->setContent(_groupname);
+ if (isPostOnInit())
+ virtualhostwnd_onNewContent();
+}
+
+void VirtualHostWnd::virtualhostwnd_setContent(SkinItem *groupitem) {
+ group->setContentBySkinItem(groupitem);
+ if (isPostOnInit())
+ virtualhostwnd_onNewContent();
+}
+
+void VirtualHostWnd::virtualhostwnd_onNewContent() {
+}
+
+#ifdef WASABI_COMPILE_SCRIPT
+ScriptObject *VirtualHostWnd::virtualhostwnd_findScriptObject(const char *object_id) {
+ return group->findScriptObject(object_id);
+}
+#endif
+
+#ifdef WASABI_COMPILE_SKIN
+GuiObject *VirtualHostWnd::virtualhostwnd_getContent() {
+ return group->getContent();
+}
+
+ScriptObject *VirtualHostWnd::virtualhostwnd_getContentScriptObject() {
+ return group->getContentScriptObject();
+}
+
+GuiObject *VirtualHostWnd::virtualhostwnd_findObject(const char *object_id) {
+ return group->findObject(object_id);
+}
+#endif
+
+api_window *VirtualHostWnd::virtualhostwnd_getContentRootWnd() {
+ return group->getContentRootWnd();
+}
+
+int VirtualHostWnd::onPaint(Canvas *c) {
+ GuiObjectWnd::onPaint(c);
+
+ virtualhostwnd_onPaintBackground(c);
+
+ if (group == NULL) return 1;
+
+ RECT wr;
+ Canvas *cv = NULL;
+
+ group->getNonClientRect(&wr);
+ group->paint(NULL, NULL);
+
+ cv = group->getFrameBuffer();
+
+ if (cv != NULL) {
+ BltCanvas *bltcanvas = static_cast<BltCanvas *>(cv); // HACK!
+ bltcanvas->/*getSkinBitmap()->*/blitAlpha(c, xoffset, yoffset);
+ }
+ return 1;
+}
+
+void VirtualHostWnd::virtualhostwnd_onPaintBackground(Canvas *c) {
+ RECT r;
+ getClientRect(&r);
+ c->fillRect(&r, RGB(255,255,255));
+}
+
+int VirtualHostWnd::onResize() {
+ GuiObjectWnd::onResize();
+ if (group != NULL) {
+ RECT r;
+ getClientRect(&r);
+ if (fittoclient) {
+ xoffset = 0;
+ yoffset = 0;
+ groupwidth = r.right-r.left;
+ groupheight = r.bottom-r.top;
+ } else {
+ groupwidth = group->getGuiObject()->guiobject_getAutoWidth();
+ groupheight = group->getGuiObject()->guiobject_getAutoHeight();
+ if (groupwidth == AUTOWH) groupwidth = 320;
+ if (groupheight == AUTOWH) groupheight = 200;
+ int cw = r.right-r.left;
+ int ch = r.bottom-r.top;
+ xoffset = (cw - groupwidth)/2;
+ yoffset = (ch - groupheight)/2;
+ }
+ group->resize(xoffset+r.left, yoffset+r.top, groupwidth, groupheight);
+ }
+ return 1;
+}
+
+void VirtualHostWnd::virtualhostwnd_getContentRect(RECT *r) {
+ ASSERT(r != NULL);
+ getClientRect(r);
+ r->left += xoffset;
+ r->top += yoffset;
+ r->right = r->left + groupwidth;
+ r->bottom = r->top + groupheight;
+}
+
+
+void VirtualHostWnd::virtualhostwnd_fitToClient(int fit) {
+ fittoclient = fit;
+ if (isPostOnInit()) {
+ onResize();
+ invalidate();
+ }
+}
+
+void VirtualHostWnd::onChildInvalidate(api_region *r, api_window *who) {
+ GuiObjectWnd::onChildInvalidate(r, who);
+ api_region *clone = r->clone();
+ clone->offset(xoffset, yoffset);
+ invalidateRgn(clone);
+ r->disposeClone(clone);
+}
+
+int VirtualHostWnd::onLeftButtonDown(int x, int y) {
+ // DO NOT CALL GuiObjectWnd::onLeftButtonDown(x, y);
+ x -= xoffset;
+ y -= yoffset;
+ return group->wndProc(group->gethWnd(), WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(x, y));
+}
+
+int VirtualHostWnd::onLeftButtonUp(int x, int y){
+ // DO NOT CALL GuiObjectWnd::onLeftButtonUp(x, y);
+ x -= xoffset;
+ y -= yoffset;
+ return group->wndProc(group->gethWnd(), WM_LBUTTONUP, 0, MAKELPARAM(x, y));
+}
+
+int VirtualHostWnd::onRightButtonDown(int x, int y){
+ // DO NOT CALL GuiObjectWnd::onRightButtonDown(x, y);
+ x -= xoffset;
+ y -= yoffset;
+ return group->wndProc(group->gethWnd(), WM_RBUTTONDOWN, MK_RBUTTON, MAKELPARAM(x, y));
+}
+
+int VirtualHostWnd::onRightButtonUp(int x, int y){
+ // DO NOT CALL GuiObjectWnd::onRightButtonUp(x, y);
+ x -= xoffset;
+ y -= yoffset;
+ return group->wndProc(group->gethWnd(), WM_RBUTTONUP, 0, MAKELPARAM(x, y));
+}
+
+int VirtualHostWnd::onLeftButtonDblClk(int x, int y){
+ // DO NOT CALL GuiObjectWnd::onLeftButtonDblClk(x, y);
+ x -= xoffset;
+ y -= yoffset;
+ return group->wndProc(group->gethWnd(), WM_RBUTTONDBLCLK, 0, MAKELPARAM(x, y));
+}
+
+int VirtualHostWnd::onRightButtonDblClk(int x, int y){
+ // DO NOT CALL GuiObjectWnd::onRightButtonDblClk(x, y);
+ x -= xoffset;
+ y -= yoffset;
+ return group->wndProc(group->gethWnd(), WM_LBUTTONDBLCLK, 0, MAKELPARAM(x, y));
+}
+
+int VirtualHostWnd::onMouseMove(int x, int y){
+ // DO NOT CALL GuiObjectWnd::onMouseMove(x, y);
+ x -= xoffset;
+ y -= yoffset;
+ return group->wndProc(group->gethWnd(), WM_MOUSEMOVE, 0, MAKELPARAM(x, y));
+}
+
diff --git a/Src/Wasabi/api/wnd/wndclass/virtualhostwnd.h b/Src/Wasabi/api/wnd/wndclass/virtualhostwnd.h
new file mode 100644
index 00000000..8dbeb93f
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/virtualhostwnd.h
@@ -0,0 +1,51 @@
+#ifndef __VIRTUALHOSTWND_H
+#define __VIRTUALHOSTWND_H
+
+#include "../../common/guiobjwnd.h"
+
+class VirtualHostWnd : public GuiObjectWnd {
+ public:
+ VirtualHostWnd();
+ virtual ~VirtualHostWnd();
+
+ virtual int onInit();
+ virtual int onPaint(Canvas *c);
+ virtual int onResize();
+ virtual void onChildInvalidate(api_region *r, ifc_window *who);
+
+ virtual int onLeftButtonDown(int x, int y);
+ virtual int onLeftButtonUp(int x, int y);
+ virtual int onRightButtonDown(int x, int y);
+ virtual int onRightButtonUp(int x, int y);
+ virtual int onLeftButtonDblClk(int x, int y);
+ virtual int onRightButtonDblClk(int x, int y);
+ virtual int onMouseMove(int x, int y);
+
+ virtual void virtualhostwnd_setContent(const wchar_t *groupid);
+ virtual void virtualhostwnd_setContent(SkinItem *item);
+ virtual void virtualhostwnd_onNewContent();
+ virtual void virtualhostwnd_onPaintBackground(Canvas *c);
+
+ virtual void virtualhostwnd_fitToClient(int fit);
+ virtual void virtualhostwnd_getContentRect(RECT *r);
+
+ virtual ifc_window *virtualhostwnd_getContentRootWnd();
+#ifdef WASABI_COMPILE_SCRIPT
+ virtual ScriptObject *virtualhostwnd_findScriptObject(const wchar_t *object_id);
+#endif
+#ifdef WASABI_COMPILE_SKIN
+ virtual GuiObject *virtualhostwnd_findObject(const wchar_t *object_id);
+ virtual GuiObject *virtualhostwnd_getContent();
+ virtual ScriptObject *virtualhostwnd_getContentScriptObject();
+#endif
+
+ private:
+
+ GuiObjectWnd *group;
+ int fittoclient;
+ int xoffset, yoffset;
+ int groupwidth, groupheight;
+ int scripts_enabled;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndclass/wndholder.cpp b/Src/Wasabi/api/wnd/wndclass/wndholder.cpp
new file mode 100644
index 00000000..272298a3
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/wndholder.cpp
@@ -0,0 +1,369 @@
+#include <precomp.h>
+#include "wndholder.h"
+#include <api/service/svcs/svc_wndcreate.h>
+#include <api/service/svc_enum.h>
+#include <api/syscb/callbacks/wndcb.h>
+
+//#pragma CHAT("lone", "benski", "needs to dispatch Layout & Containers!")
+#include <api/wndmgr/container.h>
+#include <api/wndmgr/layout.h>
+
+#define CBCLASS WindowHolderI
+START_DISPATCH;
+ CB(WNDHOLDER_ONINSERTWINDOW, onInsertWindow);
+ VCB(WNDHOLDER_ONREMOVEWINDOW, onRemoveWindow);
+ CB(WNDHOLDER_WANTGUID, wantGuid);
+ CB(WNDHOLDER_WANTGROUP, wantGroup);
+ CB(WNDHOLDER_GETROOTWNDPTR, getRootWndPtr);
+ CB(WNDHOLDER_GETCURGROUPID, getCurGroupId);
+ CB(WNDHOLDER_GETCURGUID, getCurGuid);
+ CB(WNDHOLDER_GETCURROOTWND, getCurRootWnd);
+ CB(WNDHOLDER_GETCURID, getCurId);
+ CB(WNDHOLDER_ISGENERICGUID, acceptsGenericGuid);
+ CB(WNDHOLDER_ISGENERICGROUP, acceptsGenericGroup);
+ VCB(WNDHOLDER_CANCELDEFERREDREMOVE, cancelDeferredRemove);
+ VCB(WNDHOLDER_ONNEEDRELOADGRP, wndholder_onNeedReloadGroup);
+ CB(WNDHOLDER_WANTAUTOFOCUS, wndholder_wantAutoFocus);
+ CB(WNDHOLDER_ISAUTOAVAILABLE, wndholder_isAutoAvailable);
+END_DISPATCH;
+
+WindowHolderI::WindowHolderI() {
+ wnd = NULL;
+ dr = NULL;
+ generic_guid = 1;
+ generic_group = 1;
+ cur_guid = INVALID_GUID;
+ cur_groupid = NULL;
+ wc_svc = NULL;
+ WASABI_API_WNDMGR->wndholder_register(this);
+}
+
+WindowHolderI::~WindowHolderI() {
+ delete dr;
+ if (wnd != NULL) {
+ if (wc_svc) {
+ ifc_window *w = wnd;
+ wnd = NULL;
+ wc_svc->destroyWindow(w);
+ SvcEnum::release(wc_svc);
+ wc_svc = NULL;
+ } else {
+ ifc_window *w = wnd;
+ wnd = NULL;
+ WASABI_API_SKIN->group_destroy(w);
+ }
+ }
+ accepted_groups.deleteAll();
+ accepted_guids.deleteAll();
+ WASABI_API_WNDMGR->wndholder_unregister(this);
+}
+
+ifc_window *WindowHolderI::onInsertWindow(GUID g, const wchar_t *groupid)
+{
+ cancelDeferredRemove();
+
+ defered_guid = INVALID_GUID;
+ if (wnd != NULL) return NULL;
+
+ cur_groupid = groupid;
+ if (g != INVALID_GUID)
+ {
+ cur_guid = g;
+ wchar_t cguid[256] = {0};
+ nsGUID::toCharW(g, cguid);
+ cur_id = cguid;
+ } else
+ cur_id = groupid;
+
+ wnd = createWindow(g == INVALID_GUID ? NULL : &g, groupid);
+ if (!wnd) {
+ cur_guid = INVALID_GUID;
+ cur_id = L"";
+ cur_groupid = L"";
+ }
+ if (wnd) {
+ onInsert(wnd, cur_id);
+ } else {
+ if (g != INVALID_GUID) {
+ defered_guid = g;
+ }
+ }
+ return wnd;
+}
+
+void WindowHolderI::onRemoveWindow(int deferred) {
+ if (deferred) {
+ if (!dr)
+ dr = new DeferredRemove(this);
+ dr->post();
+ return;
+ }
+ if (wnd != NULL) {
+ ifc_window *w = getCurRootWnd();
+ onRemove(w, cur_id);
+ destroyWindow();
+ cur_guid = INVALID_GUID;
+ cur_groupid = NULL;
+ defered_guid = INVALID_GUID;
+ }
+}
+
+void WindowHolderI::cancelDeferredRemove() {
+ delete dr;
+ dr = NULL;
+}
+
+void WindowHolderI::wndholder_onNeedReloadGroup(const wchar_t *id)
+{
+ if (cur_groupid.isempty()) return;
+ ifc_window *w = getCurRootWnd();
+ if (w == NULL) return;
+ if (w->isInited() && !WCSICMP(cur_groupid, id))
+ {
+ onRemove(w, cur_id);
+ destroyWindow();
+ createWindow(&INVALID_GUID, id);
+ onInsert(wnd, cur_id);
+ }
+}
+
+ifc_window *WindowHolderI::createWindow(const GUID *g, const wchar_t *groupid)
+{
+ ASSERT(wnd == NULL);
+ if (g != NULL && *g != INVALID_GUID) {
+ wc_svc = WindowCreateByGuidEnum(*g).getFirst();
+ if (wc_svc)
+ wnd = wc_svc->createWindowByGuid(*g, getRootWndPtr());
+ }
+ else if (groupid != NULL)
+ {
+ wc_svc = NULL;
+ wnd = WASABI_API_SKIN->group_create(groupid);
+ }
+ if (wnd) {
+ if (!wnd->isInited()) {
+ if (!wnd->getParent()) wnd->setParent(getRootWndPtr());
+ wnd->init(getRootWndPtr());
+ }
+ }
+ return wnd;
+}
+
+void WindowHolderI::destroyWindow() {
+ ASSERT(wnd != NULL);
+
+ ifc_window *w = wnd->getDesktopParent();
+
+ if (wc_svc) {
+ ifc_window *w = wnd;
+ wnd = NULL;
+ wc_svc->destroyWindow(w);
+ SvcEnum::release(wc_svc);
+ wc_svc = NULL;
+ } else {
+ ifc_window *w = wnd;
+ wnd = NULL;
+ WASABI_API_SKIN->group_destroy(w);
+ }
+
+ if (w != NULL) {
+ if (w->getInterface(layoutGuid)) {
+ static_cast<Layout *>(w)->updateTransparency();
+ }
+ }
+
+}
+
+void WindowHolderI::addAcceptGuid(GUID g) {
+ accepted_guids.addItem(new GUID(g));
+}
+
+void WindowHolderI::addAcceptGroup(const wchar_t *groupid)
+{
+ accepted_groups.addItem(new StringW(groupid));
+}
+
+void WindowHolderI::setAcceptAllGuids(int tf) {
+ generic_guid = tf;
+}
+
+void WindowHolderI::setAcceptAllGroups(int tf) {
+ generic_group = tf;
+}
+
+int WindowHolderI::wantGuid(GUID g) {
+ if (acceptsGenericGuid()) return 1;
+ for (int i=0;i<accepted_guids.getNumItems();i++) {
+ if (*accepted_guids.enumItem(i) == g) return 1;
+ }
+ return 0;
+}
+
+int WindowHolderI::wantGroup(const wchar_t *groupid)
+{
+ if (acceptsGenericGroup()) return 1;
+ for (int i=0;i<accepted_groups.getNumItems();i++) {
+ if (!WCSICMP(accepted_groups.enumItem(i)->getValue(), groupid))
+ return 1;
+ }
+ return 0;
+}
+
+GUID *WindowHolderI::getFirstAcceptedGuid() {
+ if (accepted_guids.getNumItems() == 0) return NULL;
+ return accepted_guids.enumItem(0);
+}
+
+const wchar_t *WindowHolderI::getFirstAcceptedGroup()
+{
+ if (accepted_guids.getNumItems() == 0)
+ return NULL;
+ return
+ accepted_groups.enumItem(0)->getValue();
+}
+
+int WindowHolderI::wndholder_wantAutoFocus() {
+ return 1;
+}
+
+WindowHolderWnd::WindowHolderWnd() {
+ autoavail = 1;
+ autoopen = 1;
+ autoclose = 0;
+ nocmdbar = 0;
+ noanim = 0;
+ has_wnd = 0;
+ autofocus = 1;
+ WASABI_API_SYSCB->syscb_registerCallback(this);
+}
+
+WindowHolderWnd::~WindowHolderWnd() {
+ if (has_wnd) {
+ notifyOnRemove();
+ }
+ WASABI_API_SYSCB->syscb_deregisterCallback(this);
+}
+
+int WindowHolderWnd::onResize() {
+ WINDOWHOLDER_PARENT::onResize();
+ if (getCurRootWnd()) {
+ RECT r;
+ getClientRect(&r);
+ if (!getCurRootWnd()->handleRatio())
+ multRatio(&r);
+ getCurRootWnd()->resize(r.left, r.top, r.right-r.left, r.bottom-r.top);
+ }
+ return 1;
+}
+
+int WindowHolderWnd::handleRatio() {
+ return 1;
+}
+
+int WindowHolderWnd::handleDesktopAlpha() {
+ if (getCurRootWnd()) return getCurRootWnd()->handleDesktopAlpha();
+ return 1;
+}
+
+int WindowHolderWnd::handleTransparency() {
+ if (getCurRootWnd()) return getCurRootWnd()->handleTransparency();
+ return 1;
+}
+
+int WindowHolderWnd::onInit() {
+ WINDOWHOLDER_PARENT::onInit();
+ if (isVisible() && autoopen && getFirstAcceptedGuid()) {
+ onInsertWindow(*getFirstAcceptedGuid(), NULL);
+ } else if (isVisible() && autoopen && getFirstAcceptedGroup()) {
+ onInsertWindow(INVALID_GUID, getFirstAcceptedGroup());
+ }
+ return 1;
+}
+
+#define DC_NOTIFYONREMOVE 0x205
+
+void WindowHolderWnd::onRemove(ifc_window *w, const wchar_t *id)
+{
+ ifc_window *dw = getDesktopParent();
+ if (dw) dw->removeMinMaxEnforcer(this);
+ postDeferredCallback(DC_NOTIFYONREMOVE);
+}
+
+int WindowHolderWnd::onDeferredCallback(intptr_t p1, intptr_t p2) {
+ if (p1 == DC_NOTIFYONREMOVE) {
+ notifyOnRemove();
+ } else return WINDOWHOLDER_PARENT::onDeferredCallback(p1, p2);
+ return 1;
+}
+
+void WindowHolderWnd::onInsert(ifc_window *w, const wchar_t *id)
+{
+ if (isPostOnInit())
+ onResize();
+ ifc_window *dw = getDesktopParent();
+ if (dw) dw->addMinMaxEnforcer(this);
+ notifyOnInsert();
+ if (wndholder_wantAutoFocus()) w->setFocus();
+}
+
+int WindowHolderWnd::getPreferences(int what) {
+ if (getCurRootWnd()) return getCurRootWnd()->getPreferences(what);
+ return WINDOWHOLDER_PARENT::getPreferences(what);
+}
+
+void WindowHolderWnd::notifyOnRemove() {
+ has_wnd = 0;
+ Layout *l = getGuiObject()->guiobject_getParentLayout();
+ if (l != NULL) {
+ Container *c = l->getParentContainer();
+ if (c != NULL) {
+ c->notifyRemoveContent(this);
+ }
+ }
+}
+
+void WindowHolderWnd::notifyOnInsert() {
+ has_wnd = 1;
+ Layout *l = getGuiObject()->guiobject_getParentLayout();
+ if (l != NULL) {
+ Container *c = l->getParentContainer();
+ if (c != NULL)
+ {
+ c->notifyAddContent(this, getCurGroupId(), getCurGuid());
+ }
+ }
+}
+
+int WindowHolderWnd::onGroupChange(const wchar_t *grpid)
+{
+ WINDOWHOLDER_PARENT::onGroupChange(grpid);
+ wndholder_onNeedReloadGroup(grpid);
+ return 1;
+}
+
+void WindowHolderWnd::onSetVisible(int show) {
+ if (show && getCurRootWnd() == NULL) {
+ if (autoopen && getFirstAcceptedGuid()) {
+ onInsertWindow(*getFirstAcceptedGuid(), NULL);
+ } else if (autoopen && getFirstAcceptedGroup()) {
+ onInsertWindow(INVALID_GUID, getFirstAcceptedGroup());
+ }
+ } else if (!show && getCurRootWnd() != NULL) {
+ if (autoclose && WASABI_API_SKIN->skin_getVersion() >= 1.0)
+ onRemoveWindow(0);
+ }
+ if (getDeferedGuid() != INVALID_GUID) {
+ if (show) {
+ #ifdef ON_CREATE_EXTERNAL_WINDOW_GUID
+ int y;
+ ON_CREATE_EXTERNAL_WINDOW_GUID(getDeferedGuid(), y);
+ #endif
+ }
+ }
+ WINDOWHOLDER_PARENT::onSetVisible(show);
+}
+
+int WindowHolderWnd::wndholder_wantAutoFocus() {
+ return autofocus;
+}
+
diff --git a/Src/Wasabi/api/wnd/wndclass/wndholder.h b/Src/Wasabi/api/wnd/wndclass/wndholder.h
new file mode 100644
index 00000000..580b8ba2
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndclass/wndholder.h
@@ -0,0 +1,285 @@
+#ifndef __WINDOWHOLDER_H
+#define __WINDOWHOLDER_H
+
+#include <api/wnd/wndclass/guiobjwnd.h>
+#include <bfc/ptrlist.h>
+#include <api/syscb/callbacks/wndcb.h>
+#include <api/timer/timerclient.h>
+
+class svc_windowCreate;
+
+#define WINDOWHOLDER_PARENT GuiObjectWnd
+
+
+/**
+ Class
+
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see
+*/
+class WindowHolder : public Dispatchable
+{
+ public:
+ ifc_window *onInsertWindow(GUID g, const wchar_t *groupid);
+ void onRemoveWindow(int deferred=0);
+ int wantGuid(GUID g);
+ int wantGroup(const wchar_t *groupid);
+ GUID getCurGuid();
+ const wchar_t *getCurGroupId();
+ ifc_window *getCurRootWnd();
+ const wchar_t *getCurId();
+ ifc_window *getRootWndPtr();
+ int acceptsGenericGuid();
+ int acceptsGenericGroup();
+ int wndholder_getPreferences(int what);
+ void wndholder_onNeedReloadGroup(const wchar_t *id);
+ void cancelDeferredRemove();
+ int wndholder_wantAutoFocus();
+ int wndholder_isAutoAvailable();
+
+ enum {
+ WNDHOLDER_ONINSERTWINDOW=50,
+ WNDHOLDER_ONREMOVEWINDOW=100,
+ WNDHOLDER_WANTGUID=150,
+ WNDHOLDER_WANTGROUP=200,
+ WNDHOLDER_GETROOTWNDPTR=250,
+ WNDHOLDER_GETCURGUID=300,
+ WNDHOLDER_GETCURGROUPID=350,
+ WNDHOLDER_GETCURROOTWND=400,
+ WNDHOLDER_GETCURID=450,
+ WNDHOLDER_ISGENERICGUID=500,
+ WNDHOLDER_ISGENERICGROUP=550,
+ WNDHOLDER_GETPREFERENCES=600,
+ WNDHOLDER_ONNEEDRELOADGRP=650,
+ WNDHOLDER_CANCELDEFERREDREMOVE=660,
+ WNDHOLDER_WANTAUTOFOCUS=670,
+ WNDHOLDER_ISAUTOAVAILABLE=680,
+ };
+};
+
+inline ifc_window *WindowHolder::onInsertWindow(GUID g, const wchar_t *groupid) {
+ return _call(WNDHOLDER_ONINSERTWINDOW, (ifc_window *)NULL, g, groupid);
+}
+
+inline void WindowHolder::onRemoveWindow(int def) {
+ _voidcall(WNDHOLDER_ONREMOVEWINDOW, def);
+}
+
+inline int WindowHolder::wantGuid(GUID g) {
+ return _call(WNDHOLDER_WANTGUID, 0, g);
+}
+
+inline int WindowHolder::wantGroup(const wchar_t *groupid) {
+ return _call(WNDHOLDER_WANTGROUP, 0, groupid);
+}
+
+inline ifc_window *WindowHolder::getRootWndPtr() {
+ return _call(WNDHOLDER_GETROOTWNDPTR, (ifc_window *)NULL);
+}
+
+inline GUID WindowHolder::getCurGuid() {
+ return _call(WNDHOLDER_GETCURGUID, INVALID_GUID);
+}
+
+inline const wchar_t *WindowHolder::getCurGroupId() {
+ return _call(WNDHOLDER_GETCURGROUPID, (const wchar_t *)NULL);
+}
+
+inline ifc_window *WindowHolder::getCurRootWnd() {
+ return _call(WNDHOLDER_GETCURROOTWND, (ifc_window *)NULL);
+}
+
+inline const wchar_t *WindowHolder::getCurId() {
+ return _call(WNDHOLDER_GETCURID, (const wchar_t *)NULL);
+}
+
+inline int WindowHolder::acceptsGenericGuid() {
+ return _call(WNDHOLDER_ISGENERICGUID, 0);
+}
+
+inline int WindowHolder::acceptsGenericGroup() {
+ return _call(WNDHOLDER_ISGENERICGROUP, 0);
+}
+
+inline int WindowHolder::wndholder_getPreferences(int what) {
+ return _call(WNDHOLDER_GETPREFERENCES, 0, what);
+}
+
+inline void WindowHolder::wndholder_onNeedReloadGroup(const wchar_t *id) {
+ _voidcall(WNDHOLDER_ONNEEDRELOADGRP, id);
+}
+
+inline void WindowHolder::cancelDeferredRemove() {
+ _voidcall(WNDHOLDER_CANCELDEFERREDREMOVE);
+}
+
+inline int WindowHolder::wndholder_wantAutoFocus() {
+ return _call(WNDHOLDER_WANTAUTOFOCUS, 1);
+}
+
+inline int WindowHolder::wndholder_isAutoAvailable() {
+ return _call(WNDHOLDER_ISAUTOAVAILABLE, 1);
+}
+
+class DeferredRemove;
+
+/**
+ Class
+
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see
+*/
+class WindowHolderI : public WindowHolder {
+ public:
+
+ WindowHolderI();
+ virtual ~WindowHolderI();
+
+ virtual ifc_window *onInsertWindow(GUID g, const wchar_t *groupid);
+
+
+ virtual void onRemoveWindow(int deferred);
+
+
+ void addAcceptGuid(GUID g);
+ void addAcceptGroup(const wchar_t *groupid);
+ void setAcceptAllGuids(int tf);
+
+
+ void setAcceptAllGroups(int tf);
+
+ virtual int acceptsGenericGroup() { return generic_group; }
+
+ virtual int acceptsGenericGuid() { return generic_guid; }
+
+ virtual int wantGuid(GUID g);
+ virtual int wantGroup(const wchar_t *groupid);
+
+ virtual void onInsert(ifc_window *w, const wchar_t *id) {};
+
+ virtual void onRemove(ifc_window *w, const wchar_t *id) {};
+
+ virtual ifc_window *getRootWndPtr()=0;
+ virtual GUID getCurGuid() { return cur_guid; }
+ virtual const wchar_t *getCurGroupId() { return cur_groupid; }
+
+ virtual ifc_window *getCurRootWnd() { return wnd; }
+
+ virtual GUID *getFirstAcceptedGuid();
+ virtual const wchar_t *getFirstAcceptedGroup();
+ virtual const wchar_t *getCurId() { return cur_id; }
+
+ virtual void cancelDeferredRemove();
+ virtual int wndholder_isAutoAvailable() { return 1; }
+
+ GUID getDeferedGuid() { return defered_guid; }
+
+ virtual int wndholder_getPreferences(int what)=0;
+
+ virtual void wndholder_onNeedReloadGroup(const wchar_t *id);
+
+ private:
+
+
+ ifc_window *createWindow(const GUID *g, const wchar_t *groupid);
+ virtual int wndholder_wantAutoFocus();
+
+
+ void destroyWindow();
+
+ ifc_window *wnd;
+ GUID cur_guid;
+ StringW cur_groupid;
+ StringW cur_id;
+ PtrList<GUID> accepted_guids;
+ PtrList<StringW> accepted_groups;
+ int generic_guid;
+ int generic_group;
+
+ svc_windowCreate *wc_svc;
+ GUID defered_guid;
+
+ DeferredRemove *dr;
+
+ protected:
+
+ RECVS_DISPATCH;
+};
+
+
+/**
+ Class
+
+ @short
+ @author Nullsoft
+ @ver 1.0
+ @see
+*/
+class WindowHolderWnd : public WINDOWHOLDER_PARENT, public WindowHolderI
+{
+
+ public:
+
+ WindowHolderWnd();
+ virtual ~WindowHolderWnd();
+ virtual int onInit();
+
+ virtual ifc_window *getRootWndPtr() { return this; }
+ virtual void onInsert(ifc_window *w, const wchar_t *id);
+ virtual void onRemove(ifc_window *w, const wchar_t *id);
+ virtual int onResize();
+ virtual int handleRatio();
+ virtual int handleDesktopAlpha();
+ virtual int handleTransparency();
+ virtual int wndholder_getPreferences(int what) { return getPreferences(what); }
+ virtual int getPreferences(int what);
+ void setAutoOpen(int tf) { autoopen = tf; }
+ void setAutoClose(int tf) { autoclose = tf; }
+ void setNoCmdBar(int tf) { nocmdbar = tf; if (isInited()) invalidate(); }
+ void setNoAnim(int tf) { noanim = tf; }
+ virtual int onGroupChange(const wchar_t *grpid);
+ virtual int wndholder_wantAutoFocus();
+ void setAutoFocus(int autof) { autofocus = autof; }
+ void setAutoAvailable(int autoa) { autoavail = autoa; }
+ virtual int wndholder_isAutoAvailable() { return autoavail; }
+
+ private:
+ void notifyOnRemove(); // no virtual please
+ void notifyOnInsert(); // no virtual please
+ virtual void onSetVisible(int show);
+ virtual int onDeferredCallback(intptr_t p1, intptr_t p2);
+
+ int autoopen;
+ int autoclose;
+ int nocmdbar;
+ int noanim;
+ int has_wnd;
+ int autofocus;
+ int autoavail;
+};
+
+class DeferredRemove : public TimerClientDI
+{
+ public:
+ DeferredRemove(WindowHolderI *parent) : whi(parent) {}
+ virtual ~DeferredRemove() {}
+
+ void post() {
+ timerclient_postDeferredCallback(1, 0);
+ }
+
+ virtual int timerclient_onDeferredCallback(intptr_t p1, intptr_t p2) {
+ if (p1 == 1 && whi != NULL) whi->onRemoveWindow(0);
+ else return TimerClientDI::timerclient_onDeferredCallback(p1, p2);
+ return 0;
+ }
+
+ private:
+ WindowHolderI *whi;
+};
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndevent.h b/Src/Wasabi/api/wnd/wndevent.h
new file mode 100644
index 00000000..20ece975
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndevent.h
@@ -0,0 +1,5 @@
+#ifndef _WNDEVENT_H
+#define _WNDEVENT_H
+
+
+#endif
diff --git a/Src/Wasabi/api/wnd/wndtrack.cpp b/Src/Wasabi/api/wnd/wndtrack.cpp
new file mode 100644
index 00000000..c378550e
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndtrack.cpp
@@ -0,0 +1,945 @@
+#include <precomp.h>
+#include <bfc/ptrlist.h>
+#include <api/wnd/basewnd.h>
+#include <bfc/util/findopenrect.h>
+#include <bfc/bfc_assert.h>
+#include <api/wndmgr/resize.h>
+#include <api/wnd/wndtrack.h>
+#include <api/config/items/attrint.h>
+#include <api/config/items/attrbool.h>
+#include <bfc/wasabi_std_wnd.h>
+#ifdef WASABI_COMPILE_WNDMGR
+#include <api/wndmgr/snappnt.h>
+#endif
+
+#ifdef WASABI_COMPILE_SCRIPT
+#include <api/script/scriptobj.h>
+#include <api/script/scriptguid.h>
+#include <api/wnd/wndclass/guiobjwnd.h> // for appbar define
+#endif
+
+#ifdef WASABI_COMPILE_WNDMGR
+#include <api/wndmgr/layout.h>
+#include <api/wnd/popexitcb.h>
+#endif
+
+#ifdef WASABI_COMPILE_SYSCB
+//#include <api/syscb/cbmgr.h>
+#endif
+
+WindowTracker *windowTracker;
+
+WindowTracker::WindowTracker()
+ : coopcache(0),
+ coopcachewnd(NULL)
+{
+ wascoop = 0;
+ disabledock = 0;
+ dock_enabled = 1;
+}
+
+WindowTracker::~WindowTracker()
+{
+ coopList.deleteAll();
+}
+
+void WindowTracker::addWindow(ifc_window *wnd)
+{
+ ASSERT(wnd);
+ desktopwnds.addItem(wnd);
+}
+
+void WindowTracker::removeWindow(ifc_window *wnd)
+{
+ ASSERT(wnd);
+ ASSERTPR(desktopwnds.haveItem(wnd), "removewindow on invalid wnd");
+ desktopwnds.removeItem(wnd);
+}
+
+int WindowTracker::checkWindow(ifc_window *wnd)
+{
+ return allWnd.haveItem(wnd);
+}
+
+ifc_window *WindowTracker::enumWindows(int n)
+{
+ return desktopwnds.enumItem(n);
+}
+
+ifc_window *WindowTracker::getNextDesktopWindow(ifc_window *w, int next)
+{
+ ifc_window *nw = NULL;
+ if (w == NULL) nw = desktopwnds.getFirst();
+ else
+ {
+ w = w->getDesktopParent();
+ int pos = desktopwnds.searchItem(w);
+ if (pos == -1) nw = desktopwnds.getFirst();
+ else
+ {
+ pos += next;
+ if (pos > desktopwnds.getNumItems() - 1) pos = 0;
+ if (pos == -1) pos = desktopwnds.getNumItems() - 1;
+ nw = desktopwnds.enumItem(pos);
+ }
+ }
+ if (nw == w) return w;
+ if (!nw->isVisible()) return getNextDesktopWindow(nw, next);
+ return nw;
+}
+
+ifc_window *WindowTracker::enumAllWindows(int n)
+{
+ return allWnd.enumItem(n);
+}
+
+int WindowTracker::getNumWindows()
+{
+ return desktopwnds.getNumItems();
+}
+
+int WindowTracker::getNumAllWindows()
+{
+ return allWnd.getNumItems();
+}
+
+void WindowTracker::invalidateAllWindows()
+{
+ for (int i = allWnd.getNumItems() - 1;i >= 0;i--)
+ {
+ ifc_window *w = allWnd[i];
+ w->triggerEvent(TRIGGER_INVALIDATE);
+ w->invalidate();
+ if (!w->isVirtual()) continue;
+ w->triggerEvent(TRIGGER_ONRESIZE);
+ }
+}
+
+RECT WindowTracker::findOpenRect(const RECT &prev, ifc_window *exclude)
+{
+ POINT pp = { 0, 0 };
+ //CUT if (prev != NULL) {
+ pp.x = prev.left;
+ pp.y = prev.top;
+ //CUT }
+ RECT vr; // viewport rect
+ Wasabi::Std::getViewport(&vr, &pp);
+
+ // make a rect list
+ PtrList<RECT> list;
+ for (int i = 0; ; i++)
+ {
+ ifc_window *wnd = enumWindows(i);
+ if (wnd == NULL) break;
+ if (wnd == exclude) continue;
+ if (!wnd->isPostOnInit() && !wnd->isVisible()) continue;
+ RECT *r = new RECT;
+ wnd->getWindowRect(r);
+ snapAdjustWindowRect(wnd, r);
+ list.addItem(r);
+ }
+
+ FindOpenRect fr;
+ RECT ret = fr.find(vr, list, prev);
+ list.deleteAll();
+ return ret;
+}
+
+void WindowTracker::setDockDistance(int dd)
+{
+ dockDist = MINMAX(dd, MIN_DOCK_DIST, MAX_DOCK_DIST);
+}
+
+int WindowTracker::getDockDistance()
+{
+ if (dock_enabled) return dockDist;
+ return 0;
+}
+
+void WindowTracker::setEnableDocking(int ed)
+{
+ dock_enabled = ed;
+}
+
+bool WindowTracker::touches(const RECT &r2, const RECT &r1)
+{
+ if (r2.left == r1.right || r2.right == r1.left || r2.right == r1.right || r2.left == r1.left)
+ {
+ if (r2.bottom >= r1.top && r2.top <= r1.bottom)
+ return true;
+ }
+ if (r2.top == r1.bottom || r2.bottom == r1.top || r2.bottom == r1.bottom || r2.top == r1.top)
+ {
+ if (r2.right >= r1.left && r2.left <= r1.right)
+ return true;
+ }
+ return false;
+}
+
+void WindowTracker::endCooperativeMove()
+{
+ wascoop = 1;
+ flushCoopWnds();
+ coopWnd = NULL;
+ recursList.removeAll();
+}
+
+void WindowTracker::startCooperativeMove(ifc_window *thiswnd)
+{
+ coopWnd = thiswnd;
+ wascoop = 1;
+ flushCoopWnds();
+ if (recursList.getNumItems() > 0) recursList.removeAll();
+ addCooperative(thiswnd);
+ foreach_reverse(recursList)
+ // FG> we need to prevent windows from excessively activating our windows or focus is gonna blow up
+ // thiswnd->bringToFront();
+#ifdef WIN32
+ SetWindowPos(recursList.getfor()->gethWnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
+#else
+ recursList.getfor()->bringToFront();
+#endif
+ endfor;
+}
+
+int WindowTracker::getNumDocked()
+{
+ return recursList.getNumItems();
+}
+
+ifc_window *WindowTracker::enumDocked(int n)
+{
+ return recursList.enumItem(n);
+}
+
+void WindowTracker::addCooperative(ifc_window *thiswnd)
+{
+ int i;
+ RECT r;
+ RECT thisr;
+ bool forceall = false;
+
+ if (Std::keyModifier(STDKEY_ALT))
+ {
+ forceall = TRUE;
+ }
+
+#ifdef WASABI_COMPILE_WNDMGR
+ Layout *l = static_cast<Layout *>(thiswnd->getInterface(layoutGuid));
+ if (l)
+ {
+ for (int i = 0; i < l->getNumLockedLayouts(); i++)
+ {
+ ifc_window *wnd = l->enumLockedLayout(i);
+ addCoopWnd(wnd, 1);
+ addCooperative(wnd);
+ }
+ }
+#endif
+
+ if (recursList.searchItem(thiswnd) != -1) return ;
+
+ recursList.addItem(thiswnd);
+
+ if (Std::keyModifier(STDKEY_SHIFT)) return ;
+
+ thiswnd->getWindowRect(&thisr);
+ snapAdjustWindowRect(thiswnd, &thisr);
+
+ for (i = 0; i < desktopwnds.getNumItems(); i++)
+ {
+ ifc_window *wnd = desktopwnds.enumItem(i);
+ if (!wnd->isVisible()) continue;
+ if (hasCoopWnd(wnd)) continue;
+ if (wnd == thiswnd) continue;
+ Layout *l = (Layout*)wnd->getInterface(layoutGuid);
+ if (l && (l->getNoDock()
+#ifdef USEAPPBAR
+ || l->appbar_isDocked()
+#endif
+ )) continue;
+ wnd->getWindowRect(&r);
+ snapAdjustWindowRect(wnd, &r);
+
+#ifdef WASABI_COMPILE_WNDMGR
+ int snap = SnapPoint::match(thiswnd, NULL, wnd, KEEPSIZE, NULL, NULL, 0, 0);
+ if (forceall || snap || (touches(r, thisr) && !Wasabi::Std::rectIntersect(r, thisr)))
+ {
+#else
+ if (forceall || (touches(r, thisr) && !Std::rectIntersect(r, thisr)))
+ {
+#endif
+ addCoopWnd(wnd);
+ addCooperative(wnd);
+ }
+ }
+}
+
+bool WindowTracker::autoDock(ifc_window *thishWnd, RECT *newPosition, int mask)
+{
+ return autoDock(thishWnd, newPosition, NULL, mask);
+}
+
+bool WindowTracker::autoDock(ifc_window *thiswnd, RECT *z, RECT *_oldPosition, int mask)
+{
+ int i = 0;
+ RECT r = {0};
+#ifdef WASABI_COMPILE_CONFIG
+ extern _bool cfg_options_docking;
+ extern _int cfg_options_dockingdistance;
+
+ dockDist = cfg_options_dockingdistance;
+ dock_enabled = cfg_options_docking;
+#else
+#warning check these values
+ dockDist = 4;
+ dock_enabled = 4;
+#endif
+
+#ifdef USEAPPBAR
+ // Layout *_l = static_cast<Layout *>(thiswnd->getInterface(layoutGuid));
+ // if (_l->appbar_isDocked()) return 0;
+#endif
+
+ RECT z_snapAdjust = {0};
+ snapAdjustWindowRect(thiswnd, z, &z_snapAdjust);
+ RECT *oldPosition = _oldPosition;
+ if (oldPosition)
+ {
+ oldPosition->left += z_snapAdjust.left;
+ oldPosition->top += z_snapAdjust.top;
+ }
+
+ if (!coopWnd)
+ wascoop = 0;
+
+ disabledock = 0;
+
+ if (Std::keyModifier(STDKEY_SHIFT))
+ {
+ for (int i = 0;i < coopList.getNumItems();i++)
+ {
+ coopEntry *e = coopList.enumItem(i);
+ if (!e->locked)
+ {
+ delete e;
+ coopList.removeByPos(i);
+ coopcachewnd = NULL;
+ i--;
+ }
+ }
+ disabledock = 1;
+ }
+
+ int f = 0, s = 0;
+ int w = z->right - z->left;
+ int h = z->bottom - z->top;
+
+ POINT done = {0};
+
+ if (!disabledock)
+ {
+ ifc_window *wnd = NULL;
+ for (i = desktopwnds.getNumItems(); i > -1; i--)
+ {
+ if (i == desktopwnds.getNumItems())
+ {
+#ifdef USEAPPBAR
+ Layout *l = static_cast<Layout *>(thiswnd->getInterface(layoutGuid));
+ if (l->appbar_isDocked()) continue;
+#endif
+ Wasabi::Std::getViewport(&r, thiswnd->gethWnd());
+ wnd = NULL;
+ }
+ else
+ {
+ wnd = desktopwnds.enumItem(i);
+ if (coopWnd != NULL && hasCoopWnd(wnd)) continue;
+ Layout *l = (Layout*)wnd->getInterface(layoutGuid);
+ if (l && (l->getNoDock()
+#ifdef USEAPPBAR
+ || l->appbar_isDocked()
+#endif
+ )) continue;
+
+ if (wnd->isVisible())
+ {
+ wnd->getWindowRect(&r);
+ snapAdjustWindowRect(wnd, &r);
+ }
+ else continue;
+ }
+
+ if (coopWnd != NULL && coopWnd == wnd || (i >= 0 && hasCoopWnd(desktopwnds.enumItem(i)))) continue;
+
+ if (thiswnd == wnd) continue;
+
+ RECT oz = *z;
+ POINT thisdone = {0};
+
+#ifdef WASABI_COMPILE_WNDMGR
+ if (SnapPoint::match(thiswnd, z, wnd, mask, (int *)&thisdone.x, (int *)&thisdone.y, w, h)) s++;
+#endif
+ if (z->left > r.left - getDockDistance() && z->left < r.left + getDockDistance() && (mask & LEFT) && !thisdone.x)
+ {
+ z->left = r.left;
+ thisdone.x = 1;
+ if (mask & KEEPSIZE) z->right = r.left + w;
+ f++;
+ }
+ if (i != desktopwnds.getNumItems() && z->right > r.left - getDockDistance() && z->right < r.left + getDockDistance() && (mask & RIGHT) && !thisdone.x)
+ {
+ z->right = r.left;
+ thisdone.x = 1;
+ if (mask & KEEPSIZE) z->left = r.left - w;
+ f++;
+ }
+ if (z->top > r.top - getDockDistance() && z->top < r.top + getDockDistance() && (mask & TOP) && !thisdone.y)
+ {
+ z->top = r.top;
+ thisdone.y = 1;
+ if (mask & KEEPSIZE) z->bottom = r.top + h;
+ f++;
+ }
+ if (i != desktopwnds.getNumItems() && z->bottom > r.top - getDockDistance() && z->bottom < r.top + getDockDistance() && (mask & BOTTOM) && !thisdone.y)
+ {
+ z->bottom = r.top;
+ thisdone.y = 1;
+ if (mask & KEEPSIZE) z->top = r.top - h;
+ f++;
+ }
+ if (z->right > r.right - getDockDistance() && z->right < r.right + getDockDistance() && (mask & RIGHT) && !thisdone.x)
+ {
+ z->right = r.right;
+ thisdone.x = 1;
+ if (mask & KEEPSIZE) z->left = r.right - w;
+ f++;
+ }
+ if (i != desktopwnds.getNumItems() && z->left > r.right - getDockDistance() && z->left < r.right + getDockDistance() && (mask & LEFT) && !thisdone.x)
+ {
+ z->left = r.right;
+ thisdone.x = 1;
+ if (mask & KEEPSIZE) z->right = r.right + w;
+ f++;
+ }
+
+ if (z->bottom > r.bottom - getDockDistance() && z->bottom < r.bottom + getDockDistance() && (mask & BOTTOM) && !thisdone.y)
+ {
+ z->bottom = r.bottom;
+ thisdone.y = 1;
+ if (mask & KEEPSIZE) z->top = r.bottom - h;
+ f++;
+ }
+
+ if (i != desktopwnds.getNumItems() && z->top > r.bottom - getDockDistance() && z->top < r.bottom + getDockDistance() && (mask & TOP) && !thisdone.y)
+ {
+ z->top = r.bottom;
+ thisdone.y = 1;
+ if (mask & KEEPSIZE) z->bottom = r.bottom + h;
+ f++;
+ }
+
+ if (((wnd != NULL && (mask & NOINTERSECT) && Wasabi::Std::rectIntersect(*z, r)) || !touches(*z, r)) && !s)
+ {
+ *z = oz;
+ thisdone.x = 0;
+ thisdone.y = 0;
+ }
+
+ done.x |= thisdone.x;
+ done.y |= thisdone.y;
+ }
+ }
+
+ if (coopWnd == thiswnd && oldPosition)
+ {
+ POINT s = {0}, redock = {0};
+ TList<RECT> rlist;
+ s.x = z->left - oldPosition->left;
+ s.y = z->top - oldPosition->top;
+ for (i = 0;i < coopList.getNumItems();i++)
+ {
+ RECT r = {0};
+ ifc_window *W = coopList.enumItem(i)->wnd;
+ if (!checkWindow(W)) { coopEntry *e = coopList.enumItem(i); delete e; coopList.removeByPos(i); i--; continue; }
+ if (W != (BaseWnd*) - 1)
+ {
+ W->getWindowRect(&r);
+ //snapAdjustWindowRect(W, &r);
+ }
+#ifdef WIN32
+ else
+ GetWindowRect(WASABI_API_WND->main_getRootWnd()->gethWnd(), &r);
+#endif
+ int w = r.right - r.left, h = r.bottom - r.top;
+ r.left += s.x;
+ r.top += s.y;
+ r.right = r.left + w;
+ r.bottom = r.top + h;
+ RECT cr = r;
+ if (autoDock(W, &cr, LEFT | RIGHT | TOP | BOTTOM | NOINTERSECT | KEEPSIZE))
+ {
+ if (redock.x == 0) redock.x = cr.left - r.left;
+ if (redock.y == 0) redock.y = cr.top - r.top;
+ }
+ rlist.addItem(r);
+ }
+
+ if (redock.x || redock.y)
+ {
+ Wasabi::Std::offsetRect(z, redock.x, redock.y);
+ f++;
+ }
+#ifdef WIN32
+ HDWP hd = NULL;
+ if (coopList.getNumItems() > 0) hd = BeginDeferWindowPos(coopList.getNumItems());
+#endif
+ for (i = 0;i < coopList.getNumItems();i++)
+ {
+ RECT r = rlist.enumItem(i);
+ ifc_window *W = coopList.enumItem(i)->wnd;
+ r.left += redock.x;
+ r.top += redock.y;
+ //unsnapAdjustWindowRect(W, &r);
+#ifdef WIN32
+ W->notifyDeferredMove(r.left, r.top);
+ //if (GetWindow(W->gethWnd(), GW_OWNER))
+// SetWindowPos(W->gethWnd(), NULL, r.left, r.top, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
+// else
+ hd = DeferWindowPos(hd, W->gethWnd(), NULL, r.left, r.top, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
+#else
+ W->move( r.left, r.top );
+#endif
+ }
+ foreach(coopList)
+ ifc_window *w = coopList.getfor()->wnd;
+ if (w != coopWnd)
+ {
+ Layout *l = static_cast<Layout *>(w->getInterface(layoutGuid));
+ if (l)
+ {
+ l->beginMove();
+ }
+ }
+ endfor;
+#ifdef WIN32
+ if (coopList.getNumItems() > 0) EndDeferWindowPos(hd);
+#endif
+ foreach(coopList)
+ ifc_window *w = coopList.getfor()->wnd;
+ if (w != coopWnd)
+ {
+ Layout *l = static_cast<Layout *>(w->getInterface(layoutGuid));
+ if (l)
+ {
+ l->onMove();
+ l->endMove();
+ }
+ }
+ endfor;
+ rlist.removeAll();
+ }
+
+ z->left -= z_snapAdjust.left;
+ z->top -= z_snapAdjust.top;
+ z->right += z_snapAdjust.right;
+ z->bottom += z_snapAdjust.bottom;
+
+ return ((f + s) != 0);
+}
+
+int WindowTracker::hasCoopWnd(ifc_window *w)
+{
+ if (coopcachewnd == w) return coopcache;
+ coopcachewnd = w;
+ coopcache = 0;
+ for (int i = 0;i < coopList.getNumItems();i++)
+ if (coopList.enumItem(i)->wnd == w)
+ {
+ coopcache = 1;
+ break;
+ }
+ return coopcache;
+}
+
+void WindowTracker::addCoopWnd(ifc_window *w, int forced)
+{
+ coopList.addItem(new coopEntry(w, forced));
+ coopcachewnd = NULL;
+}
+
+void WindowTracker::flushCoopWnds()
+{
+ coopList.deleteAll();
+ coopcachewnd = NULL;
+}
+
+void WindowTracker::addRootWnd(ifc_window *wnd)
+{
+ ASSERT(!allWnd.haveItem(wnd));
+ allWnd.addItem(wnd);
+ if (!wnd->isVirtual())
+ {
+ ASSERT(!nonvirtuals.haveItem(wnd));
+ nonvirtuals.addItem(wnd);
+ }
+}
+
+void WindowTracker::removeRootWnd(ifc_window *wnd)
+{
+ allWnd.delItem(wnd);
+ if (allWnd.getNumItems() == 0) allWnd.deleteAll(); // avoid fortify fals alarm on static
+ int n = nonvirtuals.searchItem(wnd);
+ if (n > -1) nonvirtuals.removeByPos(n);
+}
+
+ifc_window *WindowTracker::rootWndFromPoint(POINT *pt)
+{
+ /* api_window *last = NULL;
+ api_window *last_parent = NULL;
+ for (int i=0;i<allWnd.getNumItems();i++) {
+ api_window *w = allWnd[i];
+ if (last && w->getRootWndParent() != last_parent)
+ return checkGhost(last, (signed short)pt->x, (signed short)pt->y);
+ if (w->pointInWnd(pt)) {
+ if (!w->getRootWndParent() || w->gethWnd() != w->getRootWndParent()->gethWnd()) return checkGhost(w, (signed short)pt->x, (signed short)pt->y);
+ last = w;
+ last_parent = w->getRootWndParent();
+ }
+ }
+ return NULL;*/
+
+ // Get window's top level window for pt
+#ifdef _WIN32
+ OSWINDOWHANDLE t = WindowFromPoint(*pt);
+ if (!t) return NULL;
+
+ //CHECK IF SAFE ! if (!rootWndFromHwnd(t)) return NULL;
+
+ // Find its rootWnd
+ for (int i = nonvirtuals.getNumItems() - 1;i >= 0;i--)
+ {
+ ifc_window *r = nonvirtuals[i];
+ if (r->gethWnd() == t)
+ {
+ POINT p = *pt;
+ r->screenToClient((int*)&p.x, (int *)&p.y);
+ return r->findRootWndChild(p.x, p.y);
+ }
+ }
+#else
+#warning port me!
+#endif
+ return NULL;
+}
+
+ifc_window *WindowTracker::rootWndFromHwnd(OSWINDOWHANDLE h)
+{
+ if (!h) return NULL;
+ // Find its rootWnd
+ for (int i = 0;i < allWnd.getNumItems();i++)
+ {
+ ifc_window *r = allWnd[i];
+ if (r->gethWnd() == h) return r;
+ }
+ return NULL;
+}
+
+int WindowTracker::wasCooperativeMove()
+{
+ return wascoop;
+}
+
+// TODO: can be moved to a static function - doesn't seem to use any class data
+void WindowTracker::snapAdjustWindowRect(ifc_window *w, RECT *r, RECT *adjustvals)
+{
+#ifdef WASABI_COMPILE_WNDMGR
+ if (w->getInterface(layoutGuid))
+ {
+ RECT snapAdjust = {0};
+ static_cast<Layout *>(w)->getSnapAdjust(&snapAdjust);
+ double rr = w->getRenderRatio();
+ if (rr != 1.0)
+ {
+ snapAdjust.left = (int)((double)(snapAdjust.left) * rr);
+ snapAdjust.top = (int)((double)(snapAdjust.top) * rr);
+ snapAdjust.right = (int)((double)(snapAdjust.right) * rr);
+ snapAdjust.bottom = (int)((double)(snapAdjust.bottom) * rr);
+ }
+ r->left += snapAdjust.left;
+ r->top += snapAdjust.top;
+ r->right -= snapAdjust.right;
+ r->bottom -= snapAdjust.bottom;
+ if (adjustvals) *adjustvals = snapAdjust;
+ }
+ else { adjustvals = NULL; }
+#else
+ if (adjustvals) MEMSET(adjustvals, 0, sizeof(RECT));
+#endif
+}
+
+void WindowTracker::unsnapAdjustWindowRect(ifc_window *w, RECT *r, RECT *adjustvals)
+{
+#ifdef WASABI_COMPILE_WNDMGR
+ if (w->getInterface(layoutGuid))
+ {
+ RECT snapAdjust = {0};
+ static_cast<Layout *>(w)->getSnapAdjust(&snapAdjust);
+ if (w->getRenderRatio() != 1.0)
+ {
+ double rr = w->getRenderRatio();
+ snapAdjust.left = (int)((double)(snapAdjust.left) * rr);
+ snapAdjust.top = (int)((double)(snapAdjust.top) * rr);
+ snapAdjust.right = (int)((double)(snapAdjust.right) * rr);
+ snapAdjust.bottom = (int)((double)(snapAdjust.bottom) * rr);
+ }
+ r->left -= snapAdjust.left;
+ r->top -= snapAdjust.top;
+ r->right += snapAdjust.right;
+ r->bottom += snapAdjust.bottom;
+ if (adjustvals) *adjustvals = snapAdjust;
+ }
+ else { adjustvals = NULL; }
+#else
+ if (adjustvals) MEMSET(adjustvals, 0, sizeof(RECT));
+#endif
+}
+
+void WindowTracker::recursAddToMoveWindows(ifc_window *wnd, redock_struct *rs, int v)
+{
+ if (!rs) return ;
+ RECT r1;
+ if (wnd != NULL)
+ {
+ wnd->getWindowRect(&r1);
+ snapAdjustWindowRect(wnd, &r1);
+ }
+ else
+ {
+ wnd = rs->l;
+ r1 = rs->original_rect;
+ if (!WASABI_API_WND->rootwndIsValid(wnd)) return ;
+ }
+
+ {
+ Layout *l = (Layout*)wnd->getInterface(layoutGuid);
+ if (l && (l->getNoDock()
+#ifdef USEAPPBAR
+ || l->appbar_isDocked()
+#endif
+ )) return ;
+ }
+
+ // add all touching windows
+ for (int i = 0; i < desktopwnds.getNumItems(); i++)
+ {
+ ifc_window *w = desktopwnds[i];
+ if (!w->isVisible()) continue;
+ if (w == wnd) continue;
+ Layout *l = (Layout*)w->getInterface(layoutGuid);
+ if (l && (l->getNoDock()
+#ifdef USEAPPBAR
+ || l->appbar_isDocked()
+#endif
+ )) continue;
+ RECT r2;
+ w->getWindowRect(&r2);
+ snapAdjustWindowRect(w, &r2);
+ // check for bottom touch
+ if ((v == 1 || v == -1) && r2.top == r1.bottom && !tomoveWindows_bottom.haveItem(w))
+ {
+ if (r2.right >= r1.left && r2.left <= r1.right)
+ {
+ tomoveWindows_bottom.addItem(w);
+ recursAddToMoveWindows(w, rs, 1);
+ }
+ }
+ // check for right touch
+ if ((v == 0 || v == -1) && r2.left == r1.right && !tomoveWindows_right.haveItem(w))
+ {
+ if (r2.bottom >= r1.top && r2.top <= r1.bottom)
+ {
+ tomoveWindows_right.addItem(w);
+ recursAddToMoveWindows(w, rs, 0);
+ }
+ }
+ // check for left touch
+ if ((v == 0 || v == -1) && r2.right == r1.left && !tomoveWindows_left.haveItem(w))
+ {
+ if (r2.bottom >= r1.top && r2.top <= r1.bottom)
+ {
+ tomoveWindows_left.addItem(w);
+ recursAddToMoveWindows(w, rs, 0);
+ }
+ }
+ // check for top touch
+ if ((v == 1 || v == -1) && r2.bottom == r1.top && !tomoveWindows_top.haveItem(w))
+ {
+ if (r2.right >= r1.left && r2.left <= r1.right)
+ {
+ tomoveWindows_top.addItem(w);
+ recursAddToMoveWindows(w, rs, 1);
+ }
+ }
+ }
+}
+
+void WindowTracker::beforeRedock(Layout *l, redock_struct *rs)
+{
+ if (!l) return ;
+ rs->l = l;
+ l->getWindowRect(&rs->original_rect);
+ snapAdjustWindowRect(rs->l, &rs->original_rect);
+}
+
+void WindowTracker::afterRedock(Layout *l, redock_struct *rs)
+{
+ RECT nr;
+ if (!rs) return ;
+
+ if (!WASABI_API_WND->rootwndIsValid(l)) return ;
+ if (!WASABI_API_WND->rootwndIsValid(rs->l)) return ;
+ recursAddToMoveWindows(NULL, rs);
+
+ l->getWindowRect(&nr);
+ snapAdjustWindowRect(l, &nr);
+
+ if (l->isUnlinked() || rs->l->isUnlinked()) return ;
+
+#ifdef WIN32
+ HDWP hdwp = BeginDeferWindowPos(desktopwnds.getNumItems());
+#endif
+
+ PtrList<Layout> toendmove;
+
+ int diff = rs->original_rect.bottom - nr.bottom;
+ if (diff)
+ { // check for bottom side dock changes
+ for (int i = 0;i < tomoveWindows_bottom.getNumItems();i++)
+ {
+ ifc_window *w = tomoveWindows_bottom[i];
+ if (w == l) continue;
+ if (w == rs->l) continue;
+ if (!allWnd.haveItem(w)) continue;
+ RECT r;
+ w->getWindowRect(&r);
+ r.top -= diff;
+ r.bottom -= diff;
+#ifdef WIN32
+ w->notifyDeferredMove(r.left, r.top);
+ DeferWindowPos(hdwp, w->gethWnd(), NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER | SWP_NOACTIVATE);
+#else
+ w->move( r.left, r.top );
+#endif
+ Layout *l = static_cast<Layout *>(w->getInterface(layoutGuid));
+ if (l) toendmove.addItem(l);
+ }
+ }
+
+ diff = rs->original_rect.top - nr.top;
+ if (diff)
+ { // check for top side dock changes
+ for (int i = 0;i < tomoveWindows_top.getNumItems();i++)
+ {
+ ifc_window *w = tomoveWindows_top[i];
+ if (w == l) continue;
+ if (w == rs->l) continue;
+ if (!allWnd.haveItem(w)) continue;
+ RECT r;
+ w->getWindowRect(&r);
+ r.top -= diff;
+ r.bottom -= diff;
+#ifdef WIN32
+ w->notifyDeferredMove(r.left, r.top);
+ DeferWindowPos(hdwp, w->gethWnd(), NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER | SWP_NOACTIVATE);
+#else
+ w->move( r.left, r.top );
+#endif
+ Layout *l = static_cast<Layout *>(w->getInterface(layoutGuid));
+ if (l) toendmove.addItem(l);
+ }
+ }
+
+ diff = rs->original_rect.right - nr.right;
+ if (diff)
+ { // check for right side dock changes
+ for (int i = 0;i < tomoveWindows_right.getNumItems();i++)
+ {
+ ifc_window *w = tomoveWindows_right[i];
+ if (w == l) continue;
+ if (w == rs->l) continue;
+ if (!allWnd.haveItem(w)) continue;
+ RECT r;
+ w->getWindowRect(&r);
+ r.left -= diff;
+ r.right -= diff;
+ Layout *l = static_cast<Layout *>(w->getInterface(layoutGuid));
+ if (l) l->beginMove();
+#ifdef WIN32
+ w->notifyDeferredMove(r.left, r.top);
+ DeferWindowPos(hdwp, w->gethWnd(), NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER | SWP_NOACTIVATE);
+#else
+ w->move( r.left, r.top );
+#endif
+ if (l) toendmove.addItem(l);
+ }
+ }
+
+ diff = rs->original_rect.left - nr.left;
+ if (diff)
+ { // check for left side dock changes
+ for (int i = 0;i < tomoveWindows_left.getNumItems();i++)
+ {
+ ifc_window *w = tomoveWindows_left[i];
+ if (w == l) continue;
+ if (w == rs->l) continue;
+ if (!allWnd.haveItem(w)) continue;
+ RECT r;
+ w->getWindowRect(&r);
+ r.left -= diff;
+ r.right -= diff;
+ Layout *l = static_cast<Layout *>(w->getInterface(layoutGuid));
+ if (l) l->beginMove();
+#ifdef WIN32
+ w->notifyDeferredMove(r.left, r.top);
+ DeferWindowPos(hdwp, w->gethWnd(), NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER | SWP_NOACTIVATE);
+#else
+ w->move( r.left, r.top );
+#endif
+ if (l) toendmove.addItem(l);
+ }
+ }
+
+#ifdef WIN32
+ EndDeferWindowPos(hdwp);
+#endif
+ tomoveWindows_left.removeAll();
+ tomoveWindows_top.removeAll();
+ tomoveWindows_right.removeAll();
+ tomoveWindows_bottom.removeAll();
+ rs->l = NULL;
+ foreach(toendmove)
+ toendmove.getfor()->onMove();
+ toendmove.getfor()->endMove();
+ endfor;
+}
+
+void WindowTracker::layoutChanged(Layout *previouswnd, Layout *newwnd)
+{
+ redock_struct rs;
+ beforeRedock(previouswnd, &rs);
+ afterRedock(newwnd, &rs);
+}
+
+ifc_window *WindowTracker::coopWnd = NULL;
+PtrList<ifc_window> WindowTracker::desktopwnds;
+PtrList<ifc_window> WindowTracker::nonvirtuals;
+PtrList<coopEntry> WindowTracker::coopList;
+PtrList<ifc_window> WindowTracker::recursList;
+PtrList<ifc_window> WindowTracker::tomoveWindows_left;
+PtrList<ifc_window> WindowTracker::tomoveWindows_top;
+PtrList<ifc_window> WindowTracker::tomoveWindows_right;
+PtrList<ifc_window> WindowTracker::tomoveWindows_bottom;
+PtrList<ifc_window> WindowTracker::allWnd;
+int WindowTracker::dockDist = DEFAULT_DOCK_DIST;
+int WindowTracker::dock_enabled = 1;
diff --git a/Src/Wasabi/api/wnd/wndtrack.h b/Src/Wasabi/api/wnd/wndtrack.h
new file mode 100644
index 00000000..f4f33d80
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndtrack.h
@@ -0,0 +1,104 @@
+#ifndef __WNDTRACK_H
+#define __WNDTRACK_H
+
+#include "cwndtrack.h"
+#include <bfc/tlist.h>
+#include <bfc/ptrlist.h>
+#include <api/wndmgr/layout.h>
+
+class ifc_window;
+
+#define WNDTRACKCB_POPUPEXIT 0x8797
+#define WNDTRACKCB_POPUPEXITALL 0x8798
+
+const int DEFAULT_DOCK_DIST=10;
+const int MIN_DOCK_DIST=1;
+const int MAX_DOCK_DIST=64;
+
+class coopEntry {
+ public:
+ coopEntry(ifc_window *w, int lock=0) : wnd(w), locked(lock) {}
+ ~coopEntry() {}
+
+ ifc_window *wnd;
+ int locked;
+};
+
+#ifndef _REDOCK_STRUCT_DEFINED
+#define _REDOCK_STRUCT_DEFINED
+typedef struct {
+ Layout *l;
+ RECT original_rect;
+} redock_struct;
+#endif
+
+class WindowTracker {
+public:
+ WindowTracker();
+ ~WindowTracker();
+
+ void addWindow(ifc_window *wnd);
+ void removeWindow(ifc_window *wnd);
+ int checkWindow(ifc_window *wnd);
+ ifc_window *enumWindows(int n);
+ int getNumWindows();
+ ifc_window *enumAllWindows(int n);
+ int getNumAllWindows();
+ bool autoDock(ifc_window *thiswnd, RECT *newPosition, int mask);
+ bool autoDock(ifc_window *thiswnd, RECT *newPosition, RECT *oldPosition, int mask);
+ static bool touches(const RECT &z, const RECT &r);
+
+ RECT findOpenRect(const RECT &prev, ifc_window *exclude=NULL);
+
+ static void setDockDistance(int dd);
+ static int getDockDistance();
+ static void setEnableDocking(int ed);
+
+ void startCooperativeMove(ifc_window *wnd);
+ void endCooperativeMove();
+ int wasCooperativeMove();
+ void invalidateAllWindows();
+ int getNumDocked();
+ ifc_window *enumDocked(int n);
+
+ static void addRootWnd(ifc_window *wnd);
+ static void removeRootWnd(ifc_window *wnd);
+ static ifc_window *rootWndFromPoint(POINT *pt);
+ static ifc_window *rootWndFromHwnd(OSWINDOWHANDLE h);
+ static void layoutChanged(Layout *previouswnd, Layout *newwnd); // re-dock windows when changing layout
+
+ static void beforeRedock(Layout *l, redock_struct *rs);
+ static void afterRedock(Layout *l, redock_struct *rs);
+ static ifc_window *getNextDesktopWindow(ifc_window *w, int next);
+ static void snapAdjustWindowRect(ifc_window *w, RECT *r, RECT *adjustvals=NULL);
+ static void unsnapAdjustWindowRect(ifc_window *w, RECT *r, RECT *adjustvals=NULL);
+
+private:
+ void addCooperative(ifc_window *thiswnd);
+ void addCoopWnd(ifc_window *w, int forced=0);
+ int hasCoopWnd(ifc_window *w);
+ void flushCoopWnds();
+ static void recursAddToMoveWindows(ifc_window *wnd, redock_struct *rs, int v=-1); // used by layoutChanged()
+
+ static PtrList<ifc_window> desktopwnds;
+ static PtrList<ifc_window> nonvirtuals;
+ static PtrList<coopEntry> coopList;
+ static PtrList<ifc_window> recursList;
+ static ifc_window *coopWnd;
+ static PtrList<ifc_window> allWnd;
+ static PtrList<ifc_window> tomoveWindows_top;
+ static PtrList<ifc_window> tomoveWindows_left;
+ static PtrList<ifc_window> tomoveWindows_bottom;
+ static PtrList<ifc_window> tomoveWindows_right;
+
+ static int dockDist;
+ static int dock_enabled;
+ int wascoop;
+ int disabledock;
+ ifc_window *coopcachewnd;
+ int coopcache;
+};
+
+extern WindowTracker *windowTracker;
+
+#endif