diff --git a/dlanguilib.dproj b/dlanguilib.dproj
index 2ee2615b..eda50e6e 100644
--- a/dlanguilib.dproj
+++ b/dlanguilib.dproj
@@ -179,6 +179,7 @@
+
diff --git a/src/dlangui/all.d b/src/dlangui/all.d
index 65550e01..4b470910 100644
--- a/src/dlangui/all.d
+++ b/src/dlangui/all.d
@@ -1,14 +1,14 @@
-module dlangui.all;
-
-public import dlangui.core.logger;
-public import dlangui.core.types;
-public import dlangui.platforms.common.platform;
-public import dlangui.graphics.images;
-public import dlangui.widgets.widget;
-public import dlangui.widgets.controls;
-public import dlangui.widgets.layouts;
-public import dlangui.widgets.lists;
-public import dlangui.widgets.tabs;
-public import dlangui.widgets.menu;
-public import dlangui.graphics.fonts;
-public import dlangui.core.i18n;
+module dlangui.all;
+
+public import dlangui.core.logger;
+public import dlangui.core.types;
+public import dlangui.platforms.common.platform;
+public import dlangui.graphics.images;
+public import dlangui.widgets.widget;
+public import dlangui.widgets.controls;
+public import dlangui.widgets.layouts;
+public import dlangui.widgets.lists;
+public import dlangui.widgets.tabs;
+public import dlangui.widgets.menu;
+public import dlangui.graphics.fonts;
+public import dlangui.core.i18n;
diff --git a/src/dlangui/core/types.d b/src/dlangui/core/types.d
index 2fa909de..37733bf3 100644
--- a/src/dlangui/core/types.d
+++ b/src/dlangui/core/types.d
@@ -1,99 +1,99 @@
-module dlangui.core.types;
-
-import std.algorithm;
-
-struct Point {
- int x;
- int y;
- this(int x0, int y0) {
- x = x0;
- y = y0;
- }
-}
-
-struct Rect {
- int left;
- int top;
- int right;
- int bottom;
- @property int middlex() { return (left + right) / 2; }
- @property int middley() { return (top + bottom) / 2; }
- void offset(int dx, int dy) {
- left += dx;
- right += dx;
- top += dy;
- bottom += dy;
- }
- /// for all fields, sets this.field to rc.field if rc.field > this.field
- void setMax(Rect rc) {
- if (left < rc.left)
- left = rc.left;
- if (right < rc.right)
- right = rc.right;
- if (top < rc.top)
- top = rc.top;
- if (bottom < rc.bottom)
- bottom = rc.bottom;
- }
- @property int width() { return right - left; }
- @property int height() { return bottom - top; }
- this(int x0, int y0, int x1, int y1) {
- left = x0;
- top = y0;
- right = x1;
- bottom = y1;
- }
- @property bool empty() {
- return right <= left || bottom <= top;
- }
- void moveBy(int deltax, int deltay) {
- left += deltax;
- right += deltax;
- top += deltay;
- bottom += deltay;
- }
- /// moves this rect to fit rc bounds, retaining the same size
- void moveToFit(ref Rect rc) {
- if (right > rc.right)
- moveBy(rc.right - right, 0);
- if (bottom > rc.bottom)
- moveBy(0, rc.bottom - bottom);
- if (left < rc.left)
- moveBy(rc.left - left, 0);
- if (top < rc.top)
- moveBy(0, rc.top - top);
-
- }
- /// updates this rect to intersection with rc, returns true if result is non empty
- bool intersect(Rect rc) {
- if (left < rc.left)
- left = rc.left;
- if (top < rc.top)
- top = rc.top;
- if (right > rc.right)
- right = rc.right;
- if (bottom > rc.bottom)
- bottom = rc.bottom;
- return right > left && bottom > top;
- }
- /// returns true if this rect has nonempty intersection with rc
- bool intersects(Rect rc) {
- if (rc.left >= right || rc.top >= bottom || rc.right <= left || rc.bottom <= top)
- return false;
- return true;
- }
- /// returns true if point is inside of this rectangle
- bool isPointInside(Point pt) {
- return pt.x >= left && pt.x < right && pt.y >= top && pt.y < bottom;
- }
- /// returns true if point is inside of this rectangle
- bool isPointInside(int x, int y) {
- return x >= left && x < right && y >= top && y < bottom;
- }
-}
-
-/// character glyph
-align(1)
+module dlangui.core.types;
+
+import std.algorithm;
+
+struct Point {
+ int x;
+ int y;
+ this(int x0, int y0) {
+ x = x0;
+ y = y0;
+ }
+}
+
+struct Rect {
+ int left;
+ int top;
+ int right;
+ int bottom;
+ @property int middlex() { return (left + right) / 2; }
+ @property int middley() { return (top + bottom) / 2; }
+ void offset(int dx, int dy) {
+ left += dx;
+ right += dx;
+ top += dy;
+ bottom += dy;
+ }
+ /// for all fields, sets this.field to rc.field if rc.field > this.field
+ void setMax(Rect rc) {
+ if (left < rc.left)
+ left = rc.left;
+ if (right < rc.right)
+ right = rc.right;
+ if (top < rc.top)
+ top = rc.top;
+ if (bottom < rc.bottom)
+ bottom = rc.bottom;
+ }
+ @property int width() { return right - left; }
+ @property int height() { return bottom - top; }
+ this(int x0, int y0, int x1, int y1) {
+ left = x0;
+ top = y0;
+ right = x1;
+ bottom = y1;
+ }
+ @property bool empty() {
+ return right <= left || bottom <= top;
+ }
+ void moveBy(int deltax, int deltay) {
+ left += deltax;
+ right += deltax;
+ top += deltay;
+ bottom += deltay;
+ }
+ /// moves this rect to fit rc bounds, retaining the same size
+ void moveToFit(ref Rect rc) {
+ if (right > rc.right)
+ moveBy(rc.right - right, 0);
+ if (bottom > rc.bottom)
+ moveBy(0, rc.bottom - bottom);
+ if (left < rc.left)
+ moveBy(rc.left - left, 0);
+ if (top < rc.top)
+ moveBy(0, rc.top - top);
+
+ }
+ /// updates this rect to intersection with rc, returns true if result is non empty
+ bool intersect(Rect rc) {
+ if (left < rc.left)
+ left = rc.left;
+ if (top < rc.top)
+ top = rc.top;
+ if (right > rc.right)
+ right = rc.right;
+ if (bottom > rc.bottom)
+ bottom = rc.bottom;
+ return right > left && bottom > top;
+ }
+ /// returns true if this rect has nonempty intersection with rc
+ bool intersects(Rect rc) {
+ if (rc.left >= right || rc.top >= bottom || rc.right <= left || rc.bottom <= top)
+ return false;
+ return true;
+ }
+ /// returns true if point is inside of this rectangle
+ bool isPointInside(Point pt) {
+ return pt.x >= left && pt.x < right && pt.y >= top && pt.y < bottom;
+ }
+ /// returns true if point is inside of this rectangle
+ bool isPointInside(int x, int y) {
+ return x >= left && x < right && y >= top && y < bottom;
+ }
+}
+
+/// character glyph
+align(1)
struct Glyph
{
version (USE_OPENGL) {
@@ -117,84 +117,84 @@ struct Glyph
///< 12: glyph data, arbitrary size
ubyte[] glyph;
}
-
-class RefCountedObject {
- protected int _refCount;
- @property int refCount() const { return _refCount; }
- void addRef() {
- _refCount++;
- }
- void releaseRef() {
- if (--_refCount == 0)
- destroy(this);
- }
- ~this() {}
-}
-
-struct Ref(T) { // if (T is RefCountedObject)
- private T _data;
- alias get this;
- @property bool isNull() const { return _data is null; }
- @property int refCount() const { return _data !is null ? _data.refCount : 0; }
- this(T data) {
- _data = data;
- if (_data !is null)
- _data.addRef();
- }
- this(this) {
- if (_data !is null)
- _data.addRef();
- }
- ref Ref opAssign(ref Ref data) {
- if (data._data == _data)
- return this;
- if (_data !is null)
- _data.releaseRef();
- _data = data._data;
- if (_data !is null)
- _data.addRef();
- return this;
- }
- ref Ref opAssign(Ref data) {
- if (data._data == _data)
- return this;
- if (_data !is null)
- _data.releaseRef();
- _data = data._data;
- if (_data !is null)
- _data.addRef();
- return this;
- }
- ref Ref opAssign(T data) {
- if (data == _data)
- return this;
- if (_data !is null)
- _data.releaseRef();
- _data = data;
- if (_data !is null)
- _data.addRef();
- return this;
- }
- void clear() {
- if (_data !is null) {
- _data.releaseRef();
- _data = null;
- }
- }
- @property T get() {
- return _data;
- }
- @property const(T) get() const {
- return _data;
- }
- ~this() {
- if (_data !is null)
- _data.releaseRef();
- }
-}
-
-
-// some utility functions
+
+class RefCountedObject {
+ protected int _refCount;
+ @property int refCount() const { return _refCount; }
+ void addRef() {
+ _refCount++;
+ }
+ void releaseRef() {
+ if (--_refCount == 0)
+ destroy(this);
+ }
+ ~this() {}
+}
+
+struct Ref(T) { // if (T is RefCountedObject)
+ private T _data;
+ alias get this;
+ @property bool isNull() const { return _data is null; }
+ @property int refCount() const { return _data !is null ? _data.refCount : 0; }
+ this(T data) {
+ _data = data;
+ if (_data !is null)
+ _data.addRef();
+ }
+ this(this) {
+ if (_data !is null)
+ _data.addRef();
+ }
+ ref Ref opAssign(ref Ref data) {
+ if (data._data == _data)
+ return this;
+ if (_data !is null)
+ _data.releaseRef();
+ _data = data._data;
+ if (_data !is null)
+ _data.addRef();
+ return this;
+ }
+ ref Ref opAssign(Ref data) {
+ if (data._data == _data)
+ return this;
+ if (_data !is null)
+ _data.releaseRef();
+ _data = data._data;
+ if (_data !is null)
+ _data.addRef();
+ return this;
+ }
+ ref Ref opAssign(T data) {
+ if (data == _data)
+ return this;
+ if (_data !is null)
+ _data.releaseRef();
+ _data = data;
+ if (_data !is null)
+ _data.addRef();
+ return this;
+ }
+ void clear() {
+ if (_data !is null) {
+ _data.releaseRef();
+ _data = null;
+ }
+ }
+ @property T get() {
+ return _data;
+ }
+ @property const(T) get() const {
+ return _data;
+ }
+ ~this() {
+ if (_data !is null)
+ _data.releaseRef();
+ }
+}
+
+
+// some utility functions
string fromStringz(const(char[]) s) {
if (s is null)
return null;
diff --git a/src/dlangui/platforms/common/platform.d b/src/dlangui/platforms/common/platform.d
index 1668aca6..19f7b9ed 100644
--- a/src/dlangui/platforms/common/platform.d
+++ b/src/dlangui/platforms/common/platform.d
@@ -220,7 +220,7 @@ class Window {
private bool checkRemoveTracking(MouseEvent event) {
import std.algorithm;
bool res = false;
- for(int i = _mouseTrackingWidgets.length - 1; i >=0; i--) {
+ for(int i = cast(int)_mouseTrackingWidgets.length - 1; i >=0; i--) {
Widget w = _mouseTrackingWidgets[i];
if (!isChild(w)) {
// std.algorithm.remove does not work for me
diff --git a/src/dlangui/widgets/menu.d b/src/dlangui/widgets/menu.d
index 45eb21d8..d3f7b4a3 100644
--- a/src/dlangui/widgets/menu.d
+++ b/src/dlangui/widgets/menu.d
@@ -1,204 +1,209 @@
-module dlangui.widgets.menu;
-
-import dlangui.core.events;
-import dlangui.widgets.controls;
-import dlangui.widgets.layouts;
-import dlangui.widgets.lists;
-import dlangui.widgets.popup;
-
-/// menu item properties
-class MenuItem {
- protected bool _checkable;
- protected bool _checked;
- protected bool _enabled;
- protected Action _action;
- protected MenuItem[] _subitems;
- /// item action id, 0 if no action
- @property int id() { return _action is null ? 0 : _action.id; }
- /// returns count of submenu items
- @property int subitemCount() {
- return cast(int)_subitems.length;
- }
- /// returns submenu item by index
- MenuItem subitem(int index) {
- return _subitems[index];
- }
- /// adds submenu item
- MenuItem add(MenuItem subitem) {
- _subitems ~= subitem;
- return this;
- }
- /// adds submenu item from action
- MenuItem add(Action subitemAction) {
- _subitems ~= new MenuItem(subitemAction);
- return this;
- }
- /// returns true if item is submenu (contains subitems)
- @property bool isSubmenu() {
- return _subitems.length > 0;
- }
- /// returns item label
- @property UIString label() {
- return _action.labelValue;
- }
- /// returns item action
- @property const(Action) action() const { return _action; }
- /// sets item action
- @property MenuItem action(Action a) { _action = a; return this; }
- this() {
- _enabled = true;
- }
- this(Action action) {
- _action = action;
- _enabled = true;
- }
- ~this() {
- // TODO
- }
-}
-
-/// widget to draw menu item
-class MenuItemWidget : HorizontalLayout {
- protected MenuItem _item;
- protected TextWidget _label;
- @property MenuItem item() { return _item; }
- this(MenuItem item) {
- id="menuitem";
- _item = item;
- styleId = "MENU_ITEM";
- _label = new TextWidget("MENU_LABEL");
- _label.text = _item.label;
- addChild(_label);
- trackHover = true;
- }
-}
-
-/// base class for menus
-class MenuWidgetBase : ListWidget {
- protected MenuWidgetBase _parentMenu;
- protected MenuItem _item;
- protected PopupMenu _openedMenu;
- protected PopupWidget _openedPopup;
- protected bool delegate(MenuItem item) _onMenuItemClickListener;
- /// menu item click listener
- @property bool delegate(MenuItem item) onMenuItemListener() { return _onMenuItemClickListener; }
- /// menu item click listener
- @property MenuWidgetBase onMenuItemListener(bool delegate(MenuItem item) listener) { _onMenuItemClickListener = listener; return this; }
-
- this(MenuWidgetBase parentMenu, MenuItem item, Orientation orientation) {
- _parentMenu = parentMenu;
- _item = item;
- this.orientation = orientation;
- id = "popup_menu";
- styleId = "POPUP_MENU";
- WidgetListAdapter adapter = new WidgetListAdapter();
- for (int i=0; i < _item.subitemCount; i++) {
- MenuItem subitem = _item.subitem(i);
- MenuItemWidget widget = new MenuItemWidget(subitem);
- if (orientation == Orientation.Horizontal)
- widget.styleId = "MAIN_MENU_ITEM";
- adapter.widgets.add(widget);
- }
- ownAdapter = adapter;
- }
-
- protected void onPopupClosed(PopupWidget p) {
- _openedPopup = null;
- _openedMenu = null;
- selectItem(-1);
- }
-
- protected void openSubmenu(MenuItemWidget itemWidget) {
- if (_openedPopup !is null) {
- _openedPopup.close();
- }
- PopupMenu popupMenu = new PopupMenu(itemWidget.item, this);
- PopupWidget popup = window.showPopup(popupMenu, itemWidget, orientation == Orientation.Horizontal ? PopupAlign.Below : PopupAlign.Right);
- popup.onPopupCloseListener = &onPopupClosed;
- popup.flags = PopupFlags.CloseOnClickOutside;
- _openedPopup = popup;
- _openedMenu = popupMenu;
- }
-
+module dlangui.widgets.menu;
+
+import dlangui.core.events;
+import dlangui.widgets.controls;
+import dlangui.widgets.layouts;
+import dlangui.widgets.lists;
+import dlangui.widgets.popup;
+
+/// menu item properties
+class MenuItem {
+ protected bool _checkable;
+ protected bool _checked;
+ protected bool _enabled;
+ protected Action _action;
+ protected MenuItem[] _subitems;
+ /// item action id, 0 if no action
+ @property int id() { return _action is null ? 0 : _action.id; }
+ /// returns count of submenu items
+ @property int subitemCount() {
+ return cast(int)_subitems.length;
+ }
+ /// returns submenu item by index
+ MenuItem subitem(int index) {
+ return _subitems[index];
+ }
+ /// adds submenu item
+ MenuItem add(MenuItem subitem) {
+ _subitems ~= subitem;
+ return this;
+ }
+ /// adds submenu item from action
+ MenuItem add(Action subitemAction) {
+ _subitems ~= new MenuItem(subitemAction);
+ return this;
+ }
+ /// returns true if item is submenu (contains subitems)
+ @property bool isSubmenu() {
+ return _subitems.length > 0;
+ }
+ /// returns item label
+ @property UIString label() {
+ return _action.labelValue;
+ }
+ /// returns item action
+ @property const(Action) action() const { return _action; }
+ /// sets item action
+ @property MenuItem action(Action a) { _action = a; return this; }
+ this() {
+ _enabled = true;
+ }
+ this(Action action) {
+ _action = action;
+ _enabled = true;
+ }
+ ~this() {
+ // TODO
+ }
+}
+
+/// widget to draw menu item
+class MenuItemWidget : HorizontalLayout {
+ protected MenuItem _item;
+ protected TextWidget _label;
+ @property MenuItem item() { return _item; }
+ this(MenuItem item) {
+ id="menuitem";
+ _item = item;
+ styleId = "MENU_ITEM";
+ _label = new TextWidget("MENU_LABEL");
+ _label.text = _item.label;
+ addChild(_label);
+ trackHover = true;
+ }
+}
+
+/// base class for menus
+class MenuWidgetBase : ListWidget {
+ protected MenuWidgetBase _parentMenu;
+ protected MenuItem _item;
+ protected PopupMenu _openedMenu;
+ protected PopupWidget _openedPopup;
+ protected bool delegate(MenuItem item) _onMenuItemClickListener;
+ /// menu item click listener
+ @property bool delegate(MenuItem item) onMenuItemListener() { return _onMenuItemClickListener; }
+ /// menu item click listener
+ @property MenuWidgetBase onMenuItemListener(bool delegate(MenuItem item) listener) { _onMenuItemClickListener = listener; return this; }
+
+ this(MenuWidgetBase parentMenu, MenuItem item, Orientation orientation) {
+ _parentMenu = parentMenu;
+ _item = item;
+ this.orientation = orientation;
+ id = "popup_menu";
+ styleId = "POPUP_MENU";
+ WidgetListAdapter adapter = new WidgetListAdapter();
+ for (int i=0; i < _item.subitemCount; i++) {
+ MenuItem subitem = _item.subitem(i);
+ MenuItemWidget widget = new MenuItemWidget(subitem);
+ if (orientation == Orientation.Horizontal)
+ widget.styleId = "MAIN_MENU_ITEM";
+ adapter.widgets.add(widget);
+ }
+ ownAdapter = adapter;
+ }
+
+ protected void onPopupClosed(PopupWidget p) {
+ _openedPopup = null;
+ _openedMenu = null;
+ selectItem(-1);
+ }
+
+ protected void openSubmenu(MenuItemWidget itemWidget) {
+ if (_openedPopup !is null) {
+ _openedPopup.close();
+ }
+ PopupMenu popupMenu = new PopupMenu(itemWidget.item, this);
+ PopupWidget popup = window.showPopup(popupMenu, itemWidget, orientation == Orientation.Horizontal ? PopupAlign.Below : PopupAlign.Right);
+ popup.onPopupCloseListener = &onPopupClosed;
+ popup.flags = PopupFlags.CloseOnClickOutside;
+ _openedPopup = popup;
+ _openedMenu = popupMenu;
+ }
+
/// override to handle change of selection
override protected void selectionChanged(int index, int previouslySelectedItem = -1) {
MenuItemWidget itemWidget = index >= 0 ? cast(MenuItemWidget)_adapter.itemWidget(index) : null;
+ MenuItemWidget prevWidget = previouslySelectedItem >= 0 ? cast(MenuItemWidget)_adapter.itemWidget(previouslySelectedItem) : null;
+ if (prevWidget !is null) {
+ if (_openedPopup !is null)
+ _openedPopup.close();
+ }
if (itemWidget !is null) {
- if (itemWidget.item.isSubmenu()) {
- if (_selectOnHover) {
- openSubmenu(itemWidget);
- }
- } else {
- // normal item
- }
- }
+ if (itemWidget.item.isSubmenu()) {
+ if (_selectOnHover) {
+ openSubmenu(itemWidget);
+ }
+ } else {
+ // normal item
+ }
+ }
}
-
- protected void onMenuItem(MenuItem item) {
- if (_openedPopup !is null) {
- _openedPopup.close();
- _openedPopup = null;
- }
- if (_parentMenu !is null)
- _parentMenu.onMenuItem(item);
- else {
- // top level handling
- Log.d("onMenuItem ", item.id);
- selectItem(-1);
- selectOnHover = false;
- bool delegate(MenuItem item) listener = _onMenuItemClickListener;
- PopupWidget popup = cast(PopupWidget)parent;
- if (popup)
- popup.close();
- // this pointer now can be invalid - if popup removed
- if (listener !is null)
- listener(item);
- }
- }
-
+
+ protected void onMenuItem(MenuItem item) {
+ if (_openedPopup !is null) {
+ _openedPopup.close();
+ _openedPopup = null;
+ }
+ if (_parentMenu !is null)
+ _parentMenu.onMenuItem(item);
+ else {
+ // top level handling
+ Log.d("onMenuItem ", item.id);
+ selectItem(-1);
+ selectOnHover = false;
+ bool delegate(MenuItem item) listener = _onMenuItemClickListener;
+ PopupWidget popup = cast(PopupWidget)parent;
+ if (popup)
+ popup.close();
+ // this pointer now can be invalid - if popup removed
+ if (listener !is null)
+ listener(item);
+ }
+ }
+
/// override to handle mouse up on item
override protected void itemClicked(int index) {
MenuItemWidget itemWidget = index >= 0 ? cast(MenuItemWidget)_adapter.itemWidget(index) : null;
if (itemWidget !is null) {
Log.d("Menu Item clicked ", itemWidget.item.action.id);
- if (itemWidget.item.isSubmenu()) {
- // submenu clicked
- if (_clickOnButtonDown && _openedPopup !is null && _openedMenu._item is itemWidget.item) {
- // second click on main menu opened item
- _openedPopup.close();
- _openedPopup = null;
- selectItem(-1);
- selectOnHover = false;
- } else {
- openSubmenu(itemWidget);
- selectOnHover = true;
- }
+ if (itemWidget.item.isSubmenu()) {
+ // submenu clicked
+ if (_clickOnButtonDown && _openedPopup !is null && _openedMenu._item is itemWidget.item) {
+ // second click on main menu opened item
+ _openedPopup.close();
+ _openedPopup = null;
+ selectItem(-1);
+ selectOnHover = false;
+ } else {
+ openSubmenu(itemWidget);
+ selectOnHover = true;
+ }
} else {
// normal item
onMenuItem(itemWidget.item);
}
}
}
-}
-
-/// main menu (horizontal)
-class MainMenu : MenuWidgetBase {
-
- this(MenuItem item) {
- super(null, item, Orientation.Horizontal);
- id = "MAIN_MENU";
- styleId = "MAIN_MENU";
- _clickOnButtonDown = true;
- }
-}
-
-/// popup menu widget (vertical layout of items)
-class PopupMenu : MenuWidgetBase {
-
- this(MenuItem item, MenuWidgetBase parentMenu = null) {
- super(parentMenu, item, Orientation.Vertical);
- id = "POPUP_MENU";
- styleId = "POPUP_MENU";
- selectOnHover = true;
- }
-}
+}
+
+/// main menu (horizontal)
+class MainMenu : MenuWidgetBase {
+
+ this(MenuItem item) {
+ super(null, item, Orientation.Horizontal);
+ id = "MAIN_MENU";
+ styleId = "MAIN_MENU";
+ _clickOnButtonDown = true;
+ }
+}
+
+/// popup menu widget (vertical layout of items)
+class PopupMenu : MenuWidgetBase {
+
+ this(MenuItem item, MenuWidgetBase parentMenu = null) {
+ super(parentMenu, item, Orientation.Vertical);
+ id = "POPUP_MENU";
+ styleId = "POPUP_MENU";
+ selectOnHover = true;
+ }
+}