mirror of https://github.com/buggins/dlangui.git
popups support
This commit is contained in:
parent
a33cf6dcec
commit
85c3dd0091
|
@ -329,6 +329,7 @@
|
|||
<File path="src\dlangui\widgets\layouts.d" />
|
||||
<File path="src\dlangui\widgets\lists.d" />
|
||||
<File path="src\dlangui\widgets\menu.d" />
|
||||
<File path="src\dlangui\widgets\popup.d" />
|
||||
<File path="src\dlangui\widgets\styles.d" />
|
||||
<File path="src\dlangui\widgets\tabs.d" />
|
||||
<File path="src\dlangui\widgets\widget.d" />
|
||||
|
|
|
@ -132,6 +132,7 @@ extern (C) int UIAppMain(string[] args) {
|
|||
window.mainWidget = (new Button()).text("sample button");
|
||||
}
|
||||
window.show();
|
||||
window.showPopup((new TextWidget()).text("POPUP"d));
|
||||
window.windowCaption = "New Window Caption";
|
||||
|
||||
// run message loop
|
||||
|
|
|
@ -2,8 +2,9 @@ module dlangui.platforms.common.platform;
|
|||
|
||||
public import dlangui.core.events;
|
||||
import dlangui.widgets.widget;
|
||||
import dlangui.widgets.popup;
|
||||
import dlangui.graphics.drawbuf;
|
||||
import std.file;
|
||||
|
||||
private import dlangui.graphics.gldrawbuf;
|
||||
|
||||
class Window {
|
||||
|
@ -26,6 +27,21 @@ class Window {
|
|||
abstract void show();
|
||||
abstract @property string windowCaption();
|
||||
abstract @property void windowCaption(string caption);
|
||||
void measure() {
|
||||
if (_mainWidget !is null) {
|
||||
_mainWidget.measure(_dx, _dy);
|
||||
}
|
||||
foreach(p; _popups)
|
||||
p.measure(_dx, _dy);
|
||||
}
|
||||
void layout() {
|
||||
Rect rc = Rect(0, 0, _dx, _dy);
|
||||
if (_mainWidget !is null) {
|
||||
_mainWidget.layout(rc);
|
||||
}
|
||||
foreach(p; _popups)
|
||||
p.layout(rc);
|
||||
}
|
||||
void onResize(int width, int height) {
|
||||
if (_dx == width && _dy == height)
|
||||
return;
|
||||
|
@ -34,16 +50,53 @@ class Window {
|
|||
if (_mainWidget !is null) {
|
||||
Log.d("onResize ", _dx, "x", _dy);
|
||||
long measureStart = currentTimeMillis;
|
||||
_mainWidget.measure(_dx, _dy);
|
||||
measure();
|
||||
long measureEnd = currentTimeMillis;
|
||||
Log.d("measure took ", measureEnd - measureStart, " ms");
|
||||
_mainWidget.layout(Rect(0, 0, _dx, _dy));
|
||||
layout();
|
||||
long layoutEnd = currentTimeMillis;
|
||||
Log.d("layout took ", layoutEnd - measureEnd, " ms");
|
||||
}
|
||||
}
|
||||
|
||||
long lastDrawTs;
|
||||
protected PopupWidget[] _popups;
|
||||
/// show new popup
|
||||
PopupWidget showPopup(Widget content) {
|
||||
PopupWidget res = new PopupWidget(content, this);
|
||||
res.anchor.widget = _mainWidget;
|
||||
_popups ~= res;
|
||||
if (_mainWidget !is null)
|
||||
_mainWidget.requestLayout();
|
||||
return res;
|
||||
}
|
||||
/// remove popup
|
||||
bool removePopup(PopupWidget popup) {
|
||||
for (int i = 0; i < _popups.length; i++) {
|
||||
PopupWidget p = _popups[i];
|
||||
if (p is popup) {
|
||||
for (int j = i; j < _popups.length - 1; j++)
|
||||
_popups[j] = _popups[j + 1];
|
||||
_popups.length--;
|
||||
destroy(p);
|
||||
// force redraw
|
||||
_mainWidget.invalidate();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// returns true if widget is child of either main widget or one of popups
|
||||
bool isChild(Widget w) {
|
||||
if (_mainWidget !is null && _mainWidget.isChild(w))
|
||||
return true;
|
||||
foreach(p; _popups)
|
||||
if (p.isChild(w))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private long lastDrawTs;
|
||||
|
||||
this() {
|
||||
_backgroundColor = 0xFFFFFF;
|
||||
|
@ -51,11 +104,16 @@ class Window {
|
|||
~this() {
|
||||
if (_mainWidget !is null) {
|
||||
destroy(_mainWidget);
|
||||
_mainWidget = null;
|
||||
_mainWidget = null;
|
||||
}
|
||||
foreach(p; _popups)
|
||||
destroy(p);
|
||||
_popups = null;
|
||||
}
|
||||
|
||||
private void animate(Widget root, long interval) {
|
||||
if (root is null)
|
||||
return;
|
||||
if (root.visibility != Visibility.Visible)
|
||||
return;
|
||||
for (int i = 0; i < root.childCount; i++)
|
||||
|
@ -64,38 +122,46 @@ class Window {
|
|||
root.animate(interval);
|
||||
}
|
||||
|
||||
private void animate(long interval) {
|
||||
animate(_mainWidget, interval);
|
||||
foreach(p; _popups)
|
||||
p.animate(interval);
|
||||
}
|
||||
|
||||
void onDraw(DrawBuf buf) {
|
||||
if (_mainWidget !is null) {
|
||||
bool needDraw = false;
|
||||
bool needLayout = false;
|
||||
bool animationActive = false;
|
||||
bool needDraw = false;
|
||||
bool needLayout = false;
|
||||
bool animationActive = false;
|
||||
checkUpdateNeeded(needDraw, needLayout, animationActive);
|
||||
if (needLayout || animationActive)
|
||||
needDraw = true;
|
||||
long ts = std.datetime.Clock.currStdTime;
|
||||
if (animationActive && lastDrawTs != 0) {
|
||||
animate(ts - lastDrawTs);
|
||||
// layout required flag could be changed during animate - check again
|
||||
checkUpdateNeeded(needDraw, needLayout, animationActive);
|
||||
if (needLayout || animationActive)
|
||||
needDraw = true;
|
||||
long ts = std.datetime.Clock.currStdTime;
|
||||
if (animationActive && lastDrawTs != 0) {
|
||||
animate(_mainWidget, ts - lastDrawTs);
|
||||
// layout required flag could be changed during animate - check again
|
||||
checkUpdateNeeded(needDraw, needLayout, animationActive);
|
||||
}
|
||||
if (needLayout) {
|
||||
long measureStart = currentTimeMillis;
|
||||
_mainWidget.measure(_dx, _dy);
|
||||
long measureEnd = currentTimeMillis;
|
||||
Log.d("measure took ", measureEnd - measureStart, " ms");
|
||||
_mainWidget.layout(Rect(0, 0, _dx, _dy));
|
||||
long layoutEnd = currentTimeMillis;
|
||||
Log.d("layout took ", layoutEnd - measureEnd, " ms");
|
||||
//checkUpdateNeeded(needDraw, needLayout, animationActive);
|
||||
}
|
||||
long drawStart = currentTimeMillis;
|
||||
_mainWidget.onDraw(buf);
|
||||
long drawEnd = currentTimeMillis;
|
||||
Log.d("draw took ", drawEnd - drawStart, " ms");
|
||||
lastDrawTs = ts;
|
||||
if (animationActive)
|
||||
scheduleAnimation();
|
||||
}
|
||||
if (needLayout) {
|
||||
long measureStart = currentTimeMillis;
|
||||
measure();
|
||||
long measureEnd = currentTimeMillis;
|
||||
Log.d("measure took ", measureEnd - measureStart, " ms");
|
||||
layout();
|
||||
long layoutEnd = currentTimeMillis;
|
||||
Log.d("layout took ", layoutEnd - measureEnd, " ms");
|
||||
//checkUpdateNeeded(needDraw, needLayout, animationActive);
|
||||
}
|
||||
long drawStart = currentTimeMillis;
|
||||
// draw main widget
|
||||
_mainWidget.onDraw(buf);
|
||||
// draw popups
|
||||
foreach(p; _popups)
|
||||
p.onDraw(buf);
|
||||
long drawEnd = currentTimeMillis;
|
||||
Log.d("draw took ", drawEnd - drawStart, " ms");
|
||||
lastDrawTs = ts;
|
||||
if (animationActive)
|
||||
scheduleAnimation();
|
||||
}
|
||||
|
||||
/// after drawing, call to schedule redraw if animation is active
|
||||
|
@ -149,7 +215,7 @@ class Window {
|
|||
bool res = false;
|
||||
for(int i = _mouseTrackingWidgets.length - 1; i >=0; i--) {
|
||||
Widget w = _mouseTrackingWidgets[i];
|
||||
if (!_mainWidget.isChild(w)) {
|
||||
if (!isChild(w)) {
|
||||
// std.algorithm.remove does not work for me
|
||||
//_mouseTrackingWidgets.remove(i);
|
||||
for (int j = i; j < _mouseTrackingWidgets.length - 1; j++)
|
||||
|
@ -197,7 +263,7 @@ class Window {
|
|||
return false;
|
||||
|
||||
// check if _mouseCaptureWidget and _mouseTrackingWidget still exist in child of root widget
|
||||
if (_mouseCaptureWidget !is null && !_mainWidget.isChild(_mouseCaptureWidget))
|
||||
if (_mouseCaptureWidget !is null && !isChild(_mouseCaptureWidget))
|
||||
_mouseCaptureWidget = null;
|
||||
|
||||
//Log.d("dispatchMouseEvent ", event.action, " (", event.x, ",", event.y, ")");
|
||||
|
@ -265,6 +331,8 @@ class Window {
|
|||
|
||||
/// checks content widgets for necessary redraw and/or layout
|
||||
protected void checkUpdateNeeded(Widget root, ref bool needDraw, ref bool needLayout, ref bool animationActive) {
|
||||
if (root is null)
|
||||
return;
|
||||
if (!root.visibility == Visibility.Visible)
|
||||
return;
|
||||
needDraw = root.needDraw || needDraw;
|
||||
|
@ -284,6 +352,8 @@ class Window {
|
|||
if (_mainWidget is null)
|
||||
return false;
|
||||
checkUpdateNeeded(_mainWidget, needDraw, needLayout, animationActive);
|
||||
foreach(p; _popups)
|
||||
checkUpdateNeeded(p, needDraw, needLayout, animationActive);
|
||||
return needDraw || needLayout || animationActive;
|
||||
}
|
||||
/// requests update for window (unless force is true, update will be performed only if layout, redraw or animation is required).
|
||||
|
@ -334,6 +404,7 @@ version (Windows) {
|
|||
|
||||
/// returns current executable path only, including last path delimiter
|
||||
string exePath() {
|
||||
import std.file;
|
||||
string path = thisExePath();
|
||||
int lastSlash = 0;
|
||||
for (int i = 0; i < path.length; i++)
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
module dlangui.widgets.popup;
|
||||
|
||||
import dlangui.widgets.widget;
|
||||
import dlangui.widgets.layouts;
|
||||
import dlangui.platforms.common.platform;
|
||||
|
||||
struct PopupAnchor {
|
||||
Widget widget;
|
||||
Align alignment;
|
||||
}
|
||||
|
||||
/// popup widget container
|
||||
class PopupWidget : LinearLayout {
|
||||
protected PopupAnchor _anchor;
|
||||
protected bool _modal;
|
||||
/// access to popup anchor
|
||||
@property ref PopupAnchor anchor() { return _anchor; }
|
||||
/// returns true if popup is modal
|
||||
bool modal() { return _modal; }
|
||||
/// set modality flag
|
||||
PopupWidget modal(bool modal) { _modal = modal; return this; }
|
||||
|
||||
/// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
|
||||
override void measure(int parentWidth, int parentHeight) {
|
||||
super.measure(parentWidth, parentHeight);
|
||||
}
|
||||
|
||||
/// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
|
||||
override void layout(Rect rc) {
|
||||
if (visibility == Visibility.Gone) {
|
||||
return;
|
||||
}
|
||||
int w = measuredWidth;
|
||||
int h = measuredHeight;
|
||||
if (w > rc.width)
|
||||
w = rc.width;
|
||||
if (h > rc.height)
|
||||
h = rc.height;
|
||||
int extraw = rc.width - w;
|
||||
int extrah = rc.height - h;
|
||||
|
||||
Rect r;
|
||||
if (anchor.widget !is null)
|
||||
r = anchor.widget.pos;
|
||||
else
|
||||
r = rc;
|
||||
r.left += extraw / 2;
|
||||
r.top += extrah / 2;
|
||||
r.right -= extraw / 2;
|
||||
r.bottom -= extrah / 2;
|
||||
super.layout(r);
|
||||
}
|
||||
|
||||
this(Widget content, Window window) {
|
||||
_window = window;
|
||||
styleId = "POPUP_MENU";
|
||||
addChild(content);
|
||||
}
|
||||
}
|
|
@ -250,6 +250,12 @@ class Widget {
|
|||
@property int width() { return _pos.width; }
|
||||
/// returns current height of widget in pixels
|
||||
@property int height() { return _pos.height; }
|
||||
/// returns widget rectangle top position
|
||||
@property int top() { return _pos.top; }
|
||||
/// returns widget rectangle left position
|
||||
@property int left() { return _pos.left; }
|
||||
/// returns widget rectangle
|
||||
@property Rect pos() { return _pos; }
|
||||
/// returns min width constraint
|
||||
@property int minWidth() { return style.minWidth; }
|
||||
/// returns max width constraint (SIZE_UNSPECIFIED if no constraint set)
|
||||
|
|
Loading…
Reference in New Issue