]> git.mxchange.org Git - simgear.git/blob - simgear/structure/StateMachine.hxx
34fb84e103a9b4fd3a37a939cd9489eb72655c3f
[simgear.git] / simgear / structure / StateMachine.hxx
1 /* -*-c++-*-
2  *
3  * Copyright (C) 2013 James Turner
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18  * MA 02110-1301, USA.
19  *
20  */
21
22 #ifndef SIMGEAR_STATE_MACHINE_H
23 #define SIMGEAR_STATE_MACHINE_H
24
25 #include <memory>
26
27 #include <simgear/structure/SGReferenced.hxx>
28 #include <simgear/structure/SGSharedPtr.hxx>
29      
30 // forward decls
31 class SGPropertyNode;
32 class SGBinding;
33 class SGCondition;
34
35 namespace simgear
36 {
37
38 class StateMachine : public SGReferenced
39 {
40 public:
41     StateMachine();
42     virtual ~StateMachine();
43     
44     class State : public SGReferenced
45     {
46     public:    
47         virtual ~State();
48         
49         std::string name() const;
50         
51         void addUpdateBinding(SGBinding* aBinding);
52         void addEntryBinding(SGBinding* aBinding);
53         void addExitBinding(SGBinding* aBinding);
54         
55     private:  
56         friend class StateMachine;
57         
58         State(const std::string& name);
59         
60         void fireExitBindings();
61         void fireEntryBindings();
62         
63         void update();
64         
65         class StatePrivate;
66         std::auto_ptr<StatePrivate> d;
67     };
68     
69     class Transition : public SGReferenced
70     {
71     public:
72         virtual ~Transition();
73         
74         std::string name() const;
75         
76         /**
77          * The state we end in, after this transition fires
78          */
79         State* target() const;
80         
81         /**
82          * Add a state in which this transition is eligible to fire
83          */
84         void addSourceState(State* aSource);
85         
86         /**
87          * Specify the transition trigger condition. Takes ownership
88          */
89         void setTriggerCondition(SGCondition* aCondition);
90         
91         
92         void addBinding(SGBinding* aBinding);
93     private:
94         friend class StateMachine;
95         
96         Transition(const std::string& aName, State* aTarget);
97         
98         /**
99          * predicate to determine if this transition can fire given a
100          * current state.
101          */
102         bool applicableForState(State* aCurrent) const;
103         
104         /**
105         * test if the transition should fire, based on current state
106         */
107         bool evaluate() const;
108          
109         void fireBindings();
110     
111         class TransitionPrivate;
112         std::auto_ptr<TransitionPrivate> d;
113     };
114     
115     typedef SGSharedPtr<State> State_ptr;
116     typedef SGSharedPtr<Transition> Transition_ptr;
117     
118     /**
119      * create a state machine from a property list description
120      */
121     static StateMachine* createFromPlist(SGPropertyNode* desc, SGPropertyNode* root);
122     
123     SGPropertyNode* root();
124     
125     void init();
126     void shutdown();
127     
128     void update(double dt);
129     
130     State_ptr state() const;
131     
132     /**
133      * public API to force a change to a particular state.
134      * @param aOnlyIfDifferent - only make a transition if the new state is
135      *   different from the current state. Otherwise, the existing state will
136      * be exited and re-entered.
137      */
138     void changeToState(State_ptr aState, bool aOnlyIfDifferent=true);
139     
140      /// wrapper to change state by looking up a name
141     void changeToStateName(const std::string& aName, bool aOnlyIfDifferent=true);
142     
143     State_ptr findStateByName(const std::string& aName) const;
144     
145     State_ptr stateByIndex(unsigned int aIndex) const;
146     
147     int indexOfState(State_ptr aState) const;
148     
149     // programatic creation
150     State_ptr createState(const std::string& aName);
151     Transition_ptr createTransition(const std::string& aName, State_ptr aTarget);
152 private:
153     void addState(State_ptr aState);
154     void addTransition(Transition_ptr aTrans);
155     
156     void innerChangeState(State_ptr aState, Transition_ptr aTrans);
157     
158     class StateMachinePrivate;
159     std::auto_ptr<StateMachinePrivate> d;
160 };
161
162 typedef SGSharedPtr<StateMachine> StateMachine_ptr;
163
164 } // of simgear namespace
165
166 #endif // of SIMGEAR_STATE_MACHINE_H