Freeciv21
Develop your civilization from humble roots to a global empire
freeciv::multi_slider Class Reference

A widget that lets the user distribute a fixed number of items across multiple categories. More...

#include <multi_slider.h>

+ Inheritance diagram for freeciv::multi_slider:
+ Collaboration diagram for freeciv::multi_slider:

Classes

struct  category
 
struct  handle
 

Signals

void values_changed (const std::vector< int > &values) const
 

Public Member Functions

 multi_slider (QWidget *parent=nullptr)
 Constructor. More...
 
virtual ~multi_slider ()=default
 
std::size_t add_category (const QPixmap &icon)
 Adds a category. More...
 
void set_range (std::size_t category, int min, int max)
 Sets the minimum and maximum number of items a category can have. More...
 
std::vector< int > values () const
 Retrieves the number of items in each category. More...
 
void set_values (const std::vector< int > &values)
 Sets the contents of all item categories. More...
 
QSize sizeHint () const override
 Preferred size of the widget. More...
 
QSize minimumSizeHint () const override
 Minimum size of the widget. More...
 
std::size_t total () const
 Returns the total number of items controlled by this widget. More...
 

Protected Member Functions

bool event (QEvent *event) override
 Overrides tab handling to also cycle through visible categories. More...
 
void focusInEvent (QFocusEvent *event) override
 Focuses the first or last category when focus is gained with the keyboard. More...
 
void keyPressEvent (QKeyEvent *event) override
 Handles arrow keys: left/right to change the focused category, up/down to add or remove items. More...
 
void leaveEvent (QEvent *event) override
 Sopts highlighting the closest handle. More...
 
void mouseDoubleClickEvent (QMouseEvent *event) override
 Moves the closest handle when double-clicking. More...
 
void mouseMoveEvent (QMouseEvent *event) override
 Moves the current handle when dragging the mouse. More...
 
void mousePressEvent (QMouseEvent *event) override
 Sets the current handle when pressing a mouse button. More...
 
void mouseReleaseEvent (QMouseEvent *event) override
 Unsets the current handle when releasing a mouse button. More...
 
void paintEvent (QPaintEvent *event) override
 Draws the widget. More...
 
void resizeEvent (QResizeEvent *event) override
 Updates cached geometry information. More...
 

Private Member Functions

void exchange (std::size_t giver, std::size_t taker, int amount)
 Exchange items between two categories. More...
 
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. More...
 
void focus_some_category ()
 Makes sure the focused category is a visible one. More...
 
bool move_focus (bool forward)
 Moves focus to the next or previous visible category. More...
 
int handle_near (const QPoint &where)
 Finds the index of the handle closest to the given position. More...
 
bool move_handle (int handle, const QPoint &where)
 Tries to move a handle closer to a given position. More...
 
void update_cached_geometry ()
 Updates cached geometry information. More...
 
std::vector< handlevisible_handles () const
 Returns the list of all visible handles. More...
 

Private Attributes

std::vector< categorym_categories
 Category data. More...
 
std::vector< int > m_values
 Number of items in each category. More...
 
int m_focused_category = 0
 Index of the category receiving keyboard input. More...
 
int m_closest_handle = -1
 Index of the handle being dragged with the mouse. More...
 
int m_dragged_handle = -1
 
struct {
   int   icons_width = 1
 Width of the area covered with icons. More...
 
   int   left_margin = 0
 Empty space left of the icons. More...
 
   double   item_width = 1
 The logical width of one item. More...
 
m_geom
 Cached geometry information. More...
 

Detailed Description

A widget that lets the user distribute a fixed number of items across multiple categories.

This widget provides a slider with multiple handles. The width of the slider represents a number of items that the user can distribute across multiple categories. For instance, the items could be citizens that would be distributed to perform various tasks.

The widget needs an icon for each category. The icon should represent a single item in the category. When possible, the widget displays each item using one complete icon. It is important that all icons be of the same size.

Categories are initially added with add_category. A minimum and maximum number of items in each category can optionally be set with set_range. The displayed values are set using set_values and recovered with values. The signal values_changed is emitted each time the user redistributes items (which can be quite frequent).

Users can interact with this widget using the keyboard or the mouse, with interaction patterns optimized for each device. When using the keyboard, the user can navigate between categories using the left and right arrow keys, and add or remove items to the current category using the up and down arrows. Of course, in doing so they also modify other categories. The current category is indicated with a slight underline and is also integrated in tab navigation.

When using the mouse, the user can grab handles shown between categories and drag them wherever they want to adjust the number of items. It is also possible to double-click, which moves the closest handle to the location pointed to by the mouse.

It is a good idea to have a legend explaining what the icons mean next to this widget, as it is not self-explanatory.

Definition at line 13 of file multi_slider.h.

Constructor & Destructor Documentation

◆ multi_slider()

freeciv::multi_slider::multi_slider ( QWidget *  parent = nullptr)
explicit

Constructor.

Definition at line 106 of file multi_slider.cpp.

◆ ~multi_slider()

virtual freeciv::multi_slider::~multi_slider ( )
virtualdefault

Member Function Documentation

◆ add_category()

std::size_t freeciv::multi_slider::add_category ( const QPixmap &  icon)

Adds a category.

Parameters
iconAn icon representing a single item in the category. All icons must have the same size.
Returns
The index of the new category.

Definition at line 120 of file multi_slider.cpp.

Referenced by national_budget_dialog::refresh().

◆ event()

bool freeciv::multi_slider::event ( QEvent *  event)
overrideprotected

Overrides tab handling to also cycle through visible categories.

Definition at line 217 of file multi_slider.cpp.

Referenced by focusInEvent(), keyPressEvent(), leaveEvent(), mouseDoubleClickEvent(), mouseMoveEvent(), mousePressEvent(), and mouseReleaseEvent().

◆ exchange()

void freeciv::multi_slider::exchange ( std::size_t  giver,
std::size_t  taker,
int  amount 
)
private

Exchange items between two categories.

Warning
This is a low-level function that doesn't check anything.

Definition at line 441 of file multi_slider.cpp.

Referenced by grab_item().

◆ focus_some_category()

void freeciv::multi_slider::focus_some_category ( )
private

Makes sure the focused category is a visible one.

Definition at line 495 of file multi_slider.cpp.

Referenced by exchange().

◆ focusInEvent()

void freeciv::multi_slider::focusInEvent ( QFocusEvent *  event)
overrideprotected

Focuses the first or last category when focus is gained with the keyboard.

Definition at line 239 of file multi_slider.cpp.

◆ grab_item()

bool freeciv::multi_slider::grab_item ( std::size_t  taker,
int  amount,
bool  from_left = true,
bool  from_right = true 
)
private

Grab an item from elsewhere and adds it to the taker category.

Parameters
takerIndex of the category to add an item to.
amount-1 to give an item away instead.
from_leftAllows taking items from (or giving them to) categories on the left of taker.
from_rightAllows taking items from (or giving them to) categories on the right of taker.
Returns
Whether an item could be found.

Definition at line 458 of file multi_slider.cpp.

Referenced by keyPressEvent(), and move_handle().

◆ handle_near()

int freeciv::multi_slider::handle_near ( const QPoint &  where)
private

Finds the index of the handle closest to the given position.

Definition at line 532 of file multi_slider.cpp.

Referenced by mouseDoubleClickEvent(), mouseMoveEvent(), and mousePressEvent().

◆ keyPressEvent()

void freeciv::multi_slider::keyPressEvent ( QKeyEvent *  event)
overrideprotected

Handles arrow keys: left/right to change the focused category, up/down to add or remove items.

Definition at line 258 of file multi_slider.cpp.

◆ leaveEvent()

void freeciv::multi_slider::leaveEvent ( QEvent *  event)
overrideprotected

Sopts highlighting the closest handle.

Definition at line 302 of file multi_slider.cpp.

◆ minimumSizeHint()

QSize freeciv::multi_slider::minimumSizeHint ( ) const
override

Minimum size of the widget.

The width is 5 times the number of items plus extra space for handles, the height is the icon height plus space for handles.

Definition at line 203 of file multi_slider.cpp.

◆ mouseDoubleClickEvent()

void freeciv::multi_slider::mouseDoubleClickEvent ( QMouseEvent *  event)
overrideprotected

Moves the closest handle when double-clicking.

Definition at line 312 of file multi_slider.cpp.

◆ mouseMoveEvent()

void freeciv::multi_slider::mouseMoveEvent ( QMouseEvent *  event)
overrideprotected

Moves the current handle when dragging the mouse.

Definition at line 325 of file multi_slider.cpp.

◆ mousePressEvent()

void freeciv::multi_slider::mousePressEvent ( QMouseEvent *  event)
overrideprotected

Sets the current handle when pressing a mouse button.

Definition at line 346 of file multi_slider.cpp.

◆ mouseReleaseEvent()

void freeciv::multi_slider::mouseReleaseEvent ( QMouseEvent *  event)
overrideprotected

Unsets the current handle when releasing a mouse button.

Definition at line 359 of file multi_slider.cpp.

◆ move_focus()

bool freeciv::multi_slider::move_focus ( bool  forward)
private

Moves focus to the next or previous visible category.

Parameters
forwardWhether to move focus to the right (true) or to the left (false).
Returns
True if a valid category is now focused.

Definition at line 514 of file multi_slider.cpp.

Referenced by event(), focus_some_category(), and keyPressEvent().

◆ move_handle()

bool freeciv::multi_slider::move_handle ( int  handle,
const QPoint &  where 
)
private

Tries to move a handle closer to a given position.

Parameters
handleThe index of the handle to move.
whereThe location where to move it.
Returns
True one success.

Definition at line 553 of file multi_slider.cpp.

Referenced by mouseDoubleClickEvent(), and mouseMoveEvent().

◆ paintEvent()

void freeciv::multi_slider::paintEvent ( QPaintEvent *  event)
overrideprotected

Draws the widget.

Definition at line 369 of file multi_slider.cpp.

◆ resizeEvent()

void freeciv::multi_slider::resizeEvent ( QResizeEvent *  event)
overrideprotected

Updates cached geometry information.

Definition at line 432 of file multi_slider.cpp.

◆ set_range()

void freeciv::multi_slider::set_range ( std::size_t  category,
int  min,
int  max 
)

Sets the minimum and maximum number of items a category can have.

By default the minimum is zero and the maximum is very large.

Parameters
categoryThe index of the category to modify.
minThe smallest allowed value, may not be smaller than zero.
maxThe largest allowed value.

Definition at line 142 of file multi_slider.cpp.

Referenced by national_budget_dialog::refresh().

◆ set_values()

void freeciv::multi_slider::set_values ( const std::vector< int > &  values)

Sets the contents of all item categories.

Note
It is the user's responsibility to ensure that min/max constraints are satisfied.

Definition at line 161 of file multi_slider.cpp.

Referenced by national_budget_dialog::refresh().

◆ sizeHint()

QSize freeciv::multi_slider::sizeHint ( ) const
override

Preferred size of the widget.

The width is the icon width times the number of items plus extra space for handles, the height is the icon height plus space for handles.

Definition at line 186 of file multi_slider.cpp.

◆ total()

std::size_t freeciv::multi_slider::total ( ) const

Returns the total number of items controlled by this widget.

Definition at line 175 of file multi_slider.cpp.

Referenced by minimumSizeHint(), paintEvent(), sizeHint(), and update_cached_geometry().

◆ update_cached_geometry()

void freeciv::multi_slider::update_cached_geometry ( )
private

Updates cached geometry information.

Definition at line 584 of file multi_slider.cpp.

Referenced by resizeEvent(), set_range(), and set_values().

◆ values()

std::vector<int> freeciv::multi_slider::values ( ) const
inline

Retrieves the number of items in each category.

Definition at line 40 of file multi_slider.h.

Referenced by national_budget_dialog::apply(), keyPressEvent(), move_handle(), and set_values().

◆ values_changed

void freeciv::multi_slider::values_changed ( const std::vector< int > &  values) const
signal

◆ visible_handles()

std::vector< multi_slider::handle > freeciv::multi_slider::visible_handles ( ) const
private

Returns the list of all visible handles.

Definition at line 615 of file multi_slider.cpp.

Referenced by handle_near(), and paintEvent().

Member Data Documentation

◆ icons_width

int freeciv::multi_slider::icons_width = 1

Width of the area covered with icons.

Definition at line 94 of file multi_slider.h.

◆ item_width

double freeciv::multi_slider::item_width = 1

The logical width of one item.

Definition at line 96 of file multi_slider.h.

◆ left_margin

int freeciv::multi_slider::left_margin = 0

Empty space left of the icons.

Definition at line 95 of file multi_slider.h.

◆ m_categories

std::vector<category> freeciv::multi_slider::m_categories
private

◆ m_closest_handle

int freeciv::multi_slider::m_closest_handle = -1
private

Index of the handle being dragged with the mouse.

Definition at line 89 of file multi_slider.h.

Referenced by leaveEvent(), mouseMoveEvent(), and paintEvent().

◆ m_dragged_handle

int freeciv::multi_slider::m_dragged_handle = -1
private

Definition at line 90 of file multi_slider.h.

Referenced by mouseMoveEvent(), mousePressEvent(), mouseReleaseEvent(), and paintEvent().

◆ m_focused_category

int freeciv::multi_slider::m_focused_category = 0
private

Index of the category receiving keyboard input.

Definition at line 86 of file multi_slider.h.

Referenced by focus_some_category(), focusInEvent(), keyPressEvent(), move_focus(), and paintEvent().

◆ 

struct { ... } freeciv::multi_slider::m_geom

Cached geometry information.

Referenced by handle_near(), move_handle(), paintEvent(), and update_cached_geometry().

◆ m_values

std::vector<int> freeciv::multi_slider::m_values
private

Number of items in each category.

Definition at line 83 of file multi_slider.h.

Referenced by add_category(), exchange(), focus_some_category(), grab_item(), move_focus(), move_handle(), paintEvent(), set_values(), total(), values(), and visible_handles().