actions state requests, part 2

This commit is contained in:
Vadim Lopatin 2015-01-30 16:14:43 +03:00
parent 7564129b42
commit bf79159d39
3 changed files with 92 additions and 29 deletions

View File

@ -60,10 +60,14 @@ class ActionState {
ActionState clone() const {
return new ActionState(enabled, visible, checked);
}
override bool opEquals(Object obj) {
if (auto other = cast(ActionState)obj) {
return enabled == other.enabled && visible == other.visible && checked == other.checked;
}
return false;
}
}
immutable ACTION_ID_STATE_REQUEST = -1;
/// action is
__gshared const(ActionState) ACTION_STATE_DEFAULT_ENABLED;
__gshared const(ActionState) ACTION_STATE_DEFAULT_DISABLE;
@ -98,39 +102,30 @@ class Action {
/// optional object parameter
protected Object _objectParam;
protected ActionState _state;
protected ActionState _defaultState;
/// default state for action if action state lookup failed
@property const(ActionState) defaultState() const { return _defaultState ? _defaultState : ACTION_STATE_DEFAULT_ENABLED; }
/// default state for action if action state lookup failed
@property Action defaultState(ActionState s) { _defaultState = s; return this; }
/// returns true if action is state request
@property bool isStateRequest() const {
return id == ACTION_ID_STATE_REQUEST;
/// action state
@property const(ActionState) state() const { return _state ? _state : (_defaultState ? _defaultState : ACTION_STATE_DEFAULT_ENABLED); }
/// update action state (for non-const action)
@property Action state(const ActionState s) {
if (_state != s)
_state = s.clone();
return this;
}
/// if this action is request of UI state for another action, returns ID of action state is requested for
@property int requestedActionId() const {
return isStateRequest ? cast(int)_longParam : 0;
}
/// if this action is request of UI state for another action, returns state (default if not changed while request handling by UI components)
@property const(ActionState) requestedActionState() const {
assert(isStateRequest);
return cast(ActionState)_objectParam;
}
/// if this action is request of UI state for another action, returns state (default if not changed while request handling by UI components)
@property const(Action) requestedActionState(ActionState s) const {
// hack: it's ok to replace action state in const ACTION_ID_STATE_REQUEST action
assert(isStateRequest);
Action nonconstThis = cast(Action)this;
nonconstThis._objectParam = cast(Object)s.clone();
return this;
}
/// create state request action for current action
Action createStateRequest() {
return (new Action(ACTION_ID_STATE_REQUEST)).longParam(_id).objectParam(defaultState.clone());
/// update action state (can be changed even for const objects)
@property const(Action) state(const ActionState s) const {
if (_state != s) {
// hack
Action nonConstThis = cast(Action) this;
nonConstThis._state = s.clone();
}
return this;
}
/// returns optional string parameter
@ -169,6 +164,8 @@ class Action {
_id = a._id;
_label = a._label;
_iconId = a._iconId;
_state = a._state.clone();
_defaultState = a._defaultState.clone();
_accelerators.length = a._accelerators.length;
for(int i = 0; i < _accelerators.length; i++)
_accelerators[i] = a._accelerators[i];

View File

@ -364,6 +364,7 @@ class Window {
}
if (animationActive)
scheduleAnimation();
_actionsUpdateRequested = false;
}
/// after drawing, call to schedule redraw if animation is active
@ -401,6 +402,8 @@ class Window {
newFocus.setState(State.Focused);
}
_focusedWidget = newFocus;
// after focus change, ask for actions update automatically
requestActionsUpdate();
}
return _focusedWidget;
}
@ -611,6 +614,38 @@ class Window {
return false;
}
/// dispatch action to main widget
bool dispatchActionStateRequest(const Action action, Widget sourceWidget = null) {
// try to handle by source widget
if(sourceWidget && isChild(sourceWidget)) {
if (sourceWidget.handleActionStateRequest(action))
return true;
sourceWidget = sourceWidget.parent;
}
Widget focus = focusedWidget;
// then offer action to focused widget
if (focus && isChild(focus)) {
if (focus.handleActionStateRequest(action))
return true;
focus = focus.parent;
}
// then offer to parent chain of source widget
while (sourceWidget && isChild(sourceWidget)) {
if (sourceWidget.handleActionStateRequest(action))
return true;
sourceWidget = sourceWidget.parent;
}
// then offer to parent chain of focused widget
while (focus && isChild(focus)) {
if (focus.handleActionStateRequest(action))
return true;
focus = focus.parent;
}
if (_mainWidget)
return _mainWidget.handleActionStateRequest(action);
return false;
}
/// post event to handle in UI thread (this method can be used from background thread)
void postEvent(CustomEvent event) {
// override to post event into window message queue
@ -833,6 +868,16 @@ class Window {
/// close window
abstract void close();
protected bool _actionsUpdateRequested;
/// set action update request flag, will be cleared after redraw
void requestActionsUpdate() {
_actionsUpdateRequested = true;
}
@property bool actionsUpdateRequested() {
return _actionsUpdateRequested;
}
/// Show message box with specified title and message
void showMessageBox(UIString title, UIString message, const (Action)[] actions = [ACTION_OK], int defaultActionIndex = 0, bool delegate(const Action result) handler = null) {
MessageBox dlg = new MessageBox(title, message, this, actions, defaultActionIndex, handler);

View File

@ -626,7 +626,24 @@ class Widget {
@property void action(const Action action) { _action = action.clone; }
/// action to emit on click
@property void action(Action action) { _action = action; }
/// ask for update state of some action (unles force=true, checks window flag
void updateActionState(Action a, bool force = false) {
if (Window w = window) {
if (!force && !w.actionsUpdateRequested())
return;
if (w.dispatchActionStateRequest(a, this)) {
// state is updated
} else {
a.state = a.defaultState;
}
}
}
/// call to update state for action (if action is assigned for widget)
void updateActionState(bool force = false) {
if (!_action)
return;
updateActionState(_action, force);
}
protected bool _focusGroup;
/*****************************************
@ -906,6 +923,10 @@ class Widget {
bool handleAction(const Action a) {
return false;
}
/// override to handle specific actions state (e.g. change enabled state for supported actions)
bool handleActionStateRequest(const Action a) {
return false;
}
/// call to dispatch action
bool dispatchAction(const Action a) {