Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 0
The big split#41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
The big split #41
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| #include "styled_widget.h" | ||
| class ReactImgui; | ||
| class Button final : public StyledWidget { | ||
| protected: | ||
| Button(ReactImgui* view, const int id, const std::string& label, std::optional<BaseStyle>& style) : StyledWidget(view, id, style) { | ||
| m_type = "Button"; | ||
| m_label = label; | ||
| } | ||
| public: | ||
| std::string m_label; | ||
| static std::unique_ptr<Button> makeWidget(const json& widgetDef, std::optional<BaseStyle> maybeStyle, ReactImgui* view); | ||
| static std::unique_ptr<Button> makeWidget(ReactImgui* view, const int id, const std::string& label, std::optional<BaseStyle>& style) { | ||
| Button instance(view, id, label, style); | ||
| return std::make_unique<Button>(std::move(instance)); | ||
| } | ||
| static YGSize Measure(const YGNodeConstRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode) { | ||
| YGSize size{}; | ||
| const auto context = YGNodeGetContext(node); | ||
| if (context) { | ||
| const auto widget = static_cast<Button*>(context); | ||
| size.width = (widget->m_view->m_baseStyle.FramePadding.x * 2.0f) + widget->m_view->CalcTextSize(widget, widget->m_label.c_str()).x; | ||
| size.height = widget->m_view->GetFrameHeight(widget); | ||
| if (widget->HasCustomStyles() && widget->HasCustomStyleVar(ImGuiStyleVar_FramePadding)) { | ||
| auto styleVar = widget->GetCustomStyleVar(ImGuiStyleVar_FramePadding); | ||
| if (std::holds_alternative<ImVec2>(styleVar)) { | ||
| size.width = (std::get<ImVec2>(styleVar).x * 2.0f) + widget->m_view->CalcTextSize(widget, widget->m_label.c_str()).x; | ||
| } | ||
| } | ||
| } | ||
| return size; | ||
| } | ||
| void Render(ReactImgui* view) override; | ||
| bool HasCustomWidth() override; | ||
andreamancuso marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| bool HasCustomHeight() override; | ||
andreamancuso marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| void Patch(const json& widgetPatchDef, ReactImgui* view) override; | ||
andreamancuso marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| void Init() override { | ||
| Element::Init(); | ||
| YGNodeSetContext(m_layoutNode->m_node, this); | ||
| YGNodeSetMeasureFunc(m_layoutNode->m_node, Measure); | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| #include <nlohmann/json.hpp> | ||
| #include "styled_widget.h" | ||
| class Checkbox final : public StyledWidget { | ||
| protected: | ||
| Checkbox(ReactImgui* view, const int id, const std::string& label, const bool defaultChecked, std::optional<BaseStyle>& style) : StyledWidget(view, id, style) { | ||
| m_type = "Checkbox"; | ||
| m_checked = defaultChecked; | ||
| m_label = label; | ||
| } | ||
andreamancuso marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| public: | ||
| bool m_checked; | ||
| std::string m_label; | ||
| static std::unique_ptr<Checkbox> makeWidget(const json& widgetDef, std::optional<BaseStyle> maybeStyle, ReactImgui* view) { | ||
| if (widgetDef.is_object() && widgetDef.contains("id") && widgetDef["id"].is_number_integer()) { | ||
| const auto id = widgetDef["id"].template get<int>(); | ||
| const auto defaultChecked = widgetDef.contains("defaultChecked") && widgetDef["defaultChecked"].is_boolean() ? widgetDef["defaultChecked"].template get<bool>() : false; | ||
| const auto label = widgetDef.contains("label") && widgetDef["label"].is_string() ? widgetDef["label"].template get<std::string>() : ""; | ||
| return makeWidget(view, id, label, defaultChecked, maybeStyle); | ||
| } | ||
| throw std::invalid_argument("Invalid JSON data"); | ||
| } | ||
andreamancuso marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| static std::unique_ptr<Checkbox> makeWidget(ReactImgui* view, const int id, const std::string& label, const bool defaultChecked, std::optional<BaseStyle>& style) { | ||
| Checkbox instance(view, id, label, defaultChecked, style); | ||
| return std::make_unique<Checkbox>(std::move(instance)); | ||
| } | ||
andreamancuso marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| static YGSize Measure(const YGNodeConstRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode) { | ||
| YGSize size{}; | ||
| const auto context = YGNodeGetContext(node); | ||
| if (context) { | ||
| auto widget = static_cast<Checkbox*>(context); | ||
| const auto frameHeight = widget->m_view->GetFrameHeight(widget); | ||
| size.width = frameHeight; | ||
| size.height = frameHeight; | ||
| } | ||
| return size; | ||
| } | ||
| void Render(ReactImgui* view) override; | ||
| void Patch(const json& widgetPatchDef, ReactImgui* view) override; | ||
| void Init() override { | ||
| Element::Init(); | ||
| YGNodeSetContext(m_layoutNode->m_node, this); | ||
| YGNodeSetMeasureFunc(m_layoutNode->m_node, Measure); | ||
| } | ||
andreamancuso marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| #include "styled_widget.h" | ||
| class Child final : public StyledWidget { | ||
| public: | ||
| ImGuiChildFlags m_flags = ImGuiChildFlags_None; | ||
| ImGuiWindowFlags m_window_flags = ImGuiWindowFlags_None; | ||
| float m_width; | ||
| float m_height; | ||
| static std::unique_ptr<Child> makeWidget(const json& widgetDef, std::optional<BaseStyle> maybeStyle, ReactImgui* view) { | ||
| if (widgetDef.is_object() && widgetDef.contains("id") && widgetDef["id"].is_number_integer()) { | ||
| auto id = widgetDef["id"].template get<int>(); | ||
| float width = 0; | ||
| float height = 0; | ||
| if (widgetDef.contains("width") && widgetDef["width"].is_number()) { | ||
| width = widgetDef["width"].template get<float>(); | ||
| } | ||
| if (widgetDef.contains("height") && widgetDef["height"].is_number()) { | ||
| height = widgetDef["height"].template get<float>(); | ||
| } | ||
| return std::make_unique<Child>(view, id, width, height, maybeStyle); | ||
| } | ||
| throw std::invalid_argument("Invalid JSON data"); | ||
andreamancuso marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| Child(ReactImgui* view, int id, float width, float height, std::optional<BaseStyle>& style); | ||
| void Render(ReactImgui* view) override; | ||
| void Patch(const json& widgetPatchDef, ReactImgui* view) override; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| #include "styled_widget.h" | ||
| // todo: should we preallocate buffer size? | ||
| class ClippedMultiLineTextRenderer final : public StyledWidget { | ||
| protected: | ||
| ClippedMultiLineTextRenderer(ReactImgui* view, const int id, const int numberOfLines, std::optional<BaseStyle>& style) : StyledWidget(view, id, style) { | ||
| m_type = "ClippedMultiLineTextRenderer"; | ||
| m_numberOfLines = numberOfLines; | ||
| } | ||
| public: | ||
| int m_numberOfLines; | ||
| ImVector<int> m_lineOffsets; | ||
| ImGuiTextBuffer m_textBuffer; | ||
| static std::unique_ptr<ClippedMultiLineTextRenderer> makeWidget(const json& widgetDef, std::optional<BaseStyle> maybeStyle, ReactImgui* view) { | ||
| if (widgetDef.is_object() && widgetDef.contains("id") && widgetDef["id"].is_number_integer()) { | ||
| const auto id = widgetDef["id"].template get<int>(); | ||
| int numberOfLines = 10; | ||
| if (widgetDef.contains("numberOfLines") && widgetDef["numberOfLines"].is_number_unsigned()) { | ||
| numberOfLines = widgetDef["numberOfLines"].template get<int>(); | ||
| } | ||
| return makeWidget(view, id, numberOfLines, maybeStyle); | ||
| } | ||
| throw std::invalid_argument("Invalid JSON data"); | ||
| } | ||
| static std::unique_ptr<ClippedMultiLineTextRenderer> makeWidget(ReactImgui* view, int id, const int numberOfLines, std::optional<BaseStyle>& style) { | ||
| ClippedMultiLineTextRenderer instance(view, id, numberOfLines, style); | ||
| return std::make_unique<ClippedMultiLineTextRenderer>(std::move(instance)); | ||
| } | ||
| static YGSize Measure(const YGNodeConstRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode) { | ||
| YGSize size{}; | ||
| const auto context = YGNodeGetContext(node); | ||
| if (context) { | ||
| auto widget = static_cast<ClippedMultiLineTextRenderer*>(context); | ||
| size.width = width; | ||
| size.height = widget->m_view->GetFrameHeight(widget) * static_cast<float>(widget->m_numberOfLines); | ||
| } | ||
| return size; | ||
| } | ||
| void Render(ReactImgui* view) override; | ||
| void Patch(const json& widgetPatchDef, ReactImgui* view) override; | ||
| void SetNumberOfLines(int numberOfLines) { | ||
| m_numberOfLines = numberOfLines; | ||
| } | ||
| void Clear() { | ||
| m_lineOffsets.clear(); | ||
| m_lineOffsets.push_back(0); | ||
| m_textBuffer.clear(); | ||
| } | ||
| void SetData(const char* str) { | ||
| Clear(); | ||
| AppendText(str); | ||
| } | ||
| void AppendText(const char* str) { | ||
| int old_size = m_textBuffer.size(); | ||
| m_textBuffer.append(str); | ||
| for (const int new_size = m_textBuffer.size(); old_size < new_size; old_size++) | ||
| if (m_textBuffer[old_size] == '\n') | ||
| m_lineOffsets.push_back(old_size + 1); | ||
| } | ||
| void Init() override { | ||
| Element::Init(); | ||
| YGNodeSetContext(m_layoutNode->m_node, this); | ||
| YGNodeSetMeasureFunc(m_layoutNode->m_node, Measure); | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| #include "styled_widget.h" | ||
| class CollapsingHeader final : public StyledWidget { | ||
| public: | ||
| std::string m_label; | ||
andreamancuso marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| static std::unique_ptr<CollapsingHeader> makeWidget(const json& widgetDef, std::optional<BaseStyle> maybeStyle, ReactImgui* view) { | ||
| if (widgetDef.is_object() && widgetDef.contains("id") && widgetDef["id"].is_number_integer()) { | ||
| auto id = widgetDef["id"].template get<int>(); | ||
| const auto label = widgetDef["label"].template get<std::string>(); | ||
| return std::make_unique<CollapsingHeader>(view, id, label, maybeStyle); | ||
| } | ||
| throw std::invalid_argument("Invalid JSON data"); | ||
| } | ||
| CollapsingHeader(ReactImgui* view, int id, const std::string& label, std::optional<BaseStyle>& style); | ||
| void Render(ReactImgui* view) override; | ||
| void Patch(const json& widgetPatchDef, ReactImgui* view) override; | ||
| bool HasCustomWidth() override; | ||
| bool HasCustomHeight() override; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| #include "styled_widget.h" | ||
| class Combo final : public StyledWidget { | ||
| protected: | ||
| Combo(ReactImgui* view, const int id, const std::string& placeholder, const int initialSelectedIndex, const std::vector<std::string>& options, std::optional<BaseStyle>& style) : StyledWidget(view, id, style) { | ||
| m_type = "Combo"; | ||
| m_placeholder = placeholder; | ||
| m_options = options; | ||
| if (initialSelectedIndex > -1) { | ||
| m_selectedIndex = initialSelectedIndex; | ||
| } | ||
| } | ||
| public: | ||
| int m_selectedIndex = -1; | ||
| std::string m_placeholder; | ||
| std::vector<std::string> m_options; | ||
andreamancuso marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. andreamancuso marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| static std::unique_ptr<Combo> makeWidget(const json& widgetDef, std::optional<BaseStyle> maybeStyle, ReactImgui* view) { | ||
| if (widgetDef.is_object() && widgetDef.contains("id") && widgetDef["id"].is_number_integer()) { | ||
| const auto id = widgetDef["id"].template get<int>(); | ||
| const auto initialSelectedIndex = widgetDef.contains("initialSelectedIndex") && widgetDef["initialSelectedIndex"].is_number() | ||
| ? widgetDef["initialSelectedIndex"].template get<int>() | ||
| : -1; | ||
| const auto placeholder = widgetDef.contains("placeholder") ? widgetDef["placeholder"].template get<std::string>() : ""; | ||
| std::vector<std::string> options; | ||
| if (widgetDef.contains("options") && widgetDef["options"].is_array()) { | ||
| for (const auto &[key, item] : widgetDef["options"].items()) { | ||
| if (item.is_string()) { | ||
| options.emplace_back(item.template get<std::string>()); | ||
| } | ||
| } | ||
| } | ||
| return makeWidget(view, id, placeholder, initialSelectedIndex, options, maybeStyle); | ||
| } | ||
| throw std::invalid_argument("Invalid JSON data"); | ||
| } | ||
andreamancuso marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| static std::unique_ptr<Combo> makeWidget(ReactImgui* view, const int id, const std::string& placeholder, const int initialSelectedIndex, const std::vector<std::string>& options, std::optional<BaseStyle>& style) { | ||
| Combo instance(view, id, placeholder, initialSelectedIndex, options, style); | ||
| return std::make_unique<Combo>(std::move(instance)); | ||
| } | ||
andreamancuso marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| static YGSize Measure(YGNodeConstRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode) { | ||
| YGSize size{}; | ||
| const auto context = YGNodeGetContext(node); | ||
| if (context) { | ||
| const auto widget = static_cast<Combo*>(context); | ||
| // TODO: we may want to define default widths similarly to how browsers do | ||
| size.width = widget->m_view->GetWidgetFontSize(widget) * 10; | ||
| // TODO: we likely need to compute this based on the associated font, based on the widget's style | ||
| size.height = widget->m_view->GetFrameHeight(widget); | ||
| } | ||
| return size; | ||
| } | ||
| void SetOptions(const json& options) { | ||
| m_options.clear(); | ||
| if (options.is_array()) { | ||
| for (const auto &[key, item] : options.items()) { | ||
| if (item.is_string()) { | ||
| m_options.emplace_back(item.template get<std::string>()); | ||
| } | ||
| } | ||
| } | ||
| } | ||
andreamancuso marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| void SetOptions(const std::vector<std::string>& options) { | ||
| m_options = options; | ||
| } | ||
| void SetSelectedIndex(int selectedIndex) { | ||
| m_selectedIndex = selectedIndex; | ||
| } | ||
| void ClearSelectedIndex() { | ||
| m_selectedIndex = -1; | ||
| } | ||
| void Render(ReactImgui* view) override; | ||
| void Patch(const json& widgetPatchDef, ReactImgui* view) override; | ||
| void Init() override { | ||
| Element::Init(); | ||
| YGNodeSetContext(m_layoutNode->m_node, this); | ||
| YGNodeSetMeasureFunc(m_layoutNode->m_node, Measure); | ||
andreamancuso marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| }; | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.