6 : calculations::BlocksCalculator(this),
10 dragOffset({.width = 0, .height = 0}),
11 windowDelegate(windowDelegate) {}
16 logger->info(
"Skipping mouse down because we have an active choices input");
27 if (maybeClickedBlock) {
28 const auto& clickedBlock = maybeClickedBlock.value();
30 auto* doubleClickableBlock =
35 if (doubleClickableBlock ==
nullptr) {
36 logger->info(
"Double clicked block {} is not IDoubleClickable",
37 clickedBlock->getSelfId());
42 logger->info(
"Double clicked outside any block");
50 if (maybeClickedBlock) {
51 const auto& clickedBlock = maybeClickedBlock.value();
53 auto maybeClickedPort =
54 clickedBlock->getPortAtCoordinates({.x =
mouseX, .y =
mouseY});
56 if (maybeClickedPort.value_or(
nullptr) !=
nullptr) {
57 logger->info(
"Clicked port '{}' on block {}",
58 maybeClickedPort.value()->name,
59 clickedBlock->getSelfId());
62 clickedBlock.get(), maybeClickedPort.value(),
windowDelegate,
this);
67 logger->info(
"Clicked block {} for dragging", clickedBlock->getSelfId());
71 .height =
mouseY - clickedBlock->getCy()};
79 logger->info(
"Clicked outside any block");
96 logger->info(
"Escape key pressed");
111 logger->info(
"Selected choice: {}", number);
117 logger->error(
"Invalid choice number: {}", number);
120 "You entered: " + std::to_string(number) +
121 " which is out of range. Pick a "
122 "number between 1 and " +
137 std::optional<std::shared_ptr<business_logic::elements::blocks::BaseBlock>>
142 std::optional<std::shared_ptr<business_logic::elements::blocks::BaseBlock>>
146 auto maybeHoveredBlockIt =
147 std::find_if(
blocks.rbegin(),
blocks.rend(), [x, y](
const auto& block) {
148 return block->isHovered(x, y);
151 std::optional<std::shared_ptr<business_logic::elements::blocks::BaseBlock>>
152 maybeHoveredBlock = std::nullopt;
154 if (maybeHoveredBlockIt !=
blocks.rend()) {
155 maybeHoveredBlock = *maybeHoveredBlockIt;
158 return maybeHoveredBlock;
165 blocks.push_back(std::make_shared<business_logic::elements::blocks::ConstantBlock>(
170 blocks.push_back(std::make_shared<business_logic::elements::blocks::AddBlock>(
175 blocks.push_back(std::make_shared<business_logic::elements::blocks::SubtractBlock>(
180 blocks.push_back(std::make_shared<business_logic::elements::blocks::MultiplyBlock>(
185 blocks.push_back(std::make_shared<business_logic::elements::blocks::DivideBlock>(
190 blocks.push_back(std::make_shared<business_logic::elements::blocks::PowerBlock>(
195 blocks.push_back(std::make_shared<business_logic::elements::blocks::InvertBlock>(
200 blocks.push_back(std::make_shared<business_logic::elements::blocks::MonitorBlock>(
205 auto name = magic_enum::enum_name(blockType);
207 logger->error(
"Unknown user-selected block type: {}", name);
211 "You selected an invalid block type: '" + std::string(name) +
"'");
218 inputChoiceInteraction) {
221 std::vector<std::string> labels;
222 labels.reserve(choices.size());
229 labels.push_back(std::to_string(++index) +
" " + choice.displayName);
237 std::vector<components::UIText> rowBuff;
239 for (; number <= choices.size(); number++) {
240 rowBuff.emplace_back(std::to_string(number) +
" " + choices[number - 1].displayName,
249 if (!rowBuff.empty()) {
253 logger->info(
"Prepared {} input choices for rendering", number);
262 logger->info(
"Clearing active choices input");
274 .port = source.
port};
280 [variant1, variant2](
const auto& connection) {
281 return connection.first == variant1 &&
282 connection.second.contains(variant2);
290 return connection.first == side || connection.second.contains(side);
306 if (source.block == block) {
311 std::erase_if(destinations,
312 [block](
const auto& dest) {
return dest.block == block; });
323 const std::shared_ptr<business_logic::elements::blocks::BaseBlock>& block) {
327 if (maybeClickedPort.has_value()) {
329 .
block = block.get(), .port = maybeClickedPort.value()};
333 size_t erasedCount = 0;
336 if (source == sideToDelete) {
341 erasedCount += std::erase_if(destinations, [sideToDelete](
const auto& dest) {
342 return dest == sideToDelete;
347 logger->info(
"Right clicked on port '{}' - removed its {} connections",
348 maybeClickedPort.value()->name,
351 logger->info(
"Right clicked on block '{}' - asking for confirmation about removal",
356 "Are you sure you want to remove block '" +
357 std::string(magic_enum::enum_name(block->getBlockType())) +
"'?")) {
358 logger->info(
"User confirmed removal of block '{}'", block->getSelfId());
366 logger->info(
"User cancelled removal of block '{}'", block->getSelfId());
371 const std::vector<std::shared_ptr<business_logic::elements::blocks::BaseBlock>>&
377 std::unordered_set<elements::structures::BlocksConnectionSide>>&
bool hasActiveChoicesInput() const
Checks if the input callback is active.
std::unordered_map< business_logic::elements::structures::BlocksConnectionSide, std::unordered_set< business_logic::elements::structures::BlocksConnectionSide > > connectionsRegistry
void handleMouseUp()
Handles the mouse up event.
bool hasConnectionBetween(const business_logic::elements::structures::BlocksConnectionSide &source, const business_logic::elements::structures::BlocksConnectionSide &dest) const override
Checks if there is a connection between two entities.
void clearActiveChoicesInput()
Clears the active input choices and the corresponding generated UI texts rows.
void handleNumericKeyPress(int number)
Handles the numeric key press event.
void setActiveChoicesInput(business_logic::input::InputChoiceInteraction< business_logic::elements::blocks::BlockType > &&inputChoiceInteraction)
Sets the input callback; this will override rendering other entities.
void onNewBlockChoice(const business_logic::elements::blocks::BlockType &blockType) override
Called when a new block is chosen to be added to the canvas.
business_logic::geometry::Size2D dragOffset
std::chrono::steady_clock::time_point doubleClickCtLastMouseClickTime
void onPortsConnected(const business_logic::elements::structures::BlocksConnectionSide &source, const business_logic::elements::structures::BlocksConnectionSide &dest) override
Invoked when a connection is made between two ports + blocks (sides)
std::optional< std::shared_ptr< business_logic::elements::blocks::BaseBlock > > getBlockAtMousePos()
Gets the block at the mouse position.
void handleRightClickOnBlock(const std::shared_ptr< business_logic::elements::blocks::BaseBlock > &block)
Handles right click event on a block.
business_logic::delegate::IWindowDelegate * windowDelegate
void handleEscapeKeyPress()
Handles the ESC key press event.
const std::vector< std::shared_ptr< business_logic::elements::blocks::BaseBlock > > & getBlocks() const override
Gets the blocks.
const std::unordered_map< business_logic::elements::structures::BlocksConnectionSide, std::unordered_set< business_logic::elements::structures::BlocksConnectionSide > > & getConnectionsRegistry() const override
Gets the connections registry.
business_logic::input::ConnectPortsInteraction connectPortsInteraction
bool isInputConnected(const business_logic::elements::structures::BlocksConnectionSide &side) const override
Checks if the input port is connected to anything.
void handleMouseDown()
Handles the mouse down event.
std::optional< business_logic::input::InputChoiceInteraction< business_logic::elements::blocks::BlockType > > inputChoiceInteraction
void handleMouseMove(int x, int y)
Handles the mouse move event.
business_logic::elements::blocks::BaseBlock * draggedBlock
void onBlockDeleted(const business_logic::elements::blocks::BaseBlock *block) override
Called when a block is deleted.
std::vector< components::UITextsRow > inputChoicesUiTextsRows
std::vector< std::shared_ptr< business_logic::elements::blocks::BaseBlock > > blocks
BlocksManager(business_logic::delegate::IWindowDelegate *windowDelegate)
std::optional< std::shared_ptr< business_logic::elements::blocks::BaseBlock > > getBlockAt(int x, int y)
Gets the block at the given coordinates.
std::shared_ptr< spdlog::logger > logger
The delegate for the window.
virtual bool promptConfirmation(const std::string &title, const std::string &message)=0
Prompt for user confirmation.
virtual void showWarning(const std::string &title, const std::string &message)=0
Show a warning message.
The base class for all blocks, containing common functionality and members.
void onDragStart() override
Called when dragging starts.
void onDragEnd() override
Called when dragging ends.
std::optional< const structures::Port * > getPortAtCoordinates(const geometry::Point2D &point) const
Gets the port at given coordinates.
void onDragProgress(int x, int y) override
Called during dragging.
virtual std::string getSelfId() const =0
Interface for elements that can be double-clicked.
virtual void onDoubleClick(int x, int y)=0
Called when the element is double-clicked.
constexpr std::chrono::milliseconds DOUBLE_CLICK_TIME_THRESHOLD_MS(200)
constexpr int MAX_INPUT_CHOICES_PER_ROW
BlockType
The available block types.
The business logic module.
A side of a connection between two ports.
business_logic::elements::blocks::BaseBlock * block
The block.
const business_logic::elements::structures::Port * port
The port.