Skip to content

Commit

Permalink
#5532: More template trickery to remove the separate base templates f…
Browse files Browse the repository at this point in the history
…or MaterialPtr and IShaderLayer::Ptr bindings
  • Loading branch information
codereader committed Mar 21, 2021
1 parent 5d371ca commit a33b14b
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 113 deletions.
57 changes: 25 additions & 32 deletions radiant/ui/materials/Binding.h
Expand Up @@ -36,16 +36,38 @@ class Binding
{}
};

template<typename Source, typename Target, typename ValueType>
// Target selection, usually the Source type is identical to the target type
template<typename Source>
struct TargetSelector
{
using TargetType = Source;
};

// Specialisation for shader layer editing, where the target type is an IEditableShaderLayer
template<>
struct TargetSelector<IShaderLayer::Ptr>
{
using TargetType = IEditableShaderLayer::Ptr;
};

template<typename Source, typename ValueType>
class TwoWayBinding :
public Binding<Source>
{
public:
// Select target: will map Material => Material, but IShaderLayer => IEditableShaderLayer
using Target = typename TargetSelector<Source>::TargetType;

using LoadFunc = std::function<ValueType(const Source&)>;
using UpdateFunc = std::function<void(const Target&, ValueType)>;
using AcquireTargetFunc = std::function<Target()>;
using PostUpdateFunc = std::function<void()>;

Target UseSourceAsTarget()
{
return Binding<Source>::getSource();
}

protected:
LoadFunc _loadValue;
AcquireTargetFunc _acquireTarget;
Expand All @@ -57,9 +79,9 @@ class TwoWayBinding :

protected:
TwoWayBinding(const LoadFunc& loadValue,
const AcquireTargetFunc& acquireTarget,
const UpdateFunc& updateValue,
const PostUpdateFunc& postChangeNotify = PostUpdateFunc()) :
const PostUpdateFunc& postChangeNotify = PostUpdateFunc(),
const AcquireTargetFunc& acquireTarget = std::bind(&TwoWayBinding::UseSourceAsTarget, this)) :
_loadValue(loadValue),
_acquireTarget(acquireTarget),
_updateValue(updateValue),
Expand Down Expand Up @@ -109,35 +131,6 @@ class TwoWayBinding :
}
};

template<typename ValueType>
class TwoWayMaterialBinding :
public TwoWayBinding<MaterialPtr, MaterialPtr, ValueType>
{
public:
using BaseBinding = TwoWayBinding<MaterialPtr, MaterialPtr, ValueType>;

TwoWayMaterialBinding(const typename BaseBinding::LoadFunc& loadValue,
const typename BaseBinding::UpdateFunc& updateValue,
const typename BaseBinding::PostUpdateFunc& postChangeNotify = PostUpdateFunc()) :
BaseBinding(loadValue, [this] { return getSource(); }, updateValue, postChangeNotify)
{}
};

template<typename ValueType>
class TwoWayStageBinding :
public TwoWayBinding<IShaderLayer::Ptr, IEditableShaderLayer::Ptr, ValueType>
{
public:
using BaseBinding = TwoWayBinding<IShaderLayer::Ptr, IEditableShaderLayer::Ptr, ValueType>;

TwoWayStageBinding(const typename BaseBinding::LoadFunc& loadValue,
const typename BaseBinding::AcquireTargetFunc& acquireSaveTarget,
const typename BaseBinding::UpdateFunc& updateValue,
const typename BaseBinding::PostUpdateFunc& postChangeNotify = typename BaseBinding::PostUpdateFunc()) :
BaseBinding(loadValue, acquireSaveTarget, updateValue, postChangeNotify)
{}
};

template<typename Source>
class CheckBoxBinding :
public Binding<Source>
Expand Down
21 changes: 11 additions & 10 deletions radiant/ui/materials/ExpressionBinding.h
Expand Up @@ -7,22 +7,23 @@
namespace ui
{

template<typename Source>
class ExpressionBinding :
public TwoWayStageBinding<std::string>
public TwoWayBinding<Source, std::string>
{
public:
using BaseBinding = TwoWayBinding<Source, std::string>;

private:
wxTextCtrl* _textCtrl;
std::function<std::string(const IShaderLayer::Ptr&)> _getExpression;
std::function<void(const IEditableShaderLayer::Ptr&, const std::string&)> _updateExpression;
std::function<void()> _postChangeNotify;

public:
ExpressionBinding(wxTextCtrl* textCtrl,
const std::function<std::string(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<IEditableShaderLayer::Ptr()>& acquireSaveTarget,
const std::function<void(const IEditableShaderLayer::Ptr&, const std::string&)>& saveFunc,
const std::function<void()>& postChangeNotify = std::function<void()>()) :
TwoWayStageBinding(loadFunc, acquireSaveTarget, saveFunc, postChangeNotify),
const typename BaseBinding::LoadFunc& loadFunc,
const typename BaseBinding::AcquireTargetFunc& acquireSaveTarget,
const typename BaseBinding::UpdateFunc& saveFunc,
const typename BaseBinding::PostUpdateFunc& postChangeNotify = BaseBinding::PostUpdateFunc()) :
BaseBinding(loadFunc, saveFunc, postChangeNotify, acquireSaveTarget),
_textCtrl(textCtrl)
{
if (saveFunc)
Expand All @@ -39,7 +40,7 @@ class ExpressionBinding :

void onTextChanged(wxCommandEvent& ev)
{
updateValueOnTarget(_textCtrl->GetValue().ToStdString());
BaseBinding::updateValueOnTarget(_textCtrl->GetValue().ToStdString());
}
};

Expand Down
27 changes: 15 additions & 12 deletions radiant/ui/materials/MaterialEditor.cpp
Expand Up @@ -220,7 +220,8 @@ void MaterialEditor::setupMaterialProperties()
_materialBindings.emplace(std::make_shared<CheckBoxBinding<MaterialPtr>>(getControl<wxCheckBox>("MaterialHasSortValue"),
[](const MaterialPtr& material) { return (material->getParseFlags() & Material::PF_HasSortDefined) != 0; }));

_materialBindings.emplace(std::make_shared<SpinCtrlMaterialBinding<wxSpinCtrlDouble>>(getControl<wxSpinCtrlDouble>("MaterialPolygonOffsetValue"),
_materialBindings.emplace(std::make_shared<SpinCtrlBinding<wxSpinCtrlDouble, MaterialPtr>>(
getControl<wxSpinCtrlDouble>("MaterialPolygonOffsetValue"),
[](const MaterialPtr& material) { return material->getPolygonOffset(); },
[this](const MaterialPtr& material, const double& value)
{
Expand All @@ -245,7 +246,9 @@ void MaterialEditor::setupMaterialProperties()
_material->setLightFalloffCubeMapType(shaders::getMapTypeForString(lightFallOffCubeMapType->GetStringSelection().ToStdString()));
});

_materialBindings.emplace(std::make_shared<SpinCtrlMaterialBinding<wxSpinCtrl>>(getControl<wxSpinCtrl>("MaterialSpectrumValue"),
// TODO: Lightfalloffimage binding

_materialBindings.emplace(std::make_shared<SpinCtrlBinding<wxSpinCtrl, MaterialPtr>>(getControl<wxSpinCtrl>("MaterialSpectrumValue"),
[](const MaterialPtr& material) { return material->getSpectrum(); },
[this](const MaterialPtr& material, const int& value)
{
Expand Down Expand Up @@ -456,7 +459,7 @@ void MaterialEditor::createExpressionBinding(const std::string& textCtrlName,
const std::function<shaders::IShaderExpression::Ptr(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<void(const IEditableShaderLayer::Ptr&, const std::string&)>& saveFunc)
{
_stageBindings.emplace(std::make_shared<ExpressionBinding>(
_stageBindings.emplace(std::make_shared<ExpressionBinding<IShaderLayer::Ptr>>(
getControl<wxTextCtrl>(textCtrlName),
[loadFunc] (const IShaderLayer::Ptr& layer)
{
Expand All @@ -472,36 +475,36 @@ void MaterialEditor::createRadioButtonBinding(const std::string& ctrlName,
const std::function<bool(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<void(const IEditableShaderLayer::Ptr&, bool)>& saveFunc)
{
_stageBindings.emplace(std::make_shared<RadioButtonBinding>(
_stageBindings.emplace(std::make_shared<RadioButtonBinding<IShaderLayer::Ptr>>(
getControl<wxRadioButton>(ctrlName),
loadFunc,
std::bind(&MaterialEditor::getEditableStageForSelection, this),
saveFunc,
std::bind(&MaterialEditor::onMaterialChanged, this)));
std::bind(&MaterialEditor::onMaterialChanged, this),
std::bind(&MaterialEditor::getEditableStageForSelection, this)));
}

void MaterialEditor::createSpinCtrlBinding(const std::string& ctrlName,
const std::function<int(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<void(const IEditableShaderLayer::Ptr&, int)>& saveFunc)
{
_stageBindings.emplace(std::make_shared<SpinCtrlStageBinding<wxSpinCtrl>>(
_stageBindings.emplace(std::make_shared<SpinCtrlBinding<wxSpinCtrl, IShaderLayer::Ptr>>(
getControl<wxSpinCtrl>(ctrlName),
loadFunc,
std::bind(&MaterialEditor::getEditableStageForSelection, this),
saveFunc,
std::bind(&MaterialEditor::onMaterialChanged, this)));
std::bind(&MaterialEditor::onMaterialChanged, this),
std::bind(&MaterialEditor::getEditableStageForSelection, this)));
}

void MaterialEditor::createSpinCtrlDoubleBinding(const std::string& ctrlName,
const std::function<double(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<void(const IEditableShaderLayer::Ptr&, double)>& saveFunc)
{
_stageBindings.emplace(std::make_shared<SpinCtrlStageBinding<wxSpinCtrlDouble>>(
_stageBindings.emplace(std::make_shared<SpinCtrlBinding<wxSpinCtrlDouble, IShaderLayer::Ptr>>(
getControl<wxSpinCtrlDouble>(ctrlName),
loadFunc,
std::bind(&MaterialEditor::getEditableStageForSelection, this),
saveFunc,
std::bind(&MaterialEditor::onMaterialChanged, this)));
std::bind(&MaterialEditor::onMaterialChanged, this),
std::bind(&MaterialEditor::getEditableStageForSelection, this)));
}

void MaterialEditor::setupMaterialStageProperties()
Expand Down
18 changes: 11 additions & 7 deletions radiant/ui/materials/RadioButtonBinding.h
Expand Up @@ -7,19 +7,23 @@
namespace ui
{

template<typename Source>
class RadioButtonBinding :
public TwoWayStageBinding<bool>
public TwoWayBinding<Source, bool>
{
public:
using BaseBinding = TwoWayBinding<Source, bool>;

private:
wxRadioButton* _radioButton;

public:
RadioButtonBinding(wxRadioButton* radioButton,
const std::function<bool(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<IEditableShaderLayer::Ptr()>& acquireSaveTarget,
const std::function<void(const IEditableShaderLayer::Ptr&, bool)>& saveFunc,
const std::function<void()>& postChangeNotify = std::function<void()>()) :
TwoWayStageBinding(loadFunc, acquireSaveTarget, saveFunc, postChangeNotify),
const typename BaseBinding::LoadFunc& loadFunc,
const typename BaseBinding::UpdateFunc& saveFunc,
const typename BaseBinding::PostUpdateFunc& postChangeNotify = BaseBinding::PostUpdateFunc(),
const typename BaseBinding::AcquireTargetFunc& acquireSaveTarget = BaseBinding::UseSourceAsTarget) :
BaseBinding(loadFunc, saveFunc, postChangeNotify, acquireSaveTarget),
_radioButton(radioButton)
{
if (saveFunc)
Expand All @@ -36,7 +40,7 @@ class RadioButtonBinding :

void onValueChanged(wxCommandEvent& ev)
{
updateValueOnTarget(_radioButton->GetValue());
BaseBinding::updateValueOnTarget(_radioButton->GetValue());
}
};

Expand Down
79 changes: 27 additions & 52 deletions radiant/ui/materials/SpinCtrlBinding.h
Expand Up @@ -6,73 +6,48 @@
namespace ui
{

template<typename SpinCtrlType>
class SpinCtrlMaterialBinding :
public TwoWayMaterialBinding<decltype(std::declval<SpinCtrlType>().GetValue())>
template<typename SpinCtrlType, typename Source>
class SpinCtrlBinding :
public TwoWayBinding<Source, decltype(std::declval<SpinCtrlType>().GetValue())>
{
private:
SpinCtrlType* _spinCtrl;
using ValueType = decltype(std::declval<SpinCtrlType>().GetValue());

public:
SpinCtrlMaterialBinding(SpinCtrlType* spinCtrl,
const std::function<ValueType(const MaterialPtr&)>& loadFunc,
const std::function<void(const MaterialPtr&, ValueType)>& saveFunc,
const std::function<void()>& postChangeNotify = std::function<void()>()) :
TwoWayMaterialBinding<ValueType>(loadFunc, saveFunc, postChangeNotify),
_spinCtrl(spinCtrl)
{
if (saveFunc)
{
if (std::is_integral<ValueType>::value)
{
_spinCtrl->Bind(wxEVT_SPINCTRL, &SpinCtrlMaterialBinding::onValueChanged, this);
}
else
{
_spinCtrl->Bind(wxEVT_SPINCTRLDOUBLE, &SpinCtrlMaterialBinding::onValueChanged, this);
}
}
}

protected:
void setValueOnControl(const ValueType& value) override
{
_spinCtrl->SetValue(value);
}

void onValueChanged(wxCommandEvent& ev)
{
TwoWayMaterialBinding<ValueType>::updateValueOnTarget(_spinCtrl->GetValue());
}
};
using ValueType = decltype(std::declval<SpinCtrlType>().GetValue());
using BaseBinding = TwoWayBinding<Source, ValueType>;

template<typename SpinCtrlType>
class SpinCtrlStageBinding :
public TwoWayStageBinding<decltype(std::declval<SpinCtrlType>().GetValue())>
{
private:
SpinCtrlType* _spinCtrl;
using ValueType = decltype(std::declval<SpinCtrlType>().GetValue());

public:
SpinCtrlStageBinding(SpinCtrlType* spinCtrl,
const std::function<ValueType(const IShaderLayer::Ptr&)>& loadFunc,
const std::function<IEditableShaderLayer::Ptr()>& acquireSaveTarget,
const std::function<void(const IEditableShaderLayer::Ptr&, ValueType)>& saveFunc,
const std::function<void()>& postChangeNotify = std::function<void()>()) :
TwoWayStageBinding<ValueType>(loadFunc, acquireSaveTarget, saveFunc, postChangeNotify),
SpinCtrlBinding(SpinCtrlType* spinCtrl,
const typename BaseBinding::LoadFunc& loadFunc,
const typename BaseBinding::UpdateFunc& saveFunc) :
SpinCtrlBinding(spinCtrl, loadFunc, saveFunc, BaseBinding::PostUpdateFunc())
{}

SpinCtrlBinding(SpinCtrlType* spinCtrl,
const typename BaseBinding::LoadFunc& loadFunc,
const typename BaseBinding::UpdateFunc& saveFunc,
const typename BaseBinding::PostUpdateFunc& postChangeNotify) :
SpinCtrlBinding(spinCtrl, loadFunc, saveFunc, postChangeNotify, std::bind(&BaseBinding::UseSourceAsTarget, this))
{}

SpinCtrlBinding(SpinCtrlType* spinCtrl,
const typename BaseBinding::LoadFunc& loadFunc,
const typename BaseBinding::UpdateFunc& saveFunc,
const typename BaseBinding::PostUpdateFunc& postChangeNotify,
const typename BaseBinding::AcquireTargetFunc& acquireSaveTarget) :
BaseBinding(loadFunc, saveFunc, postChangeNotify, acquireSaveTarget),
_spinCtrl(spinCtrl)
{
if (saveFunc)
{
if (std::is_integral<ValueType>::value)
{
_spinCtrl->Bind(wxEVT_SPINCTRL, &SpinCtrlStageBinding::onValueChanged, this);
_spinCtrl->Bind(wxEVT_SPINCTRL, &SpinCtrlBinding::onValueChanged, this);
}
else
{
_spinCtrl->Bind(wxEVT_SPINCTRLDOUBLE, &SpinCtrlStageBinding::onValueChanged, this);
_spinCtrl->Bind(wxEVT_SPINCTRLDOUBLE, &SpinCtrlBinding::onValueChanged, this);
}
}
}
Expand All @@ -85,7 +60,7 @@ class SpinCtrlStageBinding :

void onValueChanged(wxCommandEvent& ev)
{
TwoWayStageBinding<ValueType>::updateValueOnTarget(_spinCtrl->GetValue());
BaseBinding::updateValueOnTarget(_spinCtrl->GetValue());
}
};

Expand Down

0 comments on commit a33b14b

Please sign in to comment.