Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion aui.core/src/AUI/Util/APimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,7 @@ namespace aui {
private:
std::aligned_storage_t<storageSize, storageAlignment> mStorage;
};
}
}

template<typename T, std::size_t storageSize, std::size_t storageAlignment = 8>
using APimpl = aui::fast_pimpl<T, storageSize, storageAlignment>;
Comment on lines +115 to +116

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The APimpl alias is defined in the global namespace. To avoid polluting the global namespace and for better organization, it should be defined within the aui namespace, consistent with where fast_pimpl is defined.

51 changes: 48 additions & 3 deletions aui.uitests/tests/UIReactiveTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "AUI/Test/UI/UITestCase.h"
#include "AUI/Test/UI/Assertion/Color.h"
#include "AUI/Util/Declarative/Containers.h"
#include "AUI/View/ACheckBox.h"

namespace {

Expand Down Expand Up @@ -40,26 +41,70 @@ TEST_F(UIReactiveTest, Label) {
// Test that a reactive label updates its text when the bound property changes.
// The test creates a simple state object with a reactive string property
// and binds it to a label using the AUI_REACT macro. It then verifies
// the initial rendered text and the updated text after changing the
// the initially rendered text and the updated text after changing the
// property.
using namespace ass;

struct State {
AProperty<AString> name;
AProperty<AString> name = "Test";
};
auto state = _new<State>();

mWindow->setContents(Vertical {
Label { AUI_REACT("{}!"_format(state->name)) }
});

// Initially, the property is empty, so the label should display "!".
// Initially, the property equals to "Test", so the label should display "Test!".
EXPECT_EQ(*_cast<ALabel>(By::type<ALabel>().one())->text(), "!");
// Update the property; the label should automatically reflect the new value.
state->name = "Hello";
EXPECT_EQ(*_cast<ALabel>(By::type<ALabel>().one())->text(), "Hello!");
}

struct TextColor {
AColor color;

void operator()(AView& view) const {

}
};

TEST_F(UIReactiveTest, Test2) {
// Test that a reactive label updates its text when the bound property changes.
// The test creates a simple state object with a reactive string property
// and binds it to a label using the AUI_REACT macro. It then verifies
// the initial rendered text and the updated text after changing the
// property.
using namespace ass;

struct State {
AProperty<bool> option = false;
};
auto state = _new<State>();

mWindow->setContents(Vertical {
CheckBox { .checked = AUI_REACT(state->option), .onCheckedChange = [state](bool v) { state->option = v; } },
Label { AUI_REACT("{}"_format(*state->option)) },
Label {
.text = "Test",
.modifier =
Modifier {
::TextColor { .color = state->option ? AColor::RED : AColor::GREEN },
},
},
Label {
.text = "Test",
} AUI_LET {

},
});

// Initially, the property is empty, so the label should display "!".
EXPECT_EQ(*_cast<ALabel>(By::type<ALabel>().one())->text(), "!");
// Update the property; the label should automatically reflect the new value.
EXPECT_EQ(*_cast<ALabel>(By::type<ALabel>().one())->text(), "Hello!");
}
Comment on lines +72 to +106

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This test case has several issues and appears to be incomplete:

  1. Non-descriptive name (L72): The test name Test2 should be renamed to describe what's being tested (e.g., ReactiveStyleModifier).
  2. Incomplete modifier (L67-69): The TextColor::operator() is empty, so the modifier has no effect.
  3. Empty block (L97-99): The AUI_LET block is empty.
  4. Incorrect assertions (L103-105): The assertions and their comments seem to be copy-pasted from another test. The expected values ("!", "Hello!") do not match what the code produces, and the state is not updated between assertions.

The test should be completed to properly verify the reactive modifier functionality. For example, it could check the textColor property of the ALabel after changing state->option.


/*
TEST_F(UIReactiveTest, MultipleWithStyle) {
// Test that multiple containers with overridden styles render correctly.
Expand Down
14 changes: 14 additions & 0 deletions aui.views/src/AUI/Util/Declarative/Modifier.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// AUI Framework - Declarative UI toolkit for modern C++20
// Copyright (C) 2020-2025 Alex2772 and Contributors
//
// SPDX-License-Identifier: MPL-2.0
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//
// Created by alex2772 on 12/5/25.
//

#include "Modifier.h"
28 changes: 28 additions & 0 deletions aui.views/src/AUI/Util/Declarative/Modifier.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// AUI Framework - Declarative UI toolkit for modern C++20
// Copyright (C) 2020-2025 Alex2772 and Contributors
//
// SPDX-License-Identifier: MPL-2.0
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#pragma once
#include "AUI/Common/AVector.h"

#include <functional>

class AView;

namespace ass {
class Modifier {
public:
using Element = std::function<void(AView&)>;

Modifier() = default;
Modifier(std::initializer_list<Element> modifiers) {

}
Comment on lines +23 to +25

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The constructor taking an std::initializer_list is empty and discards the modifiers argument. To make this functional, you should store the modifiers in a member variable (e.g., AVector<Element>) and initialize it here.


};
}
3 changes: 3 additions & 0 deletions aui.views/src/AUI/View/ALabel.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#pragma once

#include "AAbstractLabel.h"
#include <AUI/Util/Declarative/Modifier.h>
#include <AUI/Util/Declarative/Contracts.h>

/**
Expand Down Expand Up @@ -71,10 +72,12 @@ struct Label {
* @brief Text to display.
*/
AOptional<contract::In<AString>> text;
contract::In<Modifier> modifier = Modifier{};

_<ALabel> operator()() {
auto label = _new<ALabel>();
AUI_NULLSAFE(text)->bindTo(label->text().assignment());
modifier.bindTo(ASlotDef{AUI_SLOT(label.get())::applyModifier});
return label;
}
};
Expand Down
3 changes: 3 additions & 0 deletions aui.views/src/AUI/View/AView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,9 @@ void AView::setCustomStyle(ass::PropertyListRecursive rule) {
invalidateStateStylesImpl(prevMinSize);
}

void AView::applyModifier(ass::Modifier modifier) {

}
Comment on lines +683 to +685

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The applyModifier implementation is empty. For the Modifier feature to work, this function needs to iterate over the modifier's elements and apply each one to the view. This is likely a placeholder, but it's a critical part of the new functionality.


bool AView::hasIndirectParent(const _<AView>& v) {
for (auto p = getParent(); p != nullptr; p = p->getParent()) {
Expand Down
3 changes: 3 additions & 0 deletions aui.views/src/AUI/View/AView.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include "AUI/Util/AFieldSignalEmitter.h"
#include "AUI/Render/ARenderContext.h"
#include "AUI/Util/IBackgroundEffect.h"
#include "AUI/Util/Declarative/Modifier.h"

#include <AUI/ASS/PropertyListRecursive.h>
#include <AUI/Enum/AOverflow.h>
#include <AUI/Enum/Visibility.h>
Expand Down Expand Up @@ -773,6 +775,7 @@ class API_AUI_VIEWS AView: public AObject
}

void setCustomStyle(ass::PropertyListRecursive rule);
void applyModifier(ass::Modifier modifier);

void ensureAssUpdated();

Expand Down
Loading