Implemented window resize/add scrollbars when content is too big. Temporarily works only on SDL.

This commit is contained in:
and3md 2017-06-25 14:14:03 +02:00
parent 6980a9b2e3
commit 27c8e70f5b
2 changed files with 205 additions and 16 deletions

View File

@ -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

View File

@ -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();
} }