diff --git a/etc/Icons/Decrement.svg b/etc/Icons/Decrement.svg
new file mode 100644
index 000000000..6ba0c10ae
--- /dev/null
+++ b/etc/Icons/Decrement.svg
@@ -0,0 +1,78 @@
+
+
+
+
diff --git a/etc/Icons/Increment.svg b/etc/Icons/Increment.svg
new file mode 100644
index 000000000..a8b055d14
--- /dev/null
+++ b/etc/Icons/Increment.svg
@@ -0,0 +1,78 @@
+
+
+
+
diff --git a/lib/tlUI/CMakeLists.txt b/lib/tlUI/CMakeLists.txt
index 7a9c2b635..aa45ace46 100644
--- a/lib/tlUI/CMakeLists.txt
+++ b/lib/tlUI/CMakeLists.txt
@@ -15,6 +15,7 @@ set(HEADERS
IWidgetInline.h
IWidgetOptions.h
IconLibrary.h
+ IncButton.h
IntEdit.h
IntModel.h
IntSlider.h
@@ -57,6 +58,7 @@ set(SOURCE
IWidget.cpp
IWidgetOptions.cpp
IconLibrary.cpp
+ IncButton.cpp
IntEdit.cpp
IntModel.cpp
IntSlider.cpp
diff --git a/lib/tlUI/FloatEdit.cpp b/lib/tlUI/FloatEdit.cpp
index e10207a67..cdb6a4cbb 100644
--- a/lib/tlUI/FloatEdit.cpp
+++ b/lib/tlUI/FloatEdit.cpp
@@ -4,6 +4,9 @@
#include
+#include
+#include
+
#include
namespace tl
@@ -13,6 +16,9 @@ namespace tl
struct FloatEdit::Private
{
std::shared_ptr model;
+ std::shared_ptr lineEdit;
+ std::shared_ptr incrementButton;
+ std::shared_ptr decrementButton;
int digits = 3;
int precision = 2;
@@ -24,13 +30,16 @@ namespace tl
const std::shared_ptr& context,
const std::shared_ptr& parent)
{
- LineEdit::_init(context, parent);
- _name = "tl::ui::FloatEdit";
+ IWidget::_init("tl::ui::FloatEdit", context, parent);
TLRENDER_P();
+ p.lineEdit = LineEdit::create(context, shared_from_this());
+ p.incrementButton = IncButton::create(context, shared_from_this());
+ p.decrementButton = IncButton::create(context, shared_from_this());
+
setModel(FloatModel::create(context));
- _floatUpdate();
+ _textUpdate();
}
FloatEdit::FloatEdit() :
@@ -66,16 +75,16 @@ namespace tl
p.model->observeValue(),
[this](float)
{
- _floatUpdate();
+ _textUpdate();
});
p.rangeObserver = observer::ValueObserver::create(
p.model->observeRange(),
[this](const math::FloatRange&)
{
- _floatUpdate();
+ _textUpdate();
});
}
- _floatUpdate();
+ _textUpdate();
}
void FloatEdit::setDigits(int value)
@@ -84,7 +93,7 @@ namespace tl
if (value == p.digits)
return;
p.digits = value;
- _floatUpdate();
+ _textUpdate();
}
void FloatEdit::setPrecision(int value)
@@ -93,44 +102,45 @@ namespace tl
if (value == p.precision)
return;
p.precision = value;
- _floatUpdate();
+ _textUpdate();
+ }
+
+ void FloatEdit::setFontRole(FontRole value)
+ {
+ _p->lineEdit->setFontRole(value);
}
- void FloatEdit::keyPressEvent(KeyEvent& event)
+ void FloatEdit::setGeometry(const math::BBox2i& value)
{
- LineEdit::keyPressEvent(event);
+ IWidget::setGeometry(value);
TLRENDER_P();
- if (!event.accept)
- {
- switch (event.key)
- {
- case Key::Down:
- event.accept = true;
- p.model->subtractStep();
- break;
- case Key::Up:
- event.accept = true;
- p.model->addStep();
- break;
- case Key::PageUp:
- event.accept = true;
- p.model->addLargeStep();
- break;
- case Key::PageDown:
- event.accept = true;
- p.model->subtractLargeStep();
- break;
- }
- }
+ math::BBox2i g = value;
+ const int buttonsWidth = std::max(
+ p.incrementButton->getSizeHint().x,
+ p.decrementButton->getSizeHint().x);
+ g.max.x -= buttonsWidth;
+ p.lineEdit->setGeometry(g);
+ g = value;
+ g.min.x = g.max.x - buttonsWidth;
+ g.max.y = g.min.y + g.h() / 2;
+ p.incrementButton->setGeometry(g);
+ g.min.y = g.max.y;
+ g.max.y = value.max.y;
+ p.decrementButton->setGeometry(g);
}
- void FloatEdit::keyReleaseEvent(KeyEvent& event)
+ void FloatEdit::sizeHintEvent(const SizeHintEvent& event)
{
- LineEdit::keyPressEvent(event);
- event.accept = true;
+ IWidget::sizeHintEvent(event);
+ TLRENDER_P();
+ _sizeHint = p.lineEdit->getSizeHint();
+ const int buttonsWidth = std::max(
+ p.incrementButton->getSizeHint().x,
+ p.decrementButton->getSizeHint().x);
+ _sizeHint.x += buttonsWidth;
}
- void FloatEdit::_floatUpdate()
+ void FloatEdit::_textUpdate()
{
TLRENDER_P();
std::string text;
@@ -143,8 +153,8 @@ namespace tl
arg(range.getMin() < 0 ? "-" : "").
arg(0.F, p.precision, p.precision + 1 + p.digits);
}
- setText(text);
- setFormat(format);
+ p.lineEdit->setText(text);
+ p.lineEdit->setFormat(format);
}
}
}
diff --git a/lib/tlUI/FloatEdit.h b/lib/tlUI/FloatEdit.h
index cc9af0d86..aefbd316b 100644
--- a/lib/tlUI/FloatEdit.h
+++ b/lib/tlUI/FloatEdit.h
@@ -4,7 +4,7 @@
#pragma once
-#include
+#include
#include
namespace tl
@@ -12,7 +12,7 @@ namespace tl
namespace ui
{
//! Floating point number editor.
- class FloatEdit : public LineEdit
+ class FloatEdit : public IWidget
{
TLRENDER_NON_COPYABLE(FloatEdit);
@@ -43,11 +43,14 @@ namespace tl
//! Set the display precision.
void setPrecision(int);
- void keyPressEvent(KeyEvent&) override;
- void keyReleaseEvent(KeyEvent&) override;
+ //! Set the font role.
+ void setFontRole(FontRole);
+
+ void setGeometry(const math::BBox2i&) override;
+ void sizeHintEvent(const SizeHintEvent&) override;
private:
- void _floatUpdate();
+ void _textUpdate();
TLRENDER_PRIVATE();
};
diff --git a/lib/tlUI/FloatModel.cpp b/lib/tlUI/FloatModel.cpp
index 14eb19d8e..5fb5dbb63 100644
--- a/lib/tlUI/FloatModel.cpp
+++ b/lib/tlUI/FloatModel.cpp
@@ -87,13 +87,13 @@ namespace tl
_p->step = value;
}
- void FloatModel::addStep()
+ void FloatModel::incrementStep()
{
TLRENDER_P();
setValue(p.value->get() + p.step);
}
- void FloatModel::subtractStep()
+ void FloatModel::decrementStep()
{
TLRENDER_P();
setValue(p.value->get() - p.step);
@@ -109,13 +109,13 @@ namespace tl
_p->largeStep = value;
}
- void FloatModel::addLargeStep()
+ void FloatModel::incrementLargeStep()
{
TLRENDER_P();
setValue(p.value->get() + p.largeStep);
}
- void FloatModel::subtractLargeStep()
+ void FloatModel::decrementLargeStep()
{
TLRENDER_P();
setValue(p.value->get() - p.largeStep);
diff --git a/lib/tlUI/FloatModel.h b/lib/tlUI/FloatModel.h
index 4079ef2eb..2d9d5cd23 100644
--- a/lib/tlUI/FloatModel.h
+++ b/lib/tlUI/FloatModel.h
@@ -58,15 +58,15 @@ namespace tl
void setStep(float);
- void addStep();
- void subtractStep();
+ void incrementStep();
+ void decrementStep();
float getLargeStep() const;
void setLargeStep(float);
- void addLargeStep();
- void subtractLargeStep();
+ void incrementLargeStep();
+ void decrementLargeStep();
///@}
diff --git a/lib/tlUI/FloatSlider.cpp b/lib/tlUI/FloatSlider.cpp
index e25b36f35..11f69060d 100644
--- a/lib/tlUI/FloatSlider.cpp
+++ b/lib/tlUI/FloatSlider.cpp
@@ -223,20 +223,20 @@ namespace tl
case Key::Left:
case Key::Down:
event.accept = true;
- p.model->subtractStep();
+ p.model->decrementStep();
break;
case Key::Right:
case Key::Up:
event.accept = true;
- p.model->addStep();
+ p.model->incrementStep();
break;
case Key::PageUp:
event.accept = true;
- p.model->addLargeStep();
+ p.model->incrementLargeStep();
break;
case Key::PageDown:
event.accept = true;
- p.model->subtractLargeStep();
+ p.model->decrementLargeStep();
break;
case Key::End:
event.accept = true;
diff --git a/lib/tlUI/IconLibrary.cpp b/lib/tlUI/IconLibrary.cpp
index 103d0a548..fd2872222 100644
--- a/lib/tlUI/IconLibrary.cpp
+++ b/lib/tlUI/IconLibrary.cpp
@@ -40,6 +40,8 @@ namespace
#include "Resources/CompareWipe_96.h"
#include "Resources/Copy_192.h"
#include "Resources/Copy_96.h"
+#include "Resources/Decrement_192.h"
+#include "Resources/Decrement_96.h"
#include "Resources/Devices_192.h"
#include "Resources/Devices_96.h"
#include "Resources/DockWidgetClose_192.h"
@@ -64,6 +66,8 @@ namespace
#include "Resources/FrameNext_96.h"
#include "Resources/FramePrev_192.h"
#include "Resources/FramePrev_96.h"
+#include "Resources/Increment_192.h"
+#include "Resources/Increment_96.h"
#include "Resources/Info_192.h"
#include "Resources/Info_96.h"
#include "Resources/Messages_192.h"
@@ -161,6 +165,7 @@ namespace tl
p.iconData["CompareVertical_96.png"] = CompareVertical_96_png;
p.iconData["CompareWipe_96.png"] = CompareWipe_96_png;
p.iconData["Copy_96.png"] = Copy_96_png;
+ p.iconData["Decrement_96.png"] = Decrement_96_png;
p.iconData["Devices_96.png"] = Devices_96_png;
p.iconData["DockWidgetClose_96.png"] = DockWidgetClose_96_png;
p.iconData["DockWidgetNormal_96.png"] = DockWidgetNormal_96_png;
@@ -173,6 +178,7 @@ namespace tl
p.iconData["Files_96.png"] = Files_96_png;
p.iconData["FrameNext_96.png"] = FrameNext_96_png;
p.iconData["FramePrev_96.png"] = FramePrev_96_png;
+ p.iconData["Increment_96.png"] = Increment_96_png;
p.iconData["Info_96.png"] = Info_96_png;
p.iconData["Messages_96.png"] = Messages_96_png;
p.iconData["Mute_96.png"] = Mute_96_png;
@@ -206,6 +212,7 @@ namespace tl
p.iconData["CompareVertical_192.png"] = CompareVertical_192_png;
p.iconData["CompareWipe_192.png"] = CompareWipe_192_png;
p.iconData["Copy_192.png"] = Copy_192_png;
+ p.iconData["Decrement_192.png"] = Decrement_192_png;
p.iconData["Devices_192.png"] = Devices_192_png;
p.iconData["DockWidgetClose_192.png"] = DockWidgetClose_192_png;
p.iconData["DockWidgetNormal_192.png"] = DockWidgetNormal_192_png;
@@ -218,6 +225,7 @@ namespace tl
p.iconData["Files_192.png"] = Files_192_png;
p.iconData["FrameNext_192.png"] = FrameNext_192_png;
p.iconData["FramePrev_192.png"] = FramePrev_192_png;
+ p.iconData["Increment_192.png"] = Increment_192_png;
p.iconData["Info_192.png"] = Info_192_png;
p.iconData["Messages_192.png"] = Messages_192_png;
p.iconData["Mute_192.png"] = Mute_192_png;
diff --git a/lib/tlUI/IncButton.cpp b/lib/tlUI/IncButton.cpp
new file mode 100644
index 000000000..bf583b040
--- /dev/null
+++ b/lib/tlUI/IncButton.cpp
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright (c) 2021-2023 Darby Johnston
+// All rights reserved.
+
+#include
+
+namespace tl
+{
+ namespace ui
+ {
+ struct IncButton::Private
+ {
+ struct SizeData
+ {
+ int margin = 0;
+ };
+ SizeData size;
+ };
+
+ void IncButton::_init(
+ const std::shared_ptr& context,
+ const std::shared_ptr& parent)
+ {
+ IButton::_init("tl::ui::IncButton", context, parent);
+ }
+
+ IncButton::IncButton() :
+ _p(new Private)
+ {}
+
+ IncButton::~IncButton()
+ {}
+
+ std::shared_ptr IncButton::create(
+ const std::shared_ptr& context,
+ const std::shared_ptr& parent)
+ {
+ auto out = std::shared_ptr(new IncButton);
+ out->_init(context, parent);
+ return out;
+ }
+
+ void IncButton::sizeHintEvent(const SizeHintEvent& event)
+ {
+ IButton::sizeHintEvent(event);
+ TLRENDER_P();
+
+ p.size.margin = event.style->getSizeRole(SizeRole::MarginInside, event.displayScale);
+
+ _sizeHint = math::Vector2i();
+ if (_iconImage)
+ {
+ _sizeHint.x = _iconImage->getWidth();
+ _sizeHint.y = _iconImage->getHeight();
+ }
+ _sizeHint.x += p.size.margin * 2;
+ _sizeHint.y += p.size.margin * 2;
+ }
+
+ void IncButton::drawEvent(const DrawEvent& event)
+ {
+ IButton::drawEvent(event);
+ TLRENDER_P();
+
+ const math::BBox2i g = _geometry;
+
+ const ColorRole colorRole = _checked ?
+ ColorRole::Checked :
+ _buttonRole;
+ if (colorRole != ColorRole::None)
+ {
+ event.render->drawRect(
+ g,
+ event.style->getColorRole(colorRole));
+ }
+
+ if (_pressed && _geometry.contains(_cursorPos))
+ {
+ event.render->drawRect(
+ g,
+ event.style->getColorRole(ColorRole::Pressed));
+ }
+ else if (_inside)
+ {
+ event.render->drawRect(
+ g,
+ event.style->getColorRole(ColorRole::Hover));
+ }
+
+ int x = g.x() + p.size.margin;
+ if (_iconImage)
+ {
+ const auto iconSize = _iconImage->getSize();
+ event.render->drawImage(
+ _iconImage,
+ math::BBox2i(
+ x,
+ g.y() + g.h() / 2 - iconSize.h / 2,
+ iconSize.w,
+ iconSize.h));
+ }
+ }
+ }
+}
diff --git a/lib/tlUI/IncButton.h b/lib/tlUI/IncButton.h
new file mode 100644
index 000000000..a68749f95
--- /dev/null
+++ b/lib/tlUI/IncButton.h
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Copyright (c) 2021-2023 Darby Johnston
+// All rights reserved.
+
+#pragma once
+
+#include
+
+namespace tl
+{
+ namespace ui
+ {
+ //! Numeric widget increment button.
+ class IncButton : public IButton
+ {
+ TLRENDER_NON_COPYABLE(IncButton);
+
+ protected:
+ void _init(
+ const std::shared_ptr&,
+ const std::shared_ptr& parent = nullptr);
+
+ IncButton();
+
+ public:
+ ~IncButton() override;
+
+ //! Create a new increment button.
+ static std::shared_ptr create(
+ const std::shared_ptr&,
+ const std::shared_ptr& parent = nullptr);
+
+ void sizeHintEvent(const SizeHintEvent&) override;
+ void drawEvent(const DrawEvent&) override;
+
+ private:
+ TLRENDER_PRIVATE();
+ };
+ }
+}
diff --git a/lib/tlUI/IntEdit.cpp b/lib/tlUI/IntEdit.cpp
index 8895809da..749d02a84 100644
--- a/lib/tlUI/IntEdit.cpp
+++ b/lib/tlUI/IntEdit.cpp
@@ -4,6 +4,8 @@
#include
+#include
+
#include
namespace tl
@@ -13,6 +15,7 @@ namespace tl
struct IntEdit::Private
{
std::shared_ptr model;
+ std::shared_ptr lineEdit;
int digits = 3;
std::shared_ptr > valueObserver;
@@ -23,13 +26,14 @@ namespace tl
const std::shared_ptr& context,
const std::shared_ptr& parent)
{
- LineEdit::_init(context, parent);
- _name = "tl::ui::IntEdit";
+ IWidget::_init("tl::ui::IntEdit", context, parent);
TLRENDER_P();
+ p.lineEdit = LineEdit::create(context, shared_from_this());
+
setModel(IntModel::create(context));
- _intUpdate();
+ _textUpdate();
}
IntEdit::IntEdit() :
@@ -65,16 +69,16 @@ namespace tl
p.model->observeValue(),
[this](int)
{
- _intUpdate();
+ _textUpdate();
});
p.rangeObserver = observer::ValueObserver::create(
p.model->observeRange(),
[this](const math::IntRange&)
{
- _intUpdate();
+ _textUpdate();
});
}
- _intUpdate();
+ _textUpdate();
}
void IntEdit::setDigits(int value)
@@ -83,44 +87,27 @@ namespace tl
if (value == p.digits)
return;
p.digits = value;
- _intUpdate();
+ _textUpdate();
}
- void IntEdit::keyPressEvent(KeyEvent& event)
+ void IntEdit::setFontRole(FontRole value)
{
- LineEdit::keyPressEvent(event);
- TLRENDER_P();
- if (!event.accept)
- {
- switch (event.key)
- {
- case Key::Down:
- event.accept = true;
- p.model->subtractStep();
- break;
- case Key::Up:
- event.accept = true;
- p.model->addStep();
- break;
- case Key::PageUp:
- event.accept = true;
- p.model->addLargeStep();
- break;
- case Key::PageDown:
- event.accept = true;
- p.model->subtractLargeStep();
- break;
- }
- }
+ _p->lineEdit->setFontRole(value);
+ }
+
+ void IntEdit::setGeometry(const math::BBox2i& value)
+ {
+ IWidget::setGeometry(value);
+ _p->lineEdit->setGeometry(value);
}
- void IntEdit::keyReleaseEvent(KeyEvent& event)
+ void IntEdit::sizeHintEvent(const SizeHintEvent& event)
{
- LineEdit::keyPressEvent(event);
- event.accept = true;
+ IWidget::sizeHintEvent(event);
+ _sizeHint = _p->lineEdit->getSizeHint();
}
- void IntEdit::_intUpdate()
+ void IntEdit::_textUpdate()
{
TLRENDER_P();
std::string text;
@@ -133,8 +120,8 @@ namespace tl
arg(range.getMin() < 0 ? "-" : "").
arg(0, p.digits);
}
- setText(text);
- setFormat(format);
+ p.lineEdit->setText(text);
+ p.lineEdit->setFormat(format);
}
}
}
diff --git a/lib/tlUI/IntEdit.h b/lib/tlUI/IntEdit.h
index a524593c5..761cbda78 100644
--- a/lib/tlUI/IntEdit.h
+++ b/lib/tlUI/IntEdit.h
@@ -4,7 +4,7 @@
#pragma once
-#include
+#include
#include
namespace tl
@@ -12,7 +12,7 @@ namespace tl
namespace ui
{
//! Integer number editor.
- class IntEdit : public LineEdit
+ class IntEdit : public IWidget
{
TLRENDER_NON_COPYABLE(IntEdit);
@@ -40,11 +40,14 @@ namespace tl
//! Set the number of digits to display.
void setDigits(int);
- void keyPressEvent(KeyEvent&) override;
- void keyReleaseEvent(KeyEvent&) override;
+ //! Set the font role.
+ void setFontRole(FontRole);
+
+ void setGeometry(const math::BBox2i&) override;
+ void sizeHintEvent(const SizeHintEvent&) override;
private:
- void _intUpdate();
+ void _textUpdate();
TLRENDER_PRIVATE();
};
diff --git a/lib/tlUI/IntModel.cpp b/lib/tlUI/IntModel.cpp
index 5908c9770..aad97917e 100644
--- a/lib/tlUI/IntModel.cpp
+++ b/lib/tlUI/IntModel.cpp
@@ -87,13 +87,13 @@ namespace tl
_p->step = value;
}
- void IntModel::addStep()
+ void IntModel::incrementStep()
{
TLRENDER_P();
setValue(p.value->get() + p.step);
}
- void IntModel::subtractStep()
+ void IntModel::decrementStep()
{
TLRENDER_P();
setValue(p.value->get() - p.step);
@@ -109,13 +109,13 @@ namespace tl
_p->largeStep = value;
}
- void IntModel::addLargeStep()
+ void IntModel::incrementLargeStep()
{
TLRENDER_P();
setValue(p.value->get() + p.largeStep);
}
- void IntModel::subtractLargeStep()
+ void IntModel::decrementLargeStep()
{
TLRENDER_P();
setValue(p.value->get() - p.largeStep);
diff --git a/lib/tlUI/IntModel.h b/lib/tlUI/IntModel.h
index 1c0d3db81..f4264cdf6 100644
--- a/lib/tlUI/IntModel.h
+++ b/lib/tlUI/IntModel.h
@@ -58,15 +58,15 @@ namespace tl
void setStep(int);
- void addStep();
- void subtractStep();
+ void incrementStep();
+ void decrementStep();
int getLargeStep() const;
void setLargeStep(int);
- void addLargeStep();
- void subtractLargeStep();
+ void incrementLargeStep();
+ void decrementLargeStep();
///@}
diff --git a/lib/tlUI/IntSlider.cpp b/lib/tlUI/IntSlider.cpp
index 1fad0f5fc..a33fff8a7 100644
--- a/lib/tlUI/IntSlider.cpp
+++ b/lib/tlUI/IntSlider.cpp
@@ -223,20 +223,20 @@ namespace tl
case Key::Left:
case Key::Down:
event.accept = true;
- p.model->subtractStep();
+ p.model->decrementStep();
break;
case Key::Right:
case Key::Up:
event.accept = true;
- p.model->addStep();
+ p.model->incrementStep();
break;
case Key::PageUp:
event.accept = true;
- p.model->addLargeStep();
+ p.model->incrementLargeStep();
break;
case Key::PageDown:
event.accept = true;
- p.model->subtractLargeStep();
+ p.model->decrementLargeStep();
break;
case Key::End:
event.accept = true;