aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CruUI/ui/control.cpp12
-rw-r--r--CruUI/ui/control.h15
-rw-r--r--CruUI/ui/controls/text_block.cpp73
-rw-r--r--CruUI/ui/controls/text_block.h19
4 files changed, 113 insertions, 6 deletions
diff --git a/CruUI/ui/control.cpp b/CruUI/ui/control.cpp
index ac338e95..20aeb900 100644
--- a/CruUI/ui/control.cpp
+++ b/CruUI/ui/control.cpp
@@ -9,7 +9,8 @@ namespace cru {
namespace ui {
using namespace events;
- Control::Control() :
+ Control::Control(bool container) :
+ is_container_(container),
window_(nullptr),
parent_(nullptr),
children_(),
@@ -26,12 +27,14 @@ namespace cru {
void Control::ForeachChild(Action<Control*>&& predicate) const
{
+ ThrowIfNotContainer();
for (const auto child : children_)
predicate(child);
}
void Control::ForeachChild(FlowControlAction<Control*>&& predicate) const
{
+ ThrowIfNotContainer();
for (const auto child : children_)
{
if (predicate(child) == FlowControl::Break)
@@ -50,6 +53,7 @@ namespace cru {
void Control::AddChild(Control* control)
{
+ ThrowIfNotContainer();
AddChildCheck(control);
this->children_.push_back(control);
@@ -61,6 +65,7 @@ namespace cru {
void Control::AddChild(Control* control, int position)
{
+ ThrowIfNotContainer();
AddChildCheck(control);
if (position < 0 || static_cast<decltype(this->children_.size())>(position) > this->children_.size())
@@ -75,6 +80,7 @@ namespace cru {
void Control::RemoveChild(Control* child)
{
+ ThrowIfNotContainer();
const auto i = std::find(this->children_.cbegin(), this->children_.cend(), child);
if (i == this->children_.cend())
throw std::invalid_argument("The argument child is not a child of this control.");
@@ -88,6 +94,7 @@ namespace cru {
void Control::RemoveChild(const int position)
{
+ ThrowIfNotContainer();
if (position < 0 || static_cast<decltype(this->children_.size())>(position) >= this->children_.size())
throw std::invalid_argument("The position is out of range.");
@@ -123,6 +130,7 @@ namespace cru {
void Control::TraverseDescendants(Action<Control*>&& predicate)
{
+ ThrowIfNotContainer();
TraverseDescendantsInternal(this, predicate);
}
@@ -401,7 +409,7 @@ namespace cru {
}
};
- Size size_for_children{};
+ Size size_for_children;
size_for_children.width = get_available_length_for_child(layout_params->width, available_size.width);
size_for_children.height = get_available_length_for_child(layout_params->height, available_size.height);
diff --git a/CruUI/ui/control.h b/CruUI/ui/control.h
index ee6abe12..b9dccf19 100644
--- a/CruUI/ui/control.h
+++ b/CruUI/ui/control.h
@@ -29,7 +29,7 @@ namespace cru
friend class Window;
friend class WindowLayoutManager;
protected:
- Control();
+ explicit Control(bool container = false);
public:
Control(const Control& other) = delete;
@@ -42,6 +42,11 @@ namespace cru
//*************** region: tree ***************
+ bool IsContainer() const
+ {
+ return is_container_;
+ }
+
//Get parent of control, return nullptr if it has no parent.
Control* GetParent() const
{
@@ -235,7 +240,15 @@ namespace cru
// be done.
void CheckAndNotifyPositionChanged();
+ void ThrowIfNotContainer() const
+ {
+ if (!is_container_)
+ throw std::runtime_error("You can't perform such operation on a non-container control.");
+ }
+
private:
+ bool is_container_;
+
Window * window_;
Control * parent_;
diff --git a/CruUI/ui/controls/text_block.cpp b/CruUI/ui/controls/text_block.cpp
index a3d7577f..05eb775e 100644
--- a/CruUI/ui/controls/text_block.cpp
+++ b/CruUI/ui/controls/text_block.cpp
@@ -10,6 +10,11 @@ namespace cru
{
namespace controls
{
+ inline Microsoft::WRL::ComPtr<IDWriteFactory> GetDWriteFactory()
+ {
+ return graph::GraphManager::GetInstance()->GetDWriteFactory();
+ }
+
TextBlock::TextBlock(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format,
const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush)
{
@@ -53,8 +58,65 @@ namespace cru
Size TextBlock::OnMeasure(const Size& available_size)
{
+ if (text_.empty())
+ return Size::zero;
+
+ const auto layout_params = GetLayoutParams();
+
+
+ if (layout_params->width.mode == MeasureMode::Stretch && layout_params->height.mode == MeasureMode::Stretch)
+ return available_size;
+
+ Size measure_size;
+
+ auto&& get_measure_length = [](const MeasureLength& layout_length, const float available_length) -> float
+ {
+ switch (layout_length.mode)
+ {
+ case MeasureMode::Exactly:
+ {
+ return std::min(layout_length.length, available_length);
+ }
+ case MeasureMode::Stretch:
+ case MeasureMode::Content:
+ {
+ return available_length;
+ }
+ default:
+ UnreachableCode();
+ }
+ };
+
+ measure_size.width = get_measure_length(layout_params->width, available_size.width);
+ measure_size.height = get_measure_length(layout_params->height, available_size.height);
- //TODO!
+
+ Microsoft::WRL::ComPtr<IDWriteTextLayout> measure_text_layout;
+
+ const auto dwrite_factory = GetDWriteFactory();
+
+ dwrite_factory->CreateTextLayout(text_.c_str(), text_.size(),
+ text_format_.Get(), measure_size.width, measure_size.height, &measure_text_layout);
+
+ DWRITE_TEXT_METRICS metrics{};
+ measure_text_layout->GetMetrics(&metrics);
+
+ const Size measure_result(metrics.width, metrics.height);
+
+ auto&& calculate_final_length = [](const MeasureLength& layout_length, const float measure_length, const float measure_result_length) -> float
+ {
+ if ((layout_length.mode == MeasureMode::Stretch ||
+ layout_length.mode == MeasureMode::Exactly)
+ && measure_result_length < measure_length)
+ return measure_length;
+ else
+ return measure_result_length;
+ };
+
+ return Size(
+ calculate_final_length(layout_params->width, measure_size.width, measure_result.width),
+ calculate_final_length(layout_params->height, measure_size.height, measure_result.height)
+ );
}
void TextBlock::OnTextChangedCore(const String& old_text, const String& new_text)
@@ -73,7 +135,7 @@ namespace cru
void TextBlock::CreateDefaultTextFormat()
{
- const auto dwrite_factory = graph::GraphManager::GetInstance()->GetDWriteFactory();
+ const auto dwrite_factory = GetDWriteFactory();
ThrowIfFailed(dwrite_factory->CreateTextFormat(
L"΅ΘΟί", nullptr,
@@ -93,7 +155,7 @@ namespace cru
return;
}
- const auto dwrite_factory = graph::GraphManager::GetInstance()->GetDWriteFactory();
+ const auto dwrite_factory = GetDWriteFactory();
if (text_format_ == nullptr)
CreateDefaultTextFormat();
@@ -106,6 +168,11 @@ namespace cru
size.width, size.height,
&text_layout_
);
+
+ std::for_each(text_layout_handlers_.cbegin(), text_layout_handlers_.cend(), [this](const std::shared_ptr<TextLayoutHandler>& handler)
+ {
+ (*handler)(text_layout_);
+ });
}
}
}
diff --git a/CruUI/ui/controls/text_block.h b/CruUI/ui/controls/text_block.h
index 85bfe90c..abf77112 100644
--- a/CruUI/ui/controls/text_block.h
+++ b/CruUI/ui/controls/text_block.h
@@ -1,5 +1,7 @@
#pragma once
+#include <memory>
+
#include "ui/control.h"
namespace cru
@@ -11,6 +13,9 @@ namespace cru
class TextBlock : public Control
{
public:
+ using TextLayoutHandler = Action<Microsoft::WRL::ComPtr<IDWriteTextLayout>>;
+
+
explicit TextBlock(
const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format = nullptr,
const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush = nullptr
@@ -42,6 +47,18 @@ namespace cru
void SetTextFormat(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& text_format);
+
+ void AddTextLayoutHandler(std::shared_ptr<TextLayoutHandler> handler)
+ {
+ text_layout_handlers_.push_back(std::move(handler));
+ }
+ void RemoveTextLayoutHandler(const std::shared_ptr<TextLayoutHandler>& handler)
+ {
+ const auto find_result = std::find(text_layout_handlers_.cbegin(), text_layout_handlers_.cend(), handler);
+ if (find_result != text_layout_handlers_.cend())
+ text_layout_handlers_.erase(find_result);
+ }
+
protected:
void OnSizeChangedCore(events::SizeChangedEventArgs& args) override final;
void OnDraw(ID2D1DeviceContext* device_context) override;
@@ -61,6 +78,8 @@ namespace cru
Microsoft::WRL::ComPtr<ID2D1Brush> brush_;
Microsoft::WRL::ComPtr<IDWriteTextFormat> text_format_;
Microsoft::WRL::ComPtr<IDWriteTextLayout> text_layout_;
+
+ Vector<std::shared_ptr<TextLayoutHandler>> text_layout_handlers_;
};
}
}