Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/sound4/src/libraries/core/input/Button.cc @ 6457

Last change on this file since 6457 was 6432, checked in by rgrieder, 15 years ago

Changed the way config values associated with general settings (ConfigFileType::Settings) are handled:

  • ConfigFileManager only handles config files listed in the ConfigFileType enum (normal enum again)
  • ConfigFileManager only takes care of ConfigFiles and returns a pointer to the right one, just two functions left. —> use like: ConfigFileManager::getInstance().getConfigFile(myType)→doSomething();
  • Moved all code (except for the argument completion functions) relating to ConfigFileType::Settings to a new class: SettingsConfigFile, which is a Singleton (it doesn't make sense to have multiple instances unless you start coding a lot more)
  • SettingsConfigFile handles config value containers according to their section and entry in the ini file, not according to class and variables names. (In most cases it will be class and variable names though)
  • SettingsConfigFile supports:
    • clear() (removes any file entries not associated to a config value container)
    • updateConfigValues() (does exactly that through the identifier)
    • config, tconfig and getConfig
    • commands listed above are exported to tolua, and tconfig, config and getConfig were given shortcuts in Lua (e.g. orxonox.config)
  • If you need to organise ConfigFiles yourself, just do it without the ConfigFileManager, like the KeyBinder does.
  • All getValue() functions have been split into getOrCreateValue() and getValue(), which is const
  • Removed obsolete config value management code in the Identifier (it still stores and destroys them and provides access to them)

All of that leads to one HUGE advantage:
"config OutputHandler softDebugLevelInGameConsole"
works now :D (any further implications are up to the reader…)
(it didn't work before because the actual config value container is in the InGameConsole singleton)

  • Property svn:eol-style set to native
File size: 9.0 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Reto Grieder
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30@file
31@brief
32    Implementation of the different input handlers.
33*/
34
35#include "Button.h"
36
37#include "util/Convert.h"
38#include "util/SubString.h"
39#include "util/StringUtils.h"
40#include "util/Debug.h"
41#include "core/ConsoleCommand.h"
42#include "core/CommandEvaluation.h"
43#include "core/CommandExecutor.h"
44#include "core/ConfigFileManager.h"
45
46namespace orxonox
47{
48    /**
49    @note
50        bButtonThresholdUser_: We set it to true so that setConfigValues in KeyBinder sets the value
51        correctly the first time. It is then set to false first and changed later in Button::parse().
52    */
53    Button::Button()
54        : bButtonThresholdUser_(false)
55        , paramCommandBuffer_(0)
56    {
57        nCommands_[0]=0;
58        nCommands_[1]=0;
59        nCommands_[2]=0;
60    }
61
62    Button::~Button()
63    {
64        this->clear();
65    }
66
67    void Button::clear()
68    {
69        for (unsigned int j = 0; j < 3; j++)
70        {
71            if (nCommands_[j])
72            {
73                // delete all commands and the command pointer array
74                for (unsigned int i = 0; i < nCommands_[j]; i++)
75                    delete commands_[j][i];
76                delete[] commands_[j];
77                commands_[j] = 0;
78                nCommands_[j] = 0;
79            }
80        }
81        this->bindingString_.clear();
82    }
83
84    void Button::readBinding(ConfigFile* configFile)
85    {
86        const std::string& binding = configFile->getOrCreateValue(groupName_, name_, "", true);
87        this->parse(binding);
88    }
89
90    void Button::setBinding(ConfigFile* configFile, const std::string& binding, bool bTemporary)
91    {
92        if (!bTemporary)
93            configFile->setValue(groupName_, name_, binding, true);
94        this->parse(binding);
95    }
96
97    void Button::parse(const std::string& binding)
98    {
99        if (binding == this->bindingString_)
100            return;
101
102        // delete all commands
103        clear();
104        this->bindingString_ = binding;
105
106        if (isEmpty(bindingString_))
107            return;
108
109        // reset this to false first when parsing (was true before when parsing for the first time)
110        bButtonThresholdUser_ = false;
111
112        // use std::vector for a temporary dynamic array
113        std::vector<BaseCommand*> commands[3];
114
115        // separate the commands
116        SubString commandStrings(bindingString_, "|", SubString::WhiteSpaces, false,
117            '\\', false, '"', false, '(', ')', false, '\0');
118
119        for (unsigned int iCommand = 0; iCommand < commandStrings.size(); iCommand++)
120        {
121            if (!commandStrings[iCommand].empty())
122            {
123                SubString tokens(commandStrings[iCommand], " ", SubString::WhiteSpaces, false,
124                    '\\', false, '"', false, '(', ')', false, '\0');
125
126                KeybindMode::Value mode = KeybindMode::None;
127                float paramModifier = 1.0f;
128                std::string commandStr;
129
130                for (unsigned int iToken = 0; iToken < tokens.size(); ++iToken)
131                {
132                    const std::string& token = getLowercase(tokens[iToken]);
133
134                    if (token == "onpress")
135                        mode = KeybindMode::OnPress;
136                    else if (token == "onrelease")
137                        mode = KeybindMode::OnRelease;
138                    else if (token == "onhold")
139                        mode = KeybindMode::OnHold;
140                    else if (token == "buttonthreshold")
141                    {
142                        // for real axes, we can feed a ButtonThreshold argument
143                        ++iToken;
144                        if (iToken == tokens.size())
145                            continue;
146                        // may fail, but doesn't matter (default value already set)
147                        if (!convertValue(&buttonThreshold_, tokens[iToken + 1]))
148                            parseError("Could not parse 'ButtonThreshold' argument. \
149                                Switching to default value.", true);
150                        else
151                            this->bButtonThresholdUser_ = true;
152                    }
153                    else if (token == "scale")
154                    {
155                        ++iToken;
156                        if (iToken == tokens.size() || !convertValue(&paramModifier, tokens[iToken]))
157                            parseError("Could not parse 'scale' argument. Switching to default value.", true);
158                    }
159                    else
160                    {
161                        // no input related argument
162                        // we interpret everything from here as a command string
163                        while (iToken != tokens.size())
164                            commandStr += tokens[iToken++] + ' ';
165                    }
166                }
167
168                if (commandStr.empty())
169                {
170                    parseError("No command string given.", false);
171                    continue;
172                }
173
174                // evaluate the command
175                const CommandEvaluation& eval = CommandExecutor::evaluate(commandStr);
176                if (!eval.isValid())
177                {
178                    parseError("Command evaluation of \"" + commandStr + "\"failed.", true);
179                    continue;
180                }
181
182                // check for param command
183                int paramIndex = eval.getConsoleCommand()->getInputConfiguredParam_();
184                if (paramIndex >= 0)
185                {
186                    // parameter supported command
187                    ParamCommand* cmd = new ParamCommand();
188                    cmd->scale_ = paramModifier;
189
190                    // add command to the buffer if not yet existing
191                    for (unsigned int iParamCmd = 0; iParamCmd < paramCommandBuffer_->size(); iParamCmd++)
192                    {
193                        if ((*paramCommandBuffer_)[iParamCmd]->evaluation_.getConsoleCommand()
194                            == eval.getConsoleCommand())
195                        {
196                            // already in list
197                            cmd->paramCommand_ = (*paramCommandBuffer_)[iParamCmd];
198                            break;
199                        }
200                    }
201                    if (cmd->paramCommand_ == 0)
202                    {
203                        cmd->paramCommand_ = new BufferedParamCommand();
204                        paramCommandBuffer_->push_back(cmd->paramCommand_);
205                        cmd->paramCommand_->evaluation_ = eval;
206                        cmd->paramCommand_->paramIndex_ = paramIndex;
207                    }
208
209
210                    // we don't know whether this is an actual axis or just a button
211                    if (mode == KeybindMode::None)
212                    {
213                        if (!addParamCommand(cmd))
214                        {
215                            mode = eval.getConsoleCommand()->getKeybindMode();
216                            commands[mode].push_back(cmd);
217                        }
218                    }
219                }
220                else
221                {
222                    SimpleCommand* cmd = new SimpleCommand();
223                    cmd->evaluation_ = eval;
224
225                    if (mode == KeybindMode::None)
226                        mode = eval.getConsoleCommand()->getKeybindMode();
227
228                    commands[mode].push_back(cmd);
229                }
230            }
231        }
232
233        for (unsigned int j = 0; j < 3; j++)
234        {
235            nCommands_[j] = commands[j].size();
236            if (nCommands_[j])
237            {
238                commands_[j] = new BaseCommand*[nCommands_[j]];
239                for (unsigned int i = 0; i < commands[j].size(); i++)
240                    commands_[j][i] = commands[j][i];
241            }
242            else
243                commands_[j] = 0;
244        }
245    }
246
247    inline void Button::parseError(const std::string& message, bool serious)
248    {
249        if (serious)
250        {
251            COUT(2) << "Error while parsing binding for button/axis " << this->name_ << ". "
252                << message << std::endl;
253        }
254        else
255        {
256            COUT(3) << "Warning while parsing binding for button/axis " << this->name_ << ". "
257                << message << std::endl;
258        }
259    }
260}
Note: See TracBrowser for help on using the repository browser.