Freeciv21
Develop your civilization from humble roots to a global empire
multi_slider.h
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPLv3-or-later
2 // SPDX-FileCopyrightText: Louis Moureaux <m_louis30@yahoo.com>
3 
4 #pragma once
5 
6 #include <QWidget>
7 
8 #include <limits>
9 #include <vector>
10 
11 namespace freeciv {
12 
13 class multi_slider : public QWidget {
14  Q_OBJECT
15 
16  struct category {
17  QPixmap icon;
18  int minimum = 0, maximum = std::numeric_limits<int>::max();
19 
21  bool allowed(int value) const
22  {
23  return value >= minimum && value <= maximum;
24  }
25  };
26 
27  struct handle {
28  int index;
29  int location;
30  };
31 
32 public:
33  explicit multi_slider(QWidget *parent = nullptr);
34  virtual ~multi_slider() = default;
35 
36  std::size_t add_category(const QPixmap &icon);
37  void set_range(std::size_t category, int min, int max);
38 
40  std::vector<int> values() const { return m_values; }
41  void set_values(const std::vector<int> &values);
42 
43  QSize sizeHint() const override;
44  QSize minimumSizeHint() const override;
45 
46  std::size_t total() const;
47 
48 signals:
49  void values_changed(const std::vector<int> &values) const;
50 
51 protected:
52  bool event(QEvent *event) override;
53 
54  void focusInEvent(QFocusEvent *event) override;
55  void keyPressEvent(QKeyEvent *event) override;
56  void leaveEvent(QEvent *event) override;
57  void mouseDoubleClickEvent(QMouseEvent *event) override;
58  void mouseMoveEvent(QMouseEvent *event) override;
59  void mousePressEvent(QMouseEvent *event) override;
60  void mouseReleaseEvent(QMouseEvent *event) override;
61  void paintEvent(QPaintEvent *event) override;
62  void resizeEvent(QResizeEvent *event) override;
63 
64 private:
65  void exchange(std::size_t giver, std::size_t taker, int amount);
66  bool grab_item(std::size_t taker, int amount, bool from_left = true,
67  bool from_right = true);
68 
69  void focus_some_category();
70  bool move_focus(bool forward);
71 
72  int handle_near(const QPoint &where);
73  bool move_handle(int handle, const QPoint &where);
74 
76  std::vector<handle> visible_handles() const;
77 
79  std::vector<category> m_categories;
80  // Invariant: m_categories.size() == m_handles.size()
81 
83  std::vector<int> m_values;
84 
87 
89  int m_closest_handle = -1;
90  int m_dragged_handle = -1;
91 
93  struct {
94  int icons_width = 1;
95  int left_margin = 0;
96  double item_width = 1;
97  } m_geom;
98 };
99 
100 } // namespace freeciv
A widget that lets the user distribute a fixed number of items across multiple categories.
Definition: multi_slider.h:13
std::vector< int > m_values
Number of items in each category.
Definition: multi_slider.h:83
void mouseMoveEvent(QMouseEvent *event) override
Moves the current handle when dragging the mouse.
void paintEvent(QPaintEvent *event) override
Draws the widget.
void resizeEvent(QResizeEvent *event) override
Updates cached geometry information.
int m_closest_handle
Index of the handle being dragged with the mouse.
Definition: multi_slider.h:89
void set_range(std::size_t category, int min, int max)
Sets the minimum and maximum number of items a category can have.
virtual ~multi_slider()=default
void focus_some_category()
Makes sure the focused category is a visible one.
int left_margin
Empty space left of the icons.
Definition: multi_slider.h:95
std::vector< int > values() const
Retrieves the number of items in each category.
Definition: multi_slider.h:40
std::vector< category > m_categories
Category data.
Definition: multi_slider.h:79
double item_width
The logical width of one item.
Definition: multi_slider.h:96
struct freeciv::multi_slider::@154 m_geom
Cached geometry information.
void mouseDoubleClickEvent(QMouseEvent *event) override
Moves the closest handle when double-clicking.
bool move_focus(bool forward)
Moves focus to the next or previous visible category.
multi_slider(QWidget *parent=nullptr)
Constructor.
int handle_near(const QPoint &where)
Finds the index of the handle closest to the given position.
void set_values(const std::vector< int > &values)
Sets the contents of all item categories.
void mousePressEvent(QMouseEvent *event) override
Sets the current handle when pressing a mouse button.
bool event(QEvent *event) override
Overrides tab handling to also cycle through visible categories.
void leaveEvent(QEvent *event) override
Sopts highlighting the closest handle.
bool grab_item(std::size_t taker, int amount, bool from_left=true, bool from_right=true)
Grab an item from elsewhere and adds it to the taker category.
void mouseReleaseEvent(QMouseEvent *event) override
Unsets the current handle when releasing a mouse button.
void update_cached_geometry()
Updates cached geometry information.
std::size_t total() const
Returns the total number of items controlled by this widget.
void keyPressEvent(QKeyEvent *event) override
Handles arrow keys: left/right to change the focused category, up/down to add or remove items.
int icons_width
Width of the area covered with icons.
Definition: multi_slider.h:94
bool move_handle(int handle, const QPoint &where)
Tries to move a handle closer to a given position.
std::vector< handle > visible_handles() const
Returns the list of all visible handles.
int m_focused_category
Index of the category receiving keyboard input.
Definition: multi_slider.h:86
std::size_t add_category(const QPixmap &icon)
Adds a category.
void values_changed(const std::vector< int > &values) const
QSize minimumSizeHint() const override
Minimum size of the widget.
QSize sizeHint() const override
Preferred size of the widget.
void focusInEvent(QFocusEvent *event) override
Focuses the first or last category when focus is gained with the keyboard.
void exchange(std::size_t giver, std::size_t taker, int amount)
Exchange items between two categories.
Definition: path.cpp:10
bool allowed(int value) const
Checks if the category could take some value.
Definition: multi_slider.h:21