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 { ActionState clone() const {
return new ActionState(enabled, visible, checked); 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 /// action is
__gshared const(ActionState) ACTION_STATE_DEFAULT_ENABLED; __gshared const(ActionState) ACTION_STATE_DEFAULT_ENABLED;
__gshared const(ActionState) ACTION_STATE_DEFAULT_DISABLE; __gshared const(ActionState) ACTION_STATE_DEFAULT_DISABLE;
@ -98,39 +102,30 @@ class Action {
/// optional object parameter /// optional object parameter
protected Object _objectParam; protected Object _objectParam;
protected ActionState _state;
protected ActionState _defaultState; protected ActionState _defaultState;
/// default state for action if action state lookup failed /// default state for action if action state lookup failed
@property const(ActionState) defaultState() const { return _defaultState ? _defaultState : ACTION_STATE_DEFAULT_ENABLED; } @property const(ActionState) defaultState() const { return _defaultState ? _defaultState : ACTION_STATE_DEFAULT_ENABLED; }
/// default state for action if action state lookup failed /// default state for action if action state lookup failed
@property Action defaultState(ActionState s) { _defaultState = s; return this; } @property Action defaultState(ActionState s) { _defaultState = s; return this; }
/// action state
/// returns true if action is state request @property const(ActionState) state() const { return _state ? _state : (_defaultState ? _defaultState : ACTION_STATE_DEFAULT_ENABLED); }
@property bool isStateRequest() const { /// update action state (for non-const action)
return id == ACTION_ID_STATE_REQUEST; @property Action state(const ActionState s) {
} if (_state != s)
_state = s.clone();
/// 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; return this;
} }
/// create state request action for current action /// update action state (can be changed even for const objects)
Action createStateRequest() { @property const(Action) state(const ActionState s) const {
return (new Action(ACTION_ID_STATE_REQUEST)).longParam(_id).objectParam(defaultState.clone()); if (_state != s) {
// hack
Action nonConstThis = cast(Action) this;
nonConstThis._state = s.clone();
}
return this;
} }
/// returns optional string parameter /// returns optional string parameter
@ -169,6 +164,8 @@ class Action {
_id = a._id; _id = a._id;
_label = a._label; _label = a._label;
_iconId = a._iconId; _iconId = a._iconId;
_state = a._state.clone();
_defaultState = a._defaultState.clone();
_accelerators.length = a._accelerators.length; _accelerators.length = a._accelerators.length;
for(int i = 0; i < _accelerators.length; i++) for(int i = 0; i < _accelerators.length; i++)
_accelerators[i] = a._accelerators[i]; _accelerators[i] = a._accelerators[i];

View File

@ -364,6 +364,7 @@ class Window {
} }
if (animationActive) if (animationActive)
scheduleAnimation(); scheduleAnimation();
_actionsUpdateRequested = false;
} }
/// after drawing, call to schedule redraw if animation is active /// after drawing, call to schedule redraw if animation is active
@ -401,6 +402,8 @@ class Window {
newFocus.setState(State.Focused); newFocus.setState(State.Focused);
} }
_focusedWidget = newFocus; _focusedWidget = newFocus;
// after focus change, ask for actions update automatically
requestActionsUpdate();
} }
return _focusedWidget; return _focusedWidget;
} }
@ -611,6 +614,38 @@ class Window {
return false; 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) /// post event to handle in UI thread (this method can be used from background thread)
void postEvent(CustomEvent event) { void postEvent(CustomEvent event) {
// override to post event into window message queue // override to post event into window message queue
@ -833,6 +868,16 @@ class Window {
/// close window /// close window
abstract void close(); 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 /// 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) { 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); 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; } @property void action(const Action action) { _action = action.clone; }
/// action to emit on click /// action to emit on click
@property void action(Action action) { _action = action; } @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; protected bool _focusGroup;
/***************************************** /*****************************************
@ -906,6 +923,10 @@ class Widget {
bool handleAction(const Action a) { bool handleAction(const Action a) {
return false; 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 /// call to dispatch action
bool dispatchAction(const Action a) { bool dispatchAction(const Action a) {