/// <summary> /// Implements the reducer function /// </summary> /// <param name="state">Current state</param> /// <param name="action">Action</param> /// <returns></returns> private static AppState ReduceWindowState(AppState state, IReducerAction action) { if (!(action is WindowActionBase windowAction)) { return(state); } switch (windowAction) { case MaximizeWindowAction _: if (state.WindowState != WindowState.Maximized) { s_Worker?.Invoke(WindowState.Maximized); return(state.Assign(s => s.WindowState = WindowState.Maximized)); } return(state); case MinimizeWindowAction _: if (state.WindowState != WindowState.Minimized) { s_Worker?.Invoke(WindowState.Minimized); return(state.Assign(s => s.WindowState = WindowState.Minimized)); } return(state); case RestoreWindowAction _: if (state.WindowState != WindowState.Normal) { s_Worker?.Invoke(WindowState.Normal); return(state.Assign(s => s.WindowState = WindowState.Normal)); } return(state); case AppGotFocusAction _: return(state.Assign(s => s.HasFocus = true)); case AppLostFocusAction _: return(state.Assign(s => s.HasFocus = false)); case CloseWindowAction _: s_Worker?.Invoke(WindowState.ToClose); return(state.Assign(s => s.WindowState = WindowState.ToClose)); default: return(state); } }
/// <summary> /// Dispatches the specified actions, and sets /// the new state of the store accordingly. /// </summary> /// <param name="action">Action to dispatch</param> /// <returns> /// The new state of the store. /// </returns> /// <remarks> /// The action forst goes through the chain of middleware objects, /// starting from the first one. Middleware objects can vote to abandone /// the dispatch process. Though they can, they should not change the /// app state. /// /// If a middleware votes for abandon the dispatch process, the subsequent /// middleware objects are skipped; the reducer would not be dispatched. /// After going through the middlewares, all reducers are invoked, starting /// with the first. /// /// Whenever the new state is different from the previous one, the StateChanged /// event is raised. /// </remarks> public TState Dispatch(IReducerAction action) { var oldState = _lastState; // --- Go through middlewares var goOn = true; foreach (var middleware in _middlewares) { if (!(goOn = middleware(this, action))) { break; } } // --- Call the reducer, provided the middleware does // --- not abandon if (goOn) { lock (_syncRoot) { foreach (var reducer in _reducers) { _lastState = reducer(_lastState, action); } } } // --- Check for change var stateHasChanged = typeof(TState) is IEqualityComparer <TState> ? !(oldState as IEqualityComparer <TState>).Equals(_lastState as IEqualityComparer <TState>) : (object)oldState != (object)_lastState; if (stateHasChanged) { StateChanged?.Invoke(oldState, _lastState); } return(_lastState); }
/// <summary> /// Dispatches the specified action. /// </summary> /// <param name="action">Action to dispatch</param> public void Dispatch(IReducerAction action) { StateStore.Dispatch(action); }
/// <summary> /// Implements the reducer function /// </summary> /// <param name="state">Current state</param> /// <param name="action">Action</param> /// <returns></returns> private static AppState ReduceAppMenuState(AppState state, IReducerAction action) { if (!(action is MenuActionBase menuAction)) { return(state); } switch (menuAction) { case SetAppMenuAction setAppMenuAction: return(state.Assign( s => s.MenuState = s.MenuState.Assign( a => a.AppMenu = setAppMenuAction.AppMenu))); case MenuAltPressedAction _: return(state.Assign( s => s.MenuState = s.MenuState.Assign( a => { a.HighlightAccessKeys = s.MenuState.SelectedIndex < 0; a.OpenPanes = new List <MenuPaneInfo>(); a.KeyboardAction = true; }))); case MenuAltReleasedAction _: var itemIndex = state.MenuState.SelectedIndex < 0 ? 0 : -1; return(state.Assign( s => s.MenuState = s.MenuState.Assign( a => { a.SelectedIndex = itemIndex; a.HighlightAccessKeys = itemIndex >= 0; a.KeyboardAction = true; }))); case MenuPaneClosedAction _: { var(parentPanes, lastPane) = GetOpenMenuPanes(state.MenuState); if (lastPane != null) { return(state.Assign( s => s.MenuState = s.MenuState.Assign( a => { a.OpenPanes = parentPanes; a.KeyboardAction = true; }))); } return(state.Assign( s => s.MenuState = s.MenuState.Assign( a => { a.SelectedIndex = -1; a.HighlightAccessKeys = false; a.KeyboardAction = true; }))); } case MenuButtonSetAction menuButtonSetAction: return(state.Assign( s => s.MenuState = s.MenuState.Assign( a => { a.SelectedIndex = menuButtonSetAction.ItemIndex; a.OpenPanes = menuButtonSetAction.Pane != null ? new List <MenuPaneInfo> { menuButtonSetAction.Pane } : new List <MenuPaneInfo>(); a.KeyboardAction = menuButtonSetAction.KeyboardAction; }))); case MenuItemDownAction _: { var(parentPanes, lastPane) = GetOpenMenuPanes(state.MenuState); if (lastPane == null) { return(state); } return(state.Assign( s => s.MenuState = s.MenuState.Assign( a => { a.OpenPanes = parentPanes.Concat( new List <MenuPaneInfo> { lastPane.Assign(lp => lp.SelectedIndex = GetNextMenuItemIndex(lp, 1)) }).ToList(); }))); } case MenuItemUpAction _: { var(parentPanes, lastPane) = GetOpenMenuPanes(state.MenuState); if (lastPane == null) { return(state); } return(state.Assign( s => s.MenuState = s.MenuState.Assign( a => { a.OpenPanes = parentPanes.Concat( new List <MenuPaneInfo> { lastPane.Assign(lp => lp.SelectedIndex = GetNextMenuItemIndex(lp, -1)) }).ToList(); }))); } case MenuPaneOpenAction menuPaneOpenAction: { return(state.Assign( s => s.MenuState = s.MenuState.Assign( a => { a.OpenPanes = a.OpenPanes.Concat( new List <MenuPaneInfo> { menuPaneOpenAction.Pane }).ToList(); a.KeyboardAction = menuPaneOpenAction.KeyboardAction; }))); } case MenuCloseAllPanesAction _: return(state.Assign( s => s.MenuState = s.MenuState.Assign( a => { a.SelectedIndex = -1; a.HighlightAccessKeys = false; a.OpenPanes = new List <MenuPaneInfo>(); a.KeyboardAction = false; }))); case MenuItemSelectAction menuItemSelectAction: { var(parentPanes, lastPane) = GetOpenMenuPanes(state.MenuState); if (lastPane == null) { return(state); } return(state.Assign( s => s.MenuState = s.MenuState.Assign( a => { a.OpenPanes = parentPanes.Concat( new List <MenuPaneInfo> { lastPane.Assign(lp => lp.SelectedIndex = menuItemSelectAction.Index) }).ToList(); a.KeyboardAction = true; }))); } case MenuButtonClickAction menuButtonClickAction: { return(state.Assign( s => s.MenuState = s.MenuState.Assign( a => { a.SelectedIndex = menuButtonClickAction.Index; a.OpenPanes = new List <MenuPaneInfo> { menuButtonClickAction.Pane }; a.KeyboardAction = false; }))); } case MenuKeepPaneAction menuKeepPaneAction: { return(state.Assign( s => s.MenuState = s.MenuState.Assign( a => { a.OpenPanes = a.OpenPanes.Take(menuKeepPaneAction.PaneIndex + 1).ToList(); a.KeyboardAction = false; }))); } case MenuItemPointAction menuItemPointAction: { var panes = state.MenuState.OpenPanes.ToList(); var paneIndex = menuItemPointAction.PaneIndex; if (paneIndex < 0 || paneIndex >= panes.Count) { return(state); } var pane = panes[menuItemPointAction.PaneIndex]; var selectedIndex = menuItemPointAction.ItemIndex >= 0 ? pane.Items.Flatten().ToArray()[menuItemPointAction.ItemIndex].Enabled ? menuItemPointAction.ItemIndex : -1 : -1; panes[menuItemPointAction.PaneIndex] = new MenuPaneInfo { Items = pane.Items, ParentIndex = pane.ParentIndex, LeftPos = pane.LeftPos, TopPos = pane.TopPos, SelectedIndex = selectedIndex }; return(state.Assign( s => s.MenuState = s.MenuState.Assign( a => { a.OpenPanes = panes; a.KeyboardAction = false; }))); } default: return(state); }
/// <summary> /// Dispatches the specified actions, and sets /// the new state of the store accordingly. /// </summary> /// <param name="action">Action to dispatch</param> /// <returns> /// The new state of the store. /// </returns> public static AppState Dispatch(IReducerAction action) => s_Store.Dispatch(action);