# HG changeset patch # User Jordan Miner # Date 1249764147 18000 # Node ID c138461bf84559216a409638219322289f773f7c # Parent 3738a2d0bac3f7ed1323dba139a95956ed6a12d6 Add focusing and other changes that are related like descendantAdded/Removed events, Window.activated event, and updating List. Window.state was also added, even though focusing does not depend on it. diff -r 3738a2d0bac3 -r c138461bf845 dynamin/c/windows.d --- a/dynamin/c/windows.d Sat Aug 08 15:31:24 2009 -0500 +++ b/dynamin/c/windows.d Sat Aug 08 15:42:27 2009 -0500 @@ -271,6 +271,8 @@ BOOL ScreenToClient(HWND hWnd, POINT* lpPoint); +BOOL SetForegroundWindow(HWND hWnd); + //{{{ messages enum { WM_NULL = 0x0000, diff -r 3738a2d0bac3 -r c138461bf845 dynamin/core/list.d --- a/dynamin/core/list.d Sat Aug 08 15:31:24 2009 -0500 +++ b/dynamin/core/list.d Sat Aug 08 15:42:27 2009 -0500 @@ -37,28 +37,37 @@ // TODO: QuickSort() // TODO: HeapSort() // TODO: Sort() - calls HeapSort() so stable sort is default -// TODO: when D has template inheritance, have separate const_List and List -class List(T) { +class List(T, bool hasDelegates = false) { protected: T[] _data; uint _count; - void delegate() whenChanged; // TODO: have an index and length... + static if(hasDelegates) { + void delegate(T, int) whenAdded; + void delegate(T, int) whenRemoved; + } public: this() { - this(16, {}); + this(16); } this(uint capacity) { - this(capacity, {}); - } - this(void delegate() whenChanged) { - this(16, whenChanged); + _data = new T[capacity]; } - this(uint capacity, void delegate() whenChanged) { - _data = new T[capacity]; - this.whenChanged = whenChanged; + static if(hasDelegates) { + /// whenAdded or whenRemoved is called right after an item is added + /// or removed + this(void delegate(T, int) whenAdded, + void delegate(T, int) whenRemoved) { + this(16, whenAdded, whenRemoved); + } + this(uint capacity, void delegate(T, int) whenAdded, + void delegate(T, int) whenRemoved) { + this(capacity); + this.whenAdded = whenAdded; + this.whenRemoved = whenRemoved; + } } - static List fromArray(T[] arr...) { - List list = new List!(T)(); + static List!(T) fromArray(T[] arr...) { + auto list = new List!(T)(); list._data = arr.dup; list._count = arr.length; return list; @@ -105,43 +114,46 @@ static if(is(T == class) || is(T == interface)) _data[_count-1] = cast(T)null; --_count; - whenChanged(); + static if(hasDelegates) + whenRemoved(item, _count); return item; } void add(T item) { - insert(_count, item); + insert(item, _count); } // TODO: AddRange? void remove(T item) { uint i = find(item); if(i == -1) return; - removeRange(i); - } - void removeRange(uint index, uint length = 1) { - arrayCopy!(T)(_data, index+length, _data, index, _count - (index+length)); + + for(++i; i < _count; ++i) + _data[i-1] = _data[i]; // must null out to allow to be collected static if(is(T == class) || is(T == interface)) - for(uint i = _count-length; i < _count; ++i) - _data[i] = cast(T)null; - _count -= length; - whenChanged(); + _data[_count-1] = cast(T)null; + --_count; + + static if(hasDelegates) + whenRemoved(item, i); } - void insert(uint index, T item) { + void insert(T item, uint index) { maybeEnlarge(_count+1); arrayCopy!(T)(_data, index, _data, index+1, _count - index); _data[index] = item; ++_count; - whenChanged(); + static if(hasDelegates) + whenAdded(item, index); } // TODO: InsertRange? void clear() { - // must null out to allow to be collected - static if(is(T == class) || is(T == interface)) - for(uint i = 0; i < count; ++i) - data[i] = cast(T)null; - _count = 0; - whenChanged(); + for(; _count > 0; --_count) { + static if(hasDelegates) + whenRemoved(_data[_count-1], _count-1); + // must null out to allow to be collected + static if(is(T == class) || is(T == interface)) + data[_count-1] = cast(T)null; + } } uint find(T item) { foreach(i, item2; _data) @@ -179,12 +191,28 @@ list.add('t'); assert(list.data == "Hello, Matt"); assert(list.pop() == 't'); - list.removeRange(1, 7); - assert(list.data == "Hat"); + assert(list.data == "Hello, Mat"); + list.insert('!', 5); + assert(list.data == "Hello!, Mat"); + list.remove('l'); + assert(list.data == "Helo!, Mat"); list.clear(); assert(list.data == ""); - auto list2 = new List!(string); + + int a = 0, r = 0; + void added(string, int) { a++; }; + void removed(string, int) { r++; }; + auto list2 = new List!(string, true)(&added, &removed); + assert(a == 0 && r == 0); list2.add("hello"); + assert(a == 1 && r == 0); assert(list2.pop() == "hello"); + assert(a == 1 && r == 1); + + list2.add("Hi"); + list2.add("Jacob!"); + assert(a == 3 && r == 1); + list2.clear(); + assert(a == 3 && r == 3); } diff -r 3738a2d0bac3 -r c138461bf845 dynamin/gui/container.d --- a/dynamin/gui/container.d Sat Aug 08 15:31:24 2009 -0500 +++ b/dynamin/gui/container.d Sat Aug 08 15:42:27 2009 -0500 @@ -32,7 +32,7 @@ import dynamin.gui.events; import tango.io.Stdout; -alias List!(Control) ControlList; +alias List!(Control, true) ControlList; /// class Container : Control { @@ -44,6 +44,100 @@ override void whenResized(EventArgs e) { layout(); } + // If the specified array is large enough to hold the results, no heap + // allocation will be done. + Control[] getFocusableDescendants(Control[] des = null) { + uint cur = 0; + + void addDescendants(Container c) { + if(c._focusable) { // TODO: && c.enabled) { + if(cur == des.length) + des.length = des.length + 20; + des[cur++] = c; + } + foreach(ch; c._children) { + if(cast(Container)ch) + addDescendants(cast(Container)ch); + else if(ch.focusable) { // TODO: && ch.enabled) { + if(cur == des.length) + des.length = des.length + 20; + des[cur++] = ch; + } + } + } + addDescendants(this); + return des[0..cur]; + } + unittest { + class MyControl : Control { + this() { + _focusable = true; + } + } + auto container1 = new Container(); + auto container2 = new Container(); + auto container3 = new Container(); + auto container4 = new Container(); + container2._focusable = true; + container4._focusable = true; + auto ctrl1 = new MyControl(); + auto ctrl2 = new MyControl(); + auto ctrl3 = new MyControl(); + + container1.add(container2); + container1.add(container3); + container3.add(container4); + container2.add(ctrl1); + container4.add(ctrl2); + container4.add(ctrl3); + assert(container1.getFocusableDescendants() == + [cast(Control)container2, ctrl1, container4, ctrl2, ctrl3]); + Control[5] buf; + assert(container1.getFocusableDescendants(buf).ptr == buf.ptr); + } + + // not an event + void whenChildAdded(Control child, int) { + if(child.parent) + child.parent.remove(child); + child.parent = this; + repaint(); + + void callAdded(Control ctrl) { + scope e = new HierarchyEventArgs(ctrl); + descendantAdded(e); + + if(auto cntr = cast(Container)ctrl) { + foreach(c; cntr._children) + callAdded(c); + } + } + callAdded(child); + } + + // not an event + void whenChildRemoved(Control child, int) { + child.parent = null; + repaint(); + + scope e = new HierarchyEventArgs(child); + descendantRemoved(e); + } + + void dispatchDescendantAdded(HierarchyEventArgs e) { + descendantAdded.callHandlers(e); + descendantAdded.callMainHandler(e); + e.levels = e.levels + 1; + if(_parent) + _parent.descendantAdded(e); + } + void dispatchDescendantRemoved(HierarchyEventArgs e) { + descendantRemoved.callHandlers(e); + descendantRemoved.callMainHandler(e); + e.levels = e.levels + 1; + if(_parent) + _parent.descendantRemoved(e); + } public: /// Override this method in a subclass to handle the minSizeChanged event. protected void whenMinSizeChanged(EventArgs e) { } @@ -55,10 +149,25 @@ /// This event occurs after the control's maximum size has been changed. Event!(whenMaxSizeChanged) maxSizeChanged; + /// Override this method in a subclass to handle the descendantAdded event. + protected void whenDescendantAdded(HierarchyEventArgs e) { } + /// This event occurs after a control is added as a descendant of this container. + Event!(whenDescendantAdded) descendantAdded; + + /// Override this method in a subclass to handle the descendantRemoved event. + protected void whenDescendantRemoved(HierarchyEventArgs e) { } + /// This event occurs after a descendant of this container has been removed. + Event!(whenDescendantRemoved) descendantRemoved; + this() { minSizeChanged.mainHandler = &whenMinSizeChanged; maxSizeChanged.mainHandler = &whenMaxSizeChanged; - _children = new ControlList(); + descendantAdded.mainHandler = &whenDescendantAdded; + descendantAdded.dispatcher = &dispatchDescendantAdded; + descendantRemoved.mainHandler = &whenDescendantRemoved; + descendantRemoved.dispatcher = &dispatchDescendantRemoved; + + _children = new ControlList(&whenChildAdded, &whenChildRemoved); elasticX = true; elasticY = true; @@ -222,19 +331,11 @@ } protected void add(Control child) { - if(child.parent) - child.parent.remove(child); _children.add(child); - child.parent = this; - repaint(); - //ControlAdded(EventArgs e); // TODO: add event } protected void remove(Control child) { _children.remove(child); - child.parent = null; - repaint(); - //ControlRemoved(EventArgs e); // TODO: add event } int opApply(int delegate(inout Control item) dg) { @@ -254,6 +355,15 @@ return 0; } } +unittest { + auto i = 0; + auto container = new Panel; + container.descendantAdded += (HierarchyEventArgs e) { i++; }; + auto sub = new Panel; + sub.add(new Control); + container.add(sub); + assert(i == 2); +} // TODO: calling panel.children.add(button) will cause a crash // because the button's parent is not set to the panel diff -r 3738a2d0bac3 -r c138461bf845 dynamin/gui/control.d --- a/dynamin/gui/control.d Sat Aug 08 15:31:24 2009 -0500 +++ b/dynamin/gui/control.d Sat Aug 08 15:42:27 2009 -0500 @@ -33,6 +33,7 @@ import dynamin.gui.cursor; import tango.io.Stdout; +//{{{ hotControl Control hotControl; // the hot control is the one the mouse is over package void setHotControl(Control c) { @@ -45,11 +46,30 @@ } } package Control getHotControl() { return hotControl; } +//}}} + +//{{{ captorControl Control captorControl; package void setCaptorControl(Control c) { captorControl = c; } package Control getCaptorControl() { return captorControl; } +//}}} + +//{{{ focusedControl +Control focusedControl; +package void setFocusedControl(Control c) { + if(focusedControl is c) + return; + scope e = new EventArgs; + if(focusedControl) + focusedControl.focusLost(e); + focusedControl = c; + if(focusedControl) + focusedControl.focusGained(e); +} +package Control getFocusedControl() { return focusedControl; } +//}}} /** * The painting event is an exception to the rule that added handlers are called @@ -205,6 +225,20 @@ /// This event occurs when the control needs to be painted. Event!(whenPainting) painting; + /// Override this method in a subclass to handle the focusGained event. + protected void whenFocusGained(EventArgs e) { + repaint(); + } + /// This event occurs after this control is focused. + Event!(whenFocusGained) focusGained; + + /// Override this method in a subclass to handle the focusLost event. + protected void whenFocusLost(EventArgs e) { + repaint(); + } + /// This event occurs after this control loses focus. + Event!(whenFocusLost) focusLost; + this() { moved.mainHandler = &whenMoved; resized.mainHandler = &whenResized; @@ -229,6 +263,8 @@ keyUp.dispatcher = &dispatchKeyUp; painting.mainHandler = &whenPainting; painting.dispatcher = &dispatchPainting; + focusGained.mainHandler = &whenFocusGained; + focusLost.mainHandler = &whenFocusLost; _location = Point(0, 0); _size = Size(100, 100); @@ -277,10 +313,36 @@ } /** - * + * Returns whether or not this control can receive focus. + */ + bool focusable() { + return _focusable; + } + void focusable(bool f) { + _focusable = f; + // TODO: + } + + /** + * Returns whether this control currently has focus. A control with focus + * receives keyboard events. */ bool focused() { - return _focused; + return getFocusedControl() is this; + } + + /** + * Returns true if this control should visually show when it has focus + * and returns false if not. Focus is usually hidden until the + * user uses the keyboard to navigate. + * + * A text box is one control that shows when it is + * focused (by its caret), regardless of this value. (Because showing + * focus isn't the sole purpose of a caret.) + */ + bool showFocus() { + auto top = getTopLevel(); + return top && (cast(Window)top).showFocus; } /** @@ -307,15 +369,8 @@ auto top = getTopLevel(); if(!top) return; - if(auto win = cast(Window)top) { - if(win.focusedControl) { - win.focusedControl._focused = false; - win.focusedControl.repaint(); - } + if(auto win = cast(Window)top) win.focusedControl = this; - _focused = true; - repaint(); - } } /** diff -r 3738a2d0bac3 -r c138461bf845 dynamin/gui/events.d --- a/dynamin/gui/events.d Sat Aug 08 15:31:24 2009 -0500 +++ b/dynamin/gui/events.d Sat Aug 08 15:42:27 2009 -0500 @@ -28,6 +28,8 @@ import dynamin.all_core; import dynamin.all_painting; import dynamin.all_gui; +import dynamin.gui.control; +import dynamin.gui.container; /// enum MouseButton { @@ -162,3 +164,27 @@ dchar character() { return _ch; } } +/// +class HierarchyEventArgs : EventArgs { + int _levels = 0; + Control _control; +public: + this(Control c) { + _control = c; + } + /** + * An immediate child would be a level of 0. + */ + int levels() { return _levels; } + /// ditto + void levels(int l) { _levels = l; } + /** + * + */ + Control descendant() { return _control; } + /** + * + */ + Container ancestor() { return cast(Container)_control; } +} + diff -r 3738a2d0bac3 -r c138461bf845 dynamin/gui/list_box.d --- a/dynamin/gui/list_box.d Sat Aug 08 15:31:24 2009 -0500 +++ b/dynamin/gui/list_box.d Sat Aug 08 15:42:27 2009 -0500 @@ -38,7 +38,7 @@ */ class ListBox : Scrollable { protected: - List!(string) _items; + List!(string, true) _items; int _selectedIndex = -1; override void whenKeyDown(KeyEventArgs e) { @@ -83,7 +83,7 @@ /// This event occurs after the selection has changed. Event!(whenSelectionChanged) selectionChanged; - void listItemsChanged() { + void whenListItemsChanged(string, int) { super.layout(); repaint(); } @@ -91,7 +91,7 @@ /// this() { selectionChanged.mainHandler = &whenSelectionChanged; - _items = new List!(string)(&listItemsChanged); + _items = new List!(string, true)(&whenListItemsChanged, &whenListItemsChanged); super(); _focusable = true; @@ -99,7 +99,7 @@ backColor = WindowsTheme.getColor(5); } /// - List!(string) items() { + List!(string, true) items() { return _items; } /// diff -r 3738a2d0bac3 -r c138461bf845 dynamin/gui/notebook.d --- a/dynamin/gui/notebook.d Sat Aug 08 15:31:24 2009 -0500 +++ b/dynamin/gui/notebook.d Sat Aug 08 15:42:27 2009 -0500 @@ -68,7 +68,7 @@ */ class Notebook : Container { protected: - List!(TabPage) _tabPages; + List!(TabPage, true) _tabPages; int _selectedIndex = -1; bool _multipleLines = true; Control _content; @@ -91,7 +91,7 @@ } Theme.current.Tab_paint(selectedTabPage, this, e.graphics); } - void whenTabPagesChanged() { + void whenTabPagesChanged(TabPage page, int) { if(_tabPages.count == 0) selectedIndex = -1; else if(selectedIndex == -1) @@ -116,7 +116,7 @@ this() { selectionChanged.mainHandler = &whenSelectionChanged; - _tabPages = new List!(TabPage)(&whenTabPagesChanged); + _tabPages = new List!(TabPage, true)(&whenTabPagesChanged, &whenTabPagesChanged); _focusable = true; } override void layout() { @@ -143,7 +143,7 @@ * tabbedView.TabPages.Add(advancedPage); * ----- */ - List!(TabPage) tabPages() { return _tabPages; } + List!(TabPage, true) tabPages() { return _tabPages; } /** * Gets or sets the selected tab using its index. An index of -1 means * there is no selected tab. diff -r 3738a2d0bac3 -r c138461bf845 dynamin/gui/radio_button.d --- a/dynamin/gui/radio_button.d Sat Aug 08 15:31:24 2009 -0500 +++ b/dynamin/gui/radio_button.d Sat Aug 08 15:42:27 2009 -0500 @@ -98,6 +98,7 @@ } public: this() { + _focusable = false; } this(string text) { this(); @@ -106,6 +107,11 @@ override Size bestSize() { return Size(70, 15); } + alias CheckBox.checked checked; + override void checked(bool b) { + focusable = b; + super.checked(b); + } /** * Gets or sets what group this radio button is a part of. The default is 1. */ diff -r 3738a2d0bac3 -r c138461bf845 dynamin/gui/window.d --- a/dynamin/gui/window.d Sat Aug 08 15:31:24 2009 -0500 +++ b/dynamin/gui/window.d Sat Aug 08 15:42:27 2009 -0500 @@ -37,6 +37,7 @@ import tango.io.Stdout; import tango.core.Exception; import tango.core.Thread; +import tango.text.Util; /// static class Application { @@ -109,6 +110,26 @@ } /** + * The different states a window may be in. It may not be in more than one of + * these states at a time. + */ +enum WindowState { + /** + * Specifies that the window is neither minimized or maximized. + */ + Normal, + /** + * Specifies that the window is only visible as an icon and/or text on + * the taskbar or dock. + */ + Minimized, + /** + * Specifies that the window covers the screen in at least one direction. + */ + Maximized +} + +/** * The different types of borders that a window may have. * These do not affect whether the window is resizable-- * use Window.resizable for that. @@ -154,21 +175,107 @@ mixin WindowBackend; BorderSize _borderSize; Window _owner; + package bool _active; + package WindowState _state; WindowBorderStyle _borderStyle; bool _resizable = true; Panel _content; + bool _showFocus; + // _focusedControl might not be focused at the current time (that is + // getFocusedControl()), but will at least be focused when this + // window is active Control _focusedControl; package Control focusedControl() { return _focusedControl; } package void focusedControl(Control c) { _focusedControl = c; + if(active) + setFocusedControl(_focusedControl); } override void dispatchPainting(PaintingEventArgs e) { Theme.current.Window_paint(this, e.graphics); super.dispatchPainting(e); } + override void whenDescendantAdded(HierarchyEventArgs e) { + super.whenDescendantAdded(e); + if(focusedControl is null && e.descendant.focusable) { + // && e.descendant.enabled) { + focusedControl = e.descendant; + } + } + + //{{{ focusing + public override bool showFocus() { return _showFocus; } + override void whenKeyDown(KeyEventArgs e) { + if(e.key == Key.Tab) { + getNextFocusable().focus(); + _showFocus = true; + } + } + + // will not return null + Control getNextFocusable() { + Control foc = focusedControl; + + Control[32] buffer; + auto des = getFocusableDescendants(buffer); + if(des.length == 0) + return this; + else if(des.length == 1) + return des[0]; + + int focI = locate(des, foc); + + // look _after_ this control for one with the same tab index + foreach(c; des[focI+1..$]) + if(c.tabIndex == foc.tabIndex) + return c; + + // if none are found, look for the next largest tab index + // from the beginning of the array + Control smallest; + Control nextLargest; + foreach(c; des) { + if(c.tabIndex > foc.tabIndex) + if(nextLargest is null || c.tabIndex < nextLargest.tabIndex) + nextLargest = c; + if(smallest is null || c.tabIndex < smallest.tabIndex) + smallest = c; + } + + if(nextLargest) + return nextLargest; + else + return smallest; + } + + // will not return null + Control getPreviousFocusable() { + return null; + } + //}}} + public: + /// Override this method in a subclass to handle the activated event. + protected void whenActivated(EventArgs e) { + setFocusedControl(_focusedControl is null ? content : _focusedControl); + } + /// This event occurs after this window is activated. + Event!(whenActivated) activated; + + /// Override this method in a subclass to handle the deactivated event. + protected void whenDeactivated(EventArgs e) { + setFocusedControl(null); + } + /// This event occurs after this window is deactivated. + Event!(whenDeactivated) deactivated; + + /** + * + */ this() { - _children = new ControlList(); + activated.mainHandler = &whenActivated; + deactivated.mainHandler = &whenDeactivated; + content = new Panel; _visible = false; @@ -183,6 +290,13 @@ this.text = text; } + /** + * + */ + Panel content() { + return _content; + } + /// ditto void content(Panel panel) { if(panel is null) throw new IllegalArgumentException("content must not be null"); @@ -228,9 +342,6 @@ _content.size = _size-_borderSize; ignoreResize = false; } - Panel content() { - return _content; - } /** * If the handle has not yet been created, calling this will cause it to be. @@ -293,6 +404,32 @@ } /** + * + */ + bool active() { return _active; } + /** + * + */ + void activate() { + if(!handleCreated) + return; + backend_activate(); + } + + /** + * Gets or sets whether the window's state is normal, minimized, or + * maximized. + */ + WindowState state() { return _state; } + /// ditto + void state(WindowState s) { + _state = s; + if(!handleCreated) + return; + backend_state = s; + } + + /** * Gets or sets what border this window will have around its contents. * The default is WindowBorderStyle.Normal. */ diff -r 3738a2d0bac3 -r c138461bf845 dynamin/gui/windows_theme.d --- a/dynamin/gui/windows_theme.d Sat Aug 08 15:31:24 2009 -0500 +++ b/dynamin/gui/windows_theme.d Sat Aug 08 15:42:27 2009 -0500 @@ -216,7 +216,7 @@ auto uxState = findUxState(c, PBS_DISABLED, PBS_NORMAL, PBS_HOT, PBS_PRESSED); Ux.drawBackground(g, Rect(0, 0, c.width, c.height), "BUTTON", BP_PUSHBUTTON, uxState); - if(c.focused) + if(c.focused && c.showFocus) drawFocus(g, COLOR_WINDOWTEXT, 3.5, 3.5, c.width-7, c.height-7); g.source = getColor(COLOR_WINDOWTEXT); c.paintFore(g); @@ -236,7 +236,7 @@ draw3dRectangle(g, 1, 1, c.width-2, c.height-2, getColor(COLOR_3DLIGHT), getColor(COLOR_3DSHADOW)); } - if(c.focused) + if(c.focused && c.showFocus) drawFocus(g, COLOR_WINDOWTEXT, 3.5, 3.5, c.width-7, c.height-7); g.source = getColor(COLOR_WINDOWTEXT); c.paintFore(g); @@ -255,7 +255,7 @@ } Ux.drawBackground(g, Rect(0, 0, 13, c.height), "BUTTON", BP_CHECKBOX, uxState); - if(c.focused) + if(c.focused && c.showFocus) drawFocus(g, COLOR_WINDOWTEXT, 15.5, 0.5, c.width-16, c.height-1); g.source = getColor(COLOR_WINDOWTEXT); @@ -281,7 +281,7 @@ drawCheck(g, 3, 3); // drawCheck(g, 0, 0, 13, 13); - if(c.focused) + if(c.focused && c.showFocus) drawFocus(g, COLOR_WINDOWTEXT, 15.5, 0.5, c.width-16, c.height-1); g.source = getColor(COLOR_WINDOWTEXT); g.translate(16, 0); @@ -301,7 +301,7 @@ } Ux.drawBackground(g, Rect(0, 0, 13, c.height), "BUTTON", BP_RADIOBUTTON, uxState); - if(c.focused) + if(c.focused && c.showFocus) drawFocus(g, COLOR_WINDOWTEXT, 15.5, 0.5, c.width-16, c.height-1); g.source = getColor(COLOR_WINDOWTEXT); @@ -361,7 +361,7 @@ g.translate(-4, -4); } - if(c.focused) + if(c.focused && c.showFocus) drawFocus(g, COLOR_WINDOWTEXT, 15.5, 0.5, c.width-16, c.height-1); g.source = getColor(COLOR_WINDOWTEXT); g.translate(16, 0); diff -r 3738a2d0bac3 -r c138461bf845 dynamin/gui/windows_window.d --- a/dynamin/gui/windows_window.d Sat Aug 08 15:31:24 2009 -0500 +++ b/dynamin/gui/windows_window.d Sat Aug 08 15:42:27 2009 -0500 @@ -191,8 +191,26 @@ return g; } void backend_visible(bool b) { - //if not created, create the handle by calling Handle() - ShowWindow(handle, b ? SW_SHOW : SW_HIDE); + if(b) + // visible has been set to true by now...use state() to show window + backend_state = _state; + else + //if not created, create the handle by calling handle() + ShowWindow(handle, SW_HIDE); + } + void backend_state(WindowState s) { + if(!visible) + return; + //if not created, create the handle by calling handle() + if(s == WindowState.Normal) + ShowWindow(handle, SW_RESTORE); + else if(s == WindowState.Minimized) + ShowWindow(handle, SW_MINIMIZE); + else if(s == WindowState.Maximized) + ShowWindow(handle, SW_MAXIMIZE); + } + void backend_activate() { + SetForegroundWindow(_handle); } void backend_borderStyle(WindowBorderStyle border) { backend_updateWindowStyles(); @@ -657,8 +675,14 @@ c.moved(args); return 0; case WM_SIZE: - if(wParam == SIZE_MINIMIZED) - break; + if(wParam == SIZE_RESTORED) + c._state = WindowState.Normal; + else if(wParam == SIZE_MINIMIZED) { + c._state = WindowState.Minimized; + break; // don't update size if minimized (would be wierd size) + } else if(wParam == SIZE_MAXIMIZED) + c._state = WindowState.Maximized; + RECT rect; GetWindowRect(hwnd, &rect); c._size = Size(rect.right-rect.left, rect.bottom-rect.top); @@ -666,6 +690,16 @@ scope args = new EventArgs(); c.resized(args); return 0; + case WM_ACTIVATE: + scope e = new EventArgs; + if(LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) { + c._active = true; + c.activated(e); + } else if(LOWORD(wParam) == WA_INACTIVE) { + c._active = false; + c.deactivated(e); + } + return 0; case WM_MOUSEMOVE: if(!trackingMouseLeave) { TRACKMOUSEEVENT tme;