Loading...
Searching...
No Matches
ContextMenu.h
Go to the documentation of this file.
1// Copyright (c) 2025 Dave R. Smith.
2// Malena Framework — Licensed under PolyForm Noncommercial 1.0.0; commercial use requires a paid license. See LICENSE.
3
4#ifndef MALENA_CONTEXTMENU_H
5#define MALENA_CONTEXTMENU_H
6
7#pragma once
8
12#include <functional>
13#include <string>
14#include <vector>
15
16namespace ml
17{
34 class MALENA_API ContextMenu : public Graphic<sf::RectangleShape>
35 {
36 public:
38
39 void addItem(const std::string& label, std::function<void()> action);
40 void clearItems();
41
45 void setSearchable(bool on);
47 void setMaxVisibleItems(int n);
50 void setFixedWidth(float w);
51
52 void showAt(const sf::Vector2f& pos);
53 void hide();
54 [[nodiscard]] bool isOpen() const { return _open; }
55
57 void onClose(std::function<void()> cb);
58
59 void setPosition(const sf::Vector2f& pos) override;
60 [[nodiscard]] sf::Vector2f getPosition() const override;
61 [[nodiscard]] sf::FloatRect getGlobalBounds() const override;
62
63 void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
64
65 private:
66 struct Item { std::string label; std::function<void()> action; };
67
68 [[nodiscard]] sf::FloatRect rowRect(int visibleRow) const; // vi-th shown row
69 [[nodiscard]] sf::FloatRect searchRect() const;
70 [[nodiscard]] float itemsTop() const; // y where rows begin
71 [[nodiscard]] int visibleCount() const; // rows shown this frame
72 [[nodiscard]] bool searchShown() const; // search row visible this frame
73 void recomputeFiltered(); // rebuild _filtered from _filter
74 void clampScroll();
75 void recomputeSize();
76
77 std::vector<Item> _items;
78 bool _open = false;
79 bool _prevMouseDown = false;
80 sf::Vector2f _pos { 0.f, 0.f };
81 float _itemH = 26.f;
82 float _pad = 4.f;
83 float _width = 140.f;
84 unsigned int _charSize = 14;
85 mutable int _hover = -1;
86 // Search + scroll (search is opt-in via setSearchable).
87 bool _searchable = false;
88 std::string _filter;
89 float _searchH = 30.f;
90 int _maxVisible = 12;
91 int _scrollItem = 0; // first visible filtered row
92 float _fixedWidth = 0.f; // 0 = auto-size to widest label
93 std::vector<std::size_t> _filtered; // item indices matching _filter
94 std::function<void()> _onClose;
95 // While open, the menu claims the popup + exclusive-owner layers so it draws
96 // on top and blocks background clicks; these hold the prior holders to restore.
97 Core* _prevOwner = nullptr;
98 Core* _prevPopup = nullptr;
99 };
100
101} // namespace ml
102
103#endif // MALENA_CONTEXTMENU_H
void addItem(const std::string &label, std::function< void()> action)
void draw(sf::RenderTarget &target, sf::RenderStates states) const override
void setSearchable(bool on)
sf::FloatRect getGlobalBounds() const override
Return the axis-aligned bounding box in world space.
void setMaxVisibleItems(int n)
void onClose(std::function< void()> cb)
void showAt(const sf::Vector2f &pos)
void setPosition(const sf::Vector2f &pos) override
Set the world-space position immediately (no animation).
sf::Vector2f getPosition() const override
Return the current world-space position.
bool isOpen() const
Definition ContextMenu.h:54
void setFixedWidth(float w)
#define MALENA_API
Definition Animate.h:25
Rect< float > FloatRect
Vector2< float > Vector2f