Skip to content

Commit

Permalink
Implement change signal for GUI expressions to notify windowDef varia…
Browse files Browse the repository at this point in the history
…bles and let them recompile their texts.
  • Loading branch information
codereader committed Dec 17, 2017
1 parent 31d7e54 commit e5b215b
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 13 deletions.
39 changes: 39 additions & 0 deletions include/igui.h
Expand Up @@ -6,6 +6,7 @@
#include <map>

#include <sigc++/signal.h>
#include <sigc++/connection.h>
#include "imodule.h"
#include "math/Vector4.h"
#include "string/convert.h"
Expand Down Expand Up @@ -41,6 +42,9 @@ class IGuiExpression

// Evaluate this expression to retrieve the result
virtual ValueType evaluate() = 0;

// Value changed signal
virtual sigc::signal<void>& signal_valueChanged() = 0;
};

// An expression representing a constant value
Expand All @@ -51,6 +55,8 @@ class ConstantExpression :
private:
ValueType _value;

sigc::signal<void> _sigValueChanged;

public:
ConstantExpression(const ValueType& value) :
_value(value)
Expand All @@ -61,6 +67,12 @@ class ConstantExpression :
return _value;
}

// Provide a value changed signal, though it's never invoked
sigc::signal<void>& signal_valueChanged() override
{
return _sigValueChanged;
}

template<typename OtherType>
static std::shared_ptr<ConstantExpression<ValueType>> Create(const OtherType& value)
{
Expand Down Expand Up @@ -102,6 +114,8 @@ class WindowVariable :
// The expression which can be evaluated
ExpressionTypePtr _expression;

sigc::connection _exprChangedSignal;

public:
typedef std::shared_ptr<WindowVariable<ValueType>> Ptr; // smart ptr typedef

Expand All @@ -119,15 +133,36 @@ class WindowVariable :
// to match the ValueType of this variable
virtual void setValue(const ExpressionTypePtr& newExpr)
{
if (_expression == newExpr) return;

// Disconnect from any previously subscribed signals
_exprChangedSignal.disconnect();

_expression = newExpr;

signal_variableChanged().emit();

// Subscribe to this new expression's changed signal
if (_expression)
{
_expression->signal_valueChanged().connect([this]()
{
signal_variableChanged().emit();
});
}
}

// Assigns a constant value to this variable
virtual void setValue(const ValueType& constantValue)
{
// Disconnect from any previously subscribed signals
_exprChangedSignal.disconnect();

_expression = ConstantExpression<ValueType>::Create(constantValue);

signal_variableChanged().emit();

// Since this is a constant expression, we don't need to subscribe to any signal
}

// Implement the required string->ValueType conversion by means of string::convert<>
Expand Down Expand Up @@ -269,6 +304,10 @@ class IGui
// Sets the given state variable (gui::<key> = <value>)
virtual void setStateString(const std::string& key, const std::string& value) = 0;

// Retrieve a changed signal for the given key, which is invoked
// whenever setStateString() is called
virtual sigc::signal<void>& getChangedSignalForState(const std::string& key) = 0;

// Returns the state string "gui::<key>" or an empty string if non-existent
virtual std::string getStateString(const std::string& key) = 0;

Expand Down
24 changes: 23 additions & 1 deletion plugins/dm.gui/gui/Gui.cpp
Expand Up @@ -45,7 +45,29 @@ void Gui::setStateString(const std::string& key, const std::string& value)
{
_state[key] = value;

// TODO: Handle state variable links to windowDef registers
// Handle state variable links to windowDef registers
GuiStateChangedSignals::iterator i = _stateSignals.find(key);

if (i != _stateSignals.end())
{
i->second.emit();
}
}

sigc::signal<void>& Gui::getChangedSignalForState(const std::string& key)
{
GuiStateChangedSignals::iterator i = _stateSignals.find(key);

if (i != _stateSignals.end())
{
return i->second;
}

// Insert a new signal
std::pair<GuiStateChangedSignals::iterator, bool> result =
_stateSignals.insert(std::make_pair(key, sigc::signal<void>()));

return result.first->second;
}

std::string Gui::getStateString(const std::string& key)
Expand Down
9 changes: 8 additions & 1 deletion plugins/dm.gui/gui/Gui.h
Expand Up @@ -3,6 +3,7 @@
#include "igui.h"

#include <map>
#include <unordered_map>
#include <memory>
#include "parser/DefTokeniser.h"
#include "GuiWindowDef.h"
Expand All @@ -28,16 +29,22 @@ class Gui :
IGuiWindowDefPtr _desktop;

// The global GUI state variables
typedef std::map<std::string, std::string> GuiState;
typedef std::unordered_map<std::string, std::string> GuiState;
GuiState _state;

typedef std::unordered_map<std::string, sigc::signal<void>> GuiStateChangedSignals;
GuiStateChangedSignals _stateSignals;

public:
const IGuiWindowDefPtr& getDesktop() const override;
void setDesktop(const IGuiWindowDefPtr& newDesktop) override;

// Sets the given state variable (gui::<key> = <value>)
void setStateString(const std::string& key, const std::string& value) override;

// Allocate and/or return the changed signal for the given key
sigc::signal<void>& getChangedSignalForState(const std::string& key) override;

// Returns the state string "gui::<key>" or an empty string if non-existent
std::string getStateString(const std::string& key) override;

Expand Down
61 changes: 56 additions & 5 deletions plugins/dm.gui/gui/GuiExpression.cpp
Expand Up @@ -2,6 +2,7 @@

#include <list>
#include <stack>
#include <sigc++/connection.h>

#include "itextstream.h"

Expand All @@ -16,7 +17,16 @@ namespace gui
GuiStateVariableExpression::GuiStateVariableExpression(IGui& gui, const std::string& variableName) :
_gui(gui),
_variableName(variableName)
{}
{
if (!_variableName.empty())
{
// Register to the GUI state change signal
_gui.getChangedSignalForState(_variableName).connect([this]()
{
signal_valueChanged().emit();
});
}
}

float GuiStateVariableExpression::getFloatValue()
{
Expand Down Expand Up @@ -57,6 +67,9 @@ class BinaryExpression :
GuiExpressionPtr _b;
Precedence _precedence;

sigc::connection _aChanged;
sigc::connection _bChanged;

public:
BinaryExpression(Precedence precedence,
const GuiExpressionPtr& a = GuiExpressionPtr(),
Expand All @@ -65,7 +78,23 @@ class BinaryExpression :
_a(a),
_b(b),
_precedence(precedence)
{}
{
if (_a)
{
_aChanged = _a->signal_valueChanged().connect([this]()
{
signal_valueChanged().emit();
});
}

if (_b)
{
_bChanged = _b->signal_valueChanged().connect([this]()
{
signal_valueChanged().emit();
});
}
}

Precedence getPrecedence() const
{
Expand All @@ -74,12 +103,34 @@ class BinaryExpression :

void setA(const GuiExpressionPtr& a)
{
// Disconnect from any previous signal
_aChanged.disconnect();

_a = a;

if (_a)
{
_aChanged = _a->signal_valueChanged().connect([this]()
{
signal_valueChanged().emit();
});
}
}

void setB(const GuiExpressionPtr& b)
{
// Disconnect from any previous signal
_bChanged.disconnect();

_b = b;

if (_b)
{
_bChanged = _b->signal_valueChanged().connect([this]()
{
signal_valueChanged().emit();
});
}
}

virtual std::string getStringValue() override
Expand Down Expand Up @@ -707,13 +758,13 @@ class GuiExpressionParser
GuiExpression::GuiExpression()
{}

GuiExpressionPtr GuiExpression::createFromString(IGui& gui, const std::string& exprStr)
GuiExpressionPtr GuiExpression::CreateFromString(IGui& gui, const std::string& exprStr)
{
parser::BasicDefTokeniser<std::string> tokeniser(exprStr, parser::WHITESPACE, "{}(),");
return createFromTokens(gui, tokeniser);
return CreateFromTokens(gui, tokeniser);
}

GuiExpressionPtr GuiExpression::createFromTokens(IGui& gui, parser::DefTokeniser& tokeniser)
GuiExpressionPtr GuiExpression::CreateFromTokens(IGui& gui, parser::DefTokeniser& tokeniser)
{
// Create an adapter which takes care of splitting the tokens into finer grains
// The incoming DefTokeniser is not splitting up expressions like "3*4" without any whitespace in them
Expand Down

0 comments on commit e5b215b

Please sign in to comment.