mirror of https://github.com/buggins/dlangui.git
Implemented window resize/add scrollbars when content is too big. Temporarily works only on SDL.
This commit is contained in:
parent
6980a9b2e3
commit
27c8e70f5b
|
@ -24,6 +24,7 @@ public import dlangui.core.events;
|
||||||
import dlangui.core.collections;
|
import dlangui.core.collections;
|
||||||
import dlangui.widgets.widget;
|
import dlangui.widgets.widget;
|
||||||
import dlangui.widgets.popup;
|
import dlangui.widgets.popup;
|
||||||
|
import dlangui.widgets.scrollbar;
|
||||||
import dlangui.graphics.drawbuf;
|
import dlangui.graphics.drawbuf;
|
||||||
import dlangui.core.stdaction;
|
import dlangui.core.stdaction;
|
||||||
import dlangui.core.asyncsocket;
|
import dlangui.core.asyncsocket;
|
||||||
|
@ -91,6 +92,16 @@ enum DialogDisplayMode : ulong {
|
||||||
allTypesOfDialogsInPopup = fileDialogInPopup | messageBoxInPopup | inputBoxInPopup | settingsDialogInPopup | userDialogInPopup
|
allTypesOfDialogsInPopup = fileDialogInPopup | messageBoxInPopup | inputBoxInPopup | settingsDialogInPopup | userDialogInPopup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets what's should be done when window content is too big
|
||||||
|
enum WindowOrContentResizeMode {
|
||||||
|
/// widgets are shrink to fit in window
|
||||||
|
shrinkWidgets,
|
||||||
|
/// resize window when window is too small
|
||||||
|
resizeWindow,
|
||||||
|
/// add scrollbars to window
|
||||||
|
scrollWindow
|
||||||
|
}
|
||||||
|
|
||||||
/// Window state signal listener
|
/// Window state signal listener
|
||||||
interface OnWindowStateHandler {
|
interface OnWindowStateHandler {
|
||||||
/// signal listener - called when state of window is changed
|
/// signal listener - called when state of window is changed
|
||||||
|
@ -213,6 +224,15 @@ class Window : CustomEventTarget {
|
||||||
protected Widget _mainWidget;
|
protected Widget _mainWidget;
|
||||||
protected EventList _eventList;
|
protected EventList _eventList;
|
||||||
protected uint _flags;
|
protected uint _flags;
|
||||||
|
/// minimal good looking content width
|
||||||
|
protected int _minContentWidth;
|
||||||
|
/// minimal good looking content height
|
||||||
|
protected int _minContentHeight;
|
||||||
|
|
||||||
|
// current content width calculated using _windowOrContentResizeMode flag, usually used in measure()
|
||||||
|
protected int _currentContentWidth;
|
||||||
|
// current content height calculated using _windowOrContentResizeMode flag, usually used in measure()
|
||||||
|
protected int _currentContentHeight;
|
||||||
|
|
||||||
@property uint flags() { return _flags; }
|
@property uint flags() { return _flags; }
|
||||||
@property uint backgroundColor() const { return _backgroundColor; }
|
@property uint backgroundColor() const { return _backgroundColor; }
|
||||||
|
@ -241,7 +261,21 @@ class Window : CustomEventTarget {
|
||||||
@property void caretReplace(bool flg) { _caretReplace = flg; }
|
@property void caretReplace(bool flg) { _caretReplace = flg; }
|
||||||
@property bool caretReplace() { return _caretReplace; }
|
@property bool caretReplace() { return _caretReplace; }
|
||||||
|
|
||||||
// Abstract methods : override in platform implementatino
|
// window content resize mode
|
||||||
|
//protected WindowOrContentResizeMode _windowOrContentResizeMode = WindowOrContentResizeMode.resizeWindow;
|
||||||
|
//protected WindowOrContentResizeMode _windowOrContentResizeMode = WindowOrContentResizeMode.shrinkWidgets;
|
||||||
|
protected WindowOrContentResizeMode _windowOrContentResizeMode = WindowOrContentResizeMode.scrollWindow;
|
||||||
|
|
||||||
|
@property WindowOrContentResizeMode windowOrContentResizeMode() {return _windowOrContentResizeMode; }
|
||||||
|
@property void windowOrContentResizeMode(WindowOrContentResizeMode newMode) {
|
||||||
|
_windowOrContentResizeMode = newMode;
|
||||||
|
if (_mainWidget) {
|
||||||
|
_mainWidget.measure(SIZE_UNSPECIFIED, SIZE_UNSPECIFIED);
|
||||||
|
adjustWindowOrContentSize(_mainWidget.measuredWidth, _mainWidget.measuredHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abstract methods : override in platform implementation
|
||||||
|
|
||||||
/// show window
|
/// show window
|
||||||
abstract void show();
|
abstract void show();
|
||||||
|
@ -304,26 +338,142 @@ class Window : CustomEventTarget {
|
||||||
/// set window rectangle
|
/// set window rectangle
|
||||||
bool moveAndResizeWindow(Rect rc, bool activate = false) { return setWindowState(WindowState.unspecified, activate, rc); }
|
bool moveAndResizeWindow(Rect rc, bool activate = false) { return setWindowState(WindowState.unspecified, activate, rc); }
|
||||||
|
|
||||||
|
// things needed for WindowOrContentResizeMode.scrollWindow:
|
||||||
|
/// vertical scrollbar control
|
||||||
|
protected ScrollBar _vScrollBar = null;
|
||||||
|
/// horizontal scrollbar control
|
||||||
|
protected ScrollBar _hScrollBar = null;
|
||||||
|
|
||||||
|
/// Sets the minimal content size and adjust window or content should be called from window show
|
||||||
|
void adjustWindowOrContentSize(int minContentWidth, int minContentHeight) {
|
||||||
|
_minContentWidth = minContentWidth;
|
||||||
|
_minContentHeight = minContentHeight;
|
||||||
|
if (_windowOrContentResizeMode == WindowOrContentResizeMode.resizeWindow)
|
||||||
|
resizeWindow(Point(minContentWidth, minContentHeight));
|
||||||
|
updateWindowOrContentSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// update current content size based on windowOrContentResizeMode flag, usually used when window is resized
|
||||||
|
void updateWindowOrContentSize() {
|
||||||
|
final switch (_windowOrContentResizeMode) {
|
||||||
|
case WindowOrContentResizeMode.shrinkWidgets: {
|
||||||
|
_currentContentWidth = _windowRect.right;
|
||||||
|
_currentContentHeight = _windowRect.bottom;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case WindowOrContentResizeMode.resizeWindow: {
|
||||||
|
//maybe should not permit to resize when new window size is smaller than content size, now do nothing
|
||||||
|
_currentContentWidth = _windowRect.right;
|
||||||
|
_currentContentHeight = _windowRect.bottom;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WindowOrContentResizeMode.scrollWindow: {
|
||||||
|
if (_windowRect.right < _minContentWidth) {
|
||||||
|
// create scrollbar
|
||||||
|
_currentContentWidth = _minContentWidth;
|
||||||
|
if (!_hScrollBar) {
|
||||||
|
_hScrollBar = new ScrollBar(null,Orientation.Horizontal);
|
||||||
|
_hScrollBar.scrollEvent = delegate bool (AbstractSlider source, ScrollEvent event) {
|
||||||
|
if (event.action == ScrollAction.SliderMoved || event.action == ScrollAction.SliderReleased)
|
||||||
|
requestLayout();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_hScrollBar.measure(_windowRect.right, _windowRect.bottom);
|
||||||
|
if (windowRect().bottom < _minContentHeight)
|
||||||
|
_hScrollBar.setRange(0, _minContentWidth + _hScrollBar.measuredHeight);
|
||||||
|
else
|
||||||
|
_hScrollBar.setRange(0, _minContentWidth);
|
||||||
|
_hScrollBar.pageSize(_windowRect.right);
|
||||||
|
_hScrollBar.position(0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (_hScrollBar) {
|
||||||
|
destroy(_hScrollBar);
|
||||||
|
_hScrollBar = null;
|
||||||
|
}
|
||||||
|
_currentContentWidth = _windowRect.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (windowRect().bottom < _minContentHeight) {
|
||||||
|
// create scrollbar
|
||||||
|
_currentContentHeight = _minContentHeight;
|
||||||
|
if (!_vScrollBar) {
|
||||||
|
_vScrollBar = new ScrollBar(null,Orientation.Vertical);
|
||||||
|
_vScrollBar.scrollEvent = delegate bool (AbstractSlider source, ScrollEvent event) {
|
||||||
|
if (event.action == ScrollAction.SliderMoved || event.action == ScrollAction.SliderReleased)
|
||||||
|
requestLayout();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_vScrollBar.measure(_windowRect.right, _windowRect.bottom);
|
||||||
|
if (_hScrollBar)
|
||||||
|
_vScrollBar.setRange(0, _minContentHeight+_hScrollBar.measuredHeight);
|
||||||
|
else
|
||||||
|
_vScrollBar.setRange(0, _minContentHeight);
|
||||||
|
_vScrollBar.pageSize(windowRect().bottom);
|
||||||
|
_vScrollBar.position(0);
|
||||||
|
|
||||||
|
if (!_hScrollBar)
|
||||||
|
_currentContentWidth = _windowRect.right - _vScrollBar.measuredWidth;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (_vScrollBar) {
|
||||||
|
destroy(_vScrollBar);
|
||||||
|
_vScrollBar = null;
|
||||||
|
}
|
||||||
|
_currentContentHeight = _hScrollBar ? _windowRect.bottom - _hScrollBar.measuredHeight : _windowRect.bottom;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// requests layout for main widget and popups
|
/// requests layout for main widget and popups
|
||||||
void requestLayout() {
|
void requestLayout() {
|
||||||
if (_mainWidget)
|
if (_mainWidget)
|
||||||
_mainWidget.requestLayout();
|
_mainWidget.requestLayout();
|
||||||
|
if (_hScrollBar)
|
||||||
|
_hScrollBar.requestLayout();
|
||||||
|
if (_vScrollBar)
|
||||||
|
_vScrollBar.requestLayout();
|
||||||
foreach(p; _popups)
|
foreach(p; _popups)
|
||||||
p.requestLayout();
|
p.requestLayout();
|
||||||
if (_tooltip.popup)
|
if (_tooltip.popup)
|
||||||
_tooltip.popup.requestLayout();
|
_tooltip.popup.requestLayout();
|
||||||
}
|
}
|
||||||
void measure() {
|
void measure() {
|
||||||
|
if (_hScrollBar)
|
||||||
|
_hScrollBar.measure(_dx, _dy);
|
||||||
|
|
||||||
|
if (_vScrollBar)
|
||||||
|
_vScrollBar.measure(_dx, _dy);
|
||||||
|
|
||||||
if (_mainWidget !is null) {
|
if (_mainWidget !is null) {
|
||||||
_mainWidget.measure(_dx, _dy);
|
_mainWidget.measure(_currentContentWidth, _currentContentHeight);
|
||||||
}
|
}
|
||||||
foreach(p; _popups)
|
foreach(p; _popups)
|
||||||
p.measure(_dx, _dy);
|
p.measure(_currentContentWidth, _currentContentHeight);
|
||||||
if (_tooltip.popup)
|
if (_tooltip.popup)
|
||||||
_tooltip.popup.measure(_dx, _dy);
|
_tooltip.popup.measure(_currentContentWidth, _currentContentHeight);
|
||||||
}
|
}
|
||||||
void layout() {
|
void layout() {
|
||||||
Rect rc = Rect(0, 0, _dx, _dy);
|
if (_hScrollBar)
|
||||||
|
_hScrollBar.layout(Rect(0, _dy - _hScrollBar.measuredHeight, _vScrollBar ? _dx - _vScrollBar.measuredWidth : _dx, _dy));
|
||||||
|
|
||||||
|
if (_vScrollBar)
|
||||||
|
_vScrollBar.layout(Rect(_dx - _vScrollBar.measuredWidth, 0, _dx, _hScrollBar ? _dy - _hScrollBar.measuredHeight : _dy));
|
||||||
|
|
||||||
|
int deltaX = 0;
|
||||||
|
if (_hScrollBar)
|
||||||
|
deltaX = -_hScrollBar.position;
|
||||||
|
|
||||||
|
int deltaY = 0;
|
||||||
|
if (_vScrollBar)
|
||||||
|
deltaY = -_vScrollBar.position;
|
||||||
|
|
||||||
|
Rect rc = Rect(deltaX, deltaY, _currentContentWidth + deltaX, _currentContentHeight + deltaY);
|
||||||
if (_mainWidget !is null) {
|
if (_mainWidget !is null) {
|
||||||
_mainWidget.layout(rc);
|
_mainWidget.layout(rc);
|
||||||
}
|
}
|
||||||
|
@ -337,9 +487,13 @@ class Window : CustomEventTarget {
|
||||||
return;
|
return;
|
||||||
_dx = width;
|
_dx = width;
|
||||||
_dy = height;
|
_dy = height;
|
||||||
|
// fix window rect for platforms that don't set it yet
|
||||||
|
_windowRect.right = width;
|
||||||
|
_windowRect.bottom = height;
|
||||||
if (_mainWidget !is null) {
|
if (_mainWidget !is null) {
|
||||||
Log.d("onResize ", _dx, "x", _dy);
|
Log.d("onResize ", _dx, "x", _dy);
|
||||||
long measureStart = currentTimeMillis;
|
long measureStart = currentTimeMillis;
|
||||||
|
updateWindowOrContentSize();
|
||||||
measure();
|
measure();
|
||||||
//Log.d("measured size: ", _mainWidget.measuredWidth, "x", _mainWidget.measuredHeight);
|
//Log.d("measured size: ", _mainWidget.measuredWidth, "x", _mainWidget.measuredHeight);
|
||||||
long measureEnd = currentTimeMillis;
|
long measureEnd = currentTimeMillis;
|
||||||
|
@ -496,7 +650,7 @@ class Window : CustomEventTarget {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns true if widget is child of either main widget or one of popups
|
/// returns true if widget is child of either main widget, one of popups or window scrollbar
|
||||||
bool isChild(Widget w) {
|
bool isChild(Widget w) {
|
||||||
if (_mainWidget !is null && _mainWidget.isChild(w))
|
if (_mainWidget !is null && _mainWidget.isChild(w))
|
||||||
return true;
|
return true;
|
||||||
|
@ -506,6 +660,10 @@ class Window : CustomEventTarget {
|
||||||
if (_tooltip.popup)
|
if (_tooltip.popup)
|
||||||
if (_tooltip.popup.isChild(w))
|
if (_tooltip.popup.isChild(w))
|
||||||
return true;
|
return true;
|
||||||
|
if (_hScrollBar !is null && _hScrollBar.isChild(w))
|
||||||
|
return true;
|
||||||
|
if (_vScrollBar !is null && _vScrollBar.isChild(w))
|
||||||
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,6 +691,14 @@ class Window : CustomEventTarget {
|
||||||
destroy(_mainWidget);
|
destroy(_mainWidget);
|
||||||
_mainWidget = null;
|
_mainWidget = null;
|
||||||
}
|
}
|
||||||
|
if (_hScrollBar) {
|
||||||
|
destroy(_hScrollBar);
|
||||||
|
_hScrollBar = null;
|
||||||
|
}
|
||||||
|
if (_vScrollBar) {
|
||||||
|
destroy(_vScrollBar);
|
||||||
|
_vScrollBar = null;
|
||||||
|
}
|
||||||
destroy(_eventList);
|
destroy(_eventList);
|
||||||
destroy(_timerQueue);
|
destroy(_timerQueue);
|
||||||
_eventList = null;
|
_eventList = null;
|
||||||
|
@ -627,6 +793,13 @@ class Window : CustomEventTarget {
|
||||||
if (_tooltip.popup)
|
if (_tooltip.popup)
|
||||||
_tooltip.popup.onDraw(buf);
|
_tooltip.popup.onDraw(buf);
|
||||||
|
|
||||||
|
if (_hScrollBar)
|
||||||
|
_hScrollBar.onDraw(buf);
|
||||||
|
if (_vScrollBar)
|
||||||
|
_vScrollBar.onDraw(buf);
|
||||||
|
if (_hScrollBar && _vScrollBar)
|
||||||
|
buf.fillRect(Rect(_vScrollBar.left, _hScrollBar.top, buf.width, buf.height), _backgroundColor);
|
||||||
|
|
||||||
long drawEnd = currentTimeMillis;
|
long drawEnd = currentTimeMillis;
|
||||||
debug(DebugRedraw) {
|
debug(DebugRedraw) {
|
||||||
if (drawEnd - drawStart > PERFORMANCE_LOGGING_THRESHOLD_MS)
|
if (drawEnd - drawStart > PERFORMANCE_LOGGING_THRESHOLD_MS)
|
||||||
|
@ -1128,11 +1301,24 @@ class Window : CustomEventTarget {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!modal)
|
if (!modal) {
|
||||||
|
res = false;
|
||||||
|
if (_hScrollBar)
|
||||||
|
res = dispatchMouseEvent(_hScrollBar, event, cursorIsSet);
|
||||||
|
if (!res && _vScrollBar)
|
||||||
|
res = dispatchMouseEvent(_vScrollBar, event, cursorIsSet);
|
||||||
|
if (!res)
|
||||||
res = dispatchMouseEvent(_mainWidget, event, cursorIsSet);
|
res = dispatchMouseEvent(_mainWidget, event, cursorIsSet);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
|
if (_hScrollBar)
|
||||||
|
res = dispatchMouseEvent(_hScrollBar, event, cursorIsSet);
|
||||||
|
if (!res && _vScrollBar)
|
||||||
|
res = dispatchMouseEvent(_vScrollBar, event, cursorIsSet);
|
||||||
|
if (!res)
|
||||||
res = dispatchMouseEvent(modal, event, cursorIsSet);
|
res = dispatchMouseEvent(modal, event, cursorIsSet);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return res || processed || _mainWidget.needDraw;
|
return res || processed || _mainWidget.needDraw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1184,6 +1370,10 @@ class Window : CustomEventTarget {
|
||||||
if (_mainWidget is null)
|
if (_mainWidget is null)
|
||||||
return false;
|
return false;
|
||||||
checkUpdateNeeded(_mainWidget, needDraw, needLayout, animationActive);
|
checkUpdateNeeded(_mainWidget, needDraw, needLayout, animationActive);
|
||||||
|
if (_hScrollBar)
|
||||||
|
checkUpdateNeeded(_hScrollBar, needDraw, needLayout, animationActive);
|
||||||
|
if (_vScrollBar)
|
||||||
|
checkUpdateNeeded(_vScrollBar, needDraw, needLayout, animationActive);
|
||||||
foreach(p; _popups)
|
foreach(p; _popups)
|
||||||
checkUpdateNeeded(p, needDraw, needLayout, animationActive);
|
checkUpdateNeeded(p, needDraw, needLayout, animationActive);
|
||||||
if (_tooltip.popup)
|
if (_tooltip.popup)
|
||||||
|
@ -1574,7 +1764,7 @@ class Platform {
|
||||||
}
|
}
|
||||||
|
|
||||||
static if (ENABLE_OPENGL) {
|
static if (ENABLE_OPENGL) {
|
||||||
private __gshared bool _OPENGL_ENABLED = true;
|
private __gshared bool _OPENGL_ENABLED = false;
|
||||||
/// check if hardware acceleration is enabled
|
/// check if hardware acceleration is enabled
|
||||||
@property bool openglEnabled() { return _OPENGL_ENABLED; }
|
@property bool openglEnabled() { return _OPENGL_ENABLED; }
|
||||||
/// call on app initialization if OpenGL support is detected
|
/// call on app initialization if OpenGL support is detected
|
||||||
|
|
|
@ -350,16 +350,15 @@ class SDLWindow : Window {
|
||||||
Log.e("Window is shown without main widget");
|
Log.e("Window is shown without main widget");
|
||||||
_mainWidget = new Widget();
|
_mainWidget = new Widget();
|
||||||
}
|
}
|
||||||
if (_mainWidget && !(_flags & WindowFlag.Resizable)) {
|
if (_mainWidget) {
|
||||||
_mainWidget.measure(SIZE_UNSPECIFIED, SIZE_UNSPECIFIED);
|
_mainWidget.measure(SIZE_UNSPECIFIED, SIZE_UNSPECIFIED);
|
||||||
SDL_SetWindowSize(_win, _mainWidget.measuredWidth, _mainWidget.measuredHeight);
|
adjustWindowOrContentSize(_mainWidget.measuredWidth, _mainWidget.measuredHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_ShowWindow(_win);
|
SDL_ShowWindow(_win);
|
||||||
if (_mainWidget)
|
if (_mainWidget)
|
||||||
_mainWidget.setFocus();
|
_mainWidget.setFocus();
|
||||||
fixSize();
|
fixSize();
|
||||||
//update(true);
|
|
||||||
//redraw();
|
|
||||||
SDL_RaiseWindow(_win);
|
SDL_RaiseWindow(_win);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue