Skip to content

Commit

Permalink
Refactor|Bindings|Client: Internalized more BindContext functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
danij-deng committed Nov 12, 2014
1 parent 5dec006 commit a65cf53
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 143 deletions.
19 changes: 0 additions & 19 deletions doomsday/client/include/ui/bindcontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,25 +121,6 @@ class BindContext
*/
bool deleteBinding(int id);

/**
* Delete all other bindings matching either @a commandBind or @a impulseBind.
*/
void deleteMatching(de::Record const *commandBind, de::Record const *impulseBind);

/**
* Look through the context for a binding that matches either of @a matchCmd or
* @a matchImp.
*
* @param matchCmd CommandBinding record to match, if any.
* @param matchImp ImpulseBinding record to match, if any.
* @param cmdResult The address of any matching CommandBinding is written here.
* @param impResult The address of any matching ImpulseBinding is written here.
*
* @return @c true if a match is found.
*/
bool findMatchingBinding(de::Record const *matchCmd, de::Record const *matchImp,
de::Record **cmdResult, de::Record **impResult) const;

// Commands ---------------------------------------------------------------------

de::Record *bindCommand(char const *eventDesc, char const *command);
Expand Down
5 changes: 5 additions & 0 deletions doomsday/client/include/ui/binding.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ class Binding : public de::RecordAccessor
* Generates a textual descriptor for the binding, including any state conditions.
*/
virtual de::String composeDescriptor() = 0;

/**
* Compare the binding conditions with @a other and return @c true if equivalent.
*/
bool equalConditions(Binding const &other) const;
};

typedef Binding::Condition BindingCondition;
Expand Down
238 changes: 114 additions & 124 deletions doomsday/client/src/ui/bindcontext.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @file bindcontext.cpp Input system binding contexts.
/** @file bindcontext.cpp Input system, binding context.
*
* @authors Copyright © 2009-2013 Jaakko Keränen <jaakko.keranen@iki.fi>
* @authors Copyright © 2007-2014 Daniel Swanson <danij@dengine.net>
Expand Down Expand Up @@ -27,7 +27,6 @@

#include "CommandBinding"
#include "ImpulseBinding"
#include "ui/b_util.h" // B_EqualConditions
#include "ui/inputdevice.h"
#include "ui/playerimpulse.h"

Expand Down Expand Up @@ -60,6 +59,117 @@ DENG2_PIMPL(BindContext)

Instance(Public *i) : Base(i) {}

/**
* Look through the context for a binding that matches either of @a matchCmd or
* @a matchImp.
*
* @param matchCmd CommandBinding record to match, if any.
* @param matchImp ImpulseBinding record to match, if any.
* @param cmdResult The address of any matching CommandBinding is written here.
* @param impResult The address of any matching ImpulseBinding is written here.
*
* @return @c true if a match is found.
*/
bool findMatchingBinding(Record const *matchCmdRec, Record const *matchImpRec,
Record **cmdResult, Record **impResult) const
{
DENG2_ASSERT(cmdResult && impResult);

*cmdResult = nullptr;
*impResult = nullptr;

if(!matchCmdRec && !matchImpRec) return false;

CommandBinding matchCmd;
if(matchCmdRec) matchCmd = matchCmdRec;

ImpulseBinding matchImp;
if(matchImpRec) matchImp = matchImpRec;

for(Record const *rec : commandBinds)
{
CommandBinding bind(*rec);

if(matchCmd && matchCmd.geti("id") != rec->geti("id"))
{
if(matchCmd.geti("type") == bind.geti("type") &&
matchCmd.geti("test") == bind.geti("test") &&
matchCmd.geti("deviceId") == bind.geti("deviceId") &&
matchCmd.geti("controlId") == bind.geti("controlId") &&
matchCmd.equalConditions(bind))
{
*cmdResult = const_cast<Record *>(rec);
return true;
}
}
if(matchImp)
{
if(matchImp.geti("type") == bind.geti("type") &&
matchImp.geti("deviceId") == bind.geti("deviceId") &&
matchImp.geti("controlId") == bind.geti("controlId") &&
matchImp.equalConditions(bind))
{
*cmdResult = const_cast<Record *>(rec);
return true;
}
}
}

for(int i = 0; i < DDMAXPLAYERS; ++i)
for(Record const *rec : impulseBinds[i])
{
ImpulseBinding bind(*rec);

if(matchCmd)
{
if(matchCmd.geti("type") == bind.geti("type") &&
matchCmd.geti("deviceId") == bind.geti("deviceId") &&
matchCmd.geti("controlId") == bind.geti("controlId") &&
matchCmd.equalConditions(bind))
{
*impResult = const_cast<Record *>(rec);
return true;
}
}

if(matchImp && matchImp.geti("id") != bind.geti("id"))
{
if(matchImp.geti("type") == bind.geti("type") &&
matchImp.geti("deviceId") == bind.geti("deviceId") &&
matchImp.geti("controlId") == bind.geti("controlId") &&
matchImp.equalConditions(bind))
{
*impResult = const_cast<Record *>(rec);
return true;
}
}
}

// Nothing found.
return false;
}

/**
* Delete all other bindings matching either @a commandBind or @a impulseBind.
*/
void deleteMatching(Record const *cmdBinding, Record const *impBinding)
{
Record *foundCmd = nullptr;
Record *foundImp = nullptr;

while(findMatchingBinding(cmdBinding, impBinding, &foundCmd, &foundImp))
{
// Only either foundCmd or foundImp is returned as non-NULL.
int bindId = (foundCmd? foundCmd->geti("id") : (foundImp? foundImp->geti("id") : 0));
if(bindId)
{
LOG_INPUT_VERBOSE("Deleting binding %i, it has been overridden by binding %i")
<< bindId << (cmdBinding? cmdBinding->geti("id") : impBinding->geti("id"));
self.deleteBinding(bindId);
}
}
}

DENG2_PIMPL_AUDIENCE(ActiveChange)
DENG2_PIMPL_AUDIENCE(AcquireDeviceChange)
DENG2_PIMPL_AUDIENCE(BindingAddition)
Expand Down Expand Up @@ -176,24 +286,6 @@ void BindContext::clearAllBindings()
LOG_INPUT_VERBOSE(_E(b) "'%s'" _E(.) " cleared") << d->name;
}

void BindContext::deleteMatching(Record const *cmdBinding, Record const *impBinding)
{
Record *foundCmd = nullptr;
Record *foundImp = nullptr;

while(findMatchingBinding(cmdBinding, impBinding, &foundCmd, &foundImp))
{
// Only either foundCmd or foundImp is returned as non-NULL.
int bindId = (foundCmd? foundCmd->geti("id") : (foundImp? foundImp->geti("id") : 0));
if(bindId)
{
LOG_INPUT_VERBOSE("Deleting binding %i, it has been overridden by binding %i")
<< bindId << (cmdBinding? cmdBinding->geti("id") : impBinding->geti("id"));
deleteBinding(bindId);
}
}
}

Record *BindContext::bindCommand(char const *eventDesc, char const *command)
{
DENG2_ASSERT(eventDesc && command && command[0]);
Expand All @@ -212,7 +304,7 @@ Record *BindContext::bindCommand(char const *eventDesc, char const *command)

/// @todo: In interactive binding mode, should ask the user if the
/// replacement is ok. For now, just delete the other bindings.
deleteMatching(bind, nullptr);
d->deleteMatching(bind, nullptr);

// Notify interested parties.
DENG2_FOR_AUDIENCE2(BindingAddition, i) i->bindContextBindingAdded(*this, *bind, true/*is-command*/);
Expand Down Expand Up @@ -244,7 +336,7 @@ Record *BindContext::bindImpulse(char const *ctrlDesc, PlayerImpulse const &impu

/// @todo: In interactive binding mode, should ask the user if the
/// replacement is ok. For now, just delete the other bindings.
deleteMatching(nullptr, bind);
d->deleteMatching(nullptr, bind);

// Notify interested parties.
DENG2_FOR_AUDIENCE2(BindingAddition, i) i->bindContextBindingAdded(*this, *bind, false/*is-impulse*/);
Expand Down Expand Up @@ -362,108 +454,6 @@ bool BindContext::tryEvent(ddevent_t const &event, bool respectHigherContexts) c
return false;
}

static bool conditionsAreEqual(QVector<BindingCondition> const &conds1,
QVector<BindingCondition> const &conds2)
{
// Quick test (assumes there are no duplicated conditions).
if(conds1.count() != conds2.count()) return false;

for(BindingCondition const &a : conds1)
{
bool found = false;
for(BindingCondition const &b : conds2)
{
if(B_EqualConditions(a, b))
{
found = true;
break;
}
}
if(!found) return false;
}

return true;
}

bool BindContext::findMatchingBinding(Record const *matchCmdRec, Record const *matchImpRec,
Record **cmdResult, Record **impResult) const
{
DENG2_ASSERT(cmdResult && impResult);

*cmdResult = nullptr;
*impResult = nullptr;

if(!matchCmdRec && !matchImpRec) return false;

CommandBinding matchCmd;
if(matchCmdRec) matchCmd = matchCmdRec;

ImpulseBinding matchImp;
if(matchImpRec) matchImp = matchImpRec;

for(Record const *rec : d->commandBinds)
{
CommandBinding bind(*rec);

if(matchCmd && matchCmd.geti("id") != rec->geti("id"))
{
if(matchCmd.geti("type") == bind.geti("type") &&
matchCmd.geti("test") == bind.geti("test") &&
matchCmd.geti("deviceId") == bind.geti("deviceId") &&
matchCmd.geti("controlId") == bind.geti("controlId") &&
conditionsAreEqual(matchCmd.conditions, bind.conditions))
{
*cmdResult = const_cast<Record *>(rec);
return true;
}
}
if(matchImp)
{
if(matchImp.geti("type") == bind.geti("type") &&
matchImp.geti("deviceId") == bind.geti("deviceId") &&
matchImp.geti("controlId") == bind.geti("controlId") &&
conditionsAreEqual(matchImp.conditions, bind.conditions))
{
*cmdResult = const_cast<Record *>(rec);
return true;
}
}
}

for(int i = 0; i < DDMAXPLAYERS; ++i)
for(Record const *rec : d->impulseBinds[i])
{
ImpulseBinding bind(*rec);

if(matchCmd)
{
if(matchCmd.geti("type") == bind.geti("type") &&
matchCmd.geti("deviceId") == bind.geti("deviceId") &&
matchCmd.geti("controlId") == bind.geti("controlId") &&
conditionsAreEqual(matchCmd.conditions, bind.conditions))
{
*impResult = const_cast<Record *>(rec);
return true;
}
}

if(matchImp && matchImp.geti("id") != bind.geti("id"))
{
if(matchImp.geti("type") == bind.geti("type") &&
matchImp.geti("deviceId") == bind.geti("deviceId") &&
matchImp.geti("controlId") == bind.geti("controlId") &&
conditionsAreEqual(matchImp.conditions, bind.conditions))
{
*impResult = const_cast<Record *>(rec);
return true;
}
}
}

// Nothing found.
return false;
}

LoopResult BindContext::forAllCommandBindings(
std::function<de::LoopResult (Record &)> func) const
{
Expand Down
24 changes: 24 additions & 0 deletions doomsday/client/src/ui/binding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
* General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/

#include "ui/binding.h"
#include "ui/b_util.h" // B_EqualConditions

using namespace de;

Expand All @@ -34,3 +36,25 @@ Binding::operator bool() const
{
return accessedRecordPtr() != 0;
}

bool Binding::equalConditions(Binding const &other) const
{
// Quick test (assumes there are no duplicated conditions).
if(conditions.count() != other.conditions.count()) return false;

for(BindingCondition const &a : conditions)
{
bool found = false;
for(BindingCondition const &b : other.conditions)
{
if(B_EqualConditions(a, b))
{
found = true;
break;
}
}
if(!found) return false;
}

return true;
}

0 comments on commit a65cf53

Please sign in to comment.