Somewhat fixed keyboard navigation with ribbons; kart selection still thinks that the player name is at the bottom though (because it's added latest)
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/irrlicht@3921 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
67b46fe67c
commit
3dcf00c8d5
@ -39,7 +39,6 @@ RibbonGridWidget::RibbonGridWidget(const bool combo, const int max_rows)
|
|||||||
m_right_widget = NULL;
|
m_right_widget = NULL;
|
||||||
m_type = WTYPE_RIBBON_GRID;
|
m_type = WTYPE_RIBBON_GRID;
|
||||||
m_selected_item = 0;
|
m_selected_item = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
void RibbonGridWidget::add()
|
void RibbonGridWidget::add()
|
||||||
@ -100,6 +99,32 @@ void RibbonGridWidget::add()
|
|||||||
m_left_widget->id = left_arrow->getID();
|
m_left_widget->id = left_arrow->getID();
|
||||||
m_children.push_back( m_left_widget );
|
m_children.push_back( m_left_widget );
|
||||||
|
|
||||||
|
// ---- Determine number of rows and columns
|
||||||
|
|
||||||
|
// Find children size (and ratio)
|
||||||
|
m_child_width = atoi(m_properties[PROP_CHILD_WIDTH].c_str());
|
||||||
|
m_child_height = atoi(m_properties[PROP_CHILD_HEIGHT].c_str());
|
||||||
|
|
||||||
|
if (m_child_width <= 0 || m_child_height <= 0)
|
||||||
|
{
|
||||||
|
std::cerr << "/!\\ Warning /!\\ : ribbon grid widgets require 'child_width' and 'child_height' arguments" << std::endl;
|
||||||
|
m_child_width = 256;
|
||||||
|
m_child_height = 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine row amonunt
|
||||||
|
m_row_amount = (int)round((h-m_label_height) / (float)m_child_height);
|
||||||
|
if (m_row_amount > m_max_rows) m_row_amount = m_max_rows;
|
||||||
|
|
||||||
|
// get and build a list of IDs (by now we may not yet know how many rows we will needs,
|
||||||
|
// but we need to get IDs *now* in order for tabbing to work.
|
||||||
|
m_ids.resize(m_row_amount);
|
||||||
|
for (int i=0; i<m_row_amount; i++)
|
||||||
|
{
|
||||||
|
m_ids[i] = getNewID();
|
||||||
|
std::cout << "ribbon : getNewID returns " << m_ids[i] << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
setSubElements();
|
setSubElements();
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@ -119,39 +144,23 @@ void RibbonGridWidget::setSubElements()
|
|||||||
}
|
}
|
||||||
m_rows.clearWithoutDeleting(); // rows already deleted above, don't double-delete
|
m_rows.clearWithoutDeleting(); // rows already deleted above, don't double-delete
|
||||||
|
|
||||||
// ---- Determine number of rows and columns
|
// ---- determine column amount
|
||||||
// Find children size (and ratio)
|
const float row_height = (float)(h - m_label_height)/(float)m_row_amount;
|
||||||
int child_width, child_height;
|
float ratio_zoom = (float)row_height / (float)(m_child_height - m_label_height);
|
||||||
child_width = atoi(m_properties[PROP_CHILD_WIDTH].c_str());
|
m_col_amount = (int)round( w / ( m_child_width*ratio_zoom ) );
|
||||||
child_height = atoi(m_properties[PROP_CHILD_HEIGHT].c_str());
|
|
||||||
|
|
||||||
if (child_width <= 0 || child_height <= 0)
|
// ajust column amount to not add more items slot than we actually need
|
||||||
{
|
|
||||||
std::cerr << "/!\\ Warning /!\\ : ribbon grid widgets require 'child_width' and 'child_height' arguments" << std::endl;
|
|
||||||
child_width = 256;
|
|
||||||
child_height = 256;
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine row amonunt
|
|
||||||
int row_amount = (int)round((h-m_label_height) / (float)child_height);
|
|
||||||
if (row_amount > m_max_rows) row_amount = m_max_rows;
|
|
||||||
|
|
||||||
// determine column amount
|
|
||||||
const float row_height = (float)(h - m_label_height)/(float)row_amount;
|
|
||||||
float ratio_zoom = (float)row_height / (float)(child_height - m_label_height);
|
|
||||||
m_col_amount = (int)round( w / ( child_width*ratio_zoom ) );
|
|
||||||
|
|
||||||
// ajust row and column amount to not add more items slot than we actually need
|
|
||||||
const int item_count = m_items.size();
|
const int item_count = m_items.size();
|
||||||
std::cout << "item_count=" << item_count << ", row_amount*m_col_amount=" << row_amount*m_col_amount << std::endl;
|
std::cout << "item_count=" << item_count << ", row_amount*m_col_amount=" << m_row_amount*m_col_amount << std::endl;
|
||||||
if (row_amount*m_col_amount > item_count)
|
if (m_row_amount*m_col_amount > item_count)
|
||||||
{
|
{
|
||||||
m_col_amount = ceil((float)item_count/(float)row_amount);
|
m_col_amount = ceil((float)item_count/(float)m_row_amount);
|
||||||
std::cout << "Adjusting m_col_amount to be " << m_col_amount << std::endl;
|
std::cout << "Adjusting m_col_amount to be " << m_col_amount << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Hide arrows when everything is visible
|
// Hide arrows when everything is visible
|
||||||
if (item_count <= row_amount*m_col_amount)
|
if (item_count <= m_row_amount*m_col_amount)
|
||||||
{
|
{
|
||||||
m_left_widget->m_element->setVisible(false);
|
m_left_widget->m_element->setVisible(false);
|
||||||
m_right_widget->m_element->setVisible(false);
|
m_right_widget->m_element->setVisible(false);
|
||||||
@ -163,13 +172,14 @@ void RibbonGridWidget::setSubElements()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add rows
|
// add rows
|
||||||
for(int n=0; n<row_amount; n++)
|
for(int n=0; n<m_row_amount; n++)
|
||||||
{
|
{
|
||||||
RibbonWidget* ribbon;
|
RibbonWidget* ribbon;
|
||||||
if (m_combo)
|
if (m_combo)
|
||||||
ribbon = new RibbonWidget(RIBBON_COMBO);
|
ribbon = new RibbonWidget(RIBBON_COMBO, m_ids[n]);
|
||||||
else
|
else
|
||||||
ribbon = new RibbonWidget(RIBBON_TOOLBAR);
|
ribbon = new RibbonWidget(RIBBON_TOOLBAR, m_ids[n]);
|
||||||
|
|
||||||
ribbon->x = x + m_arrows_w;
|
ribbon->x = x + m_arrows_w;
|
||||||
ribbon->y = y + (int)(n*row_height);
|
ribbon->y = y + (int)(n*row_height);
|
||||||
ribbon->w = w - m_arrows_w*2;
|
ribbon->w = w - m_arrows_w*2;
|
||||||
@ -284,13 +294,13 @@ bool RibbonGridWidget::rightPressed()
|
|||||||
{
|
{
|
||||||
updateLabel();
|
updateLabel();
|
||||||
propagateSelection();
|
propagateSelection();
|
||||||
}
|
|
||||||
|
|
||||||
const int listenerAmount = m_hover_listeners.size();
|
const int listenerAmount = m_hover_listeners.size();
|
||||||
for (int n=0; n<listenerAmount; n++)
|
for (int n=0; n<listenerAmount; n++)
|
||||||
{
|
{
|
||||||
m_hover_listeners[n].onSelectionChanged(this, getSelectedRibbon()->getSelectionIDString());
|
m_hover_listeners[n].onSelectionChanged(this, getSelectedRibbon()->getSelectionIDString());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_rows[0].m_ribbon_type == RIBBON_TOOLBAR) return false;
|
if (m_rows[0].m_ribbon_type == RIBBON_TOOLBAR) return false;
|
||||||
|
|
||||||
@ -304,13 +314,14 @@ bool RibbonGridWidget::leftPressed()
|
|||||||
{
|
{
|
||||||
updateLabel();
|
updateLabel();
|
||||||
propagateSelection();
|
propagateSelection();
|
||||||
}
|
|
||||||
|
|
||||||
const int listenerAmount = m_hover_listeners.size();
|
const int listenerAmount = m_hover_listeners.size();
|
||||||
for (int n=0; n<listenerAmount; n++)
|
for (int n=0; n<listenerAmount; n++)
|
||||||
{
|
{
|
||||||
m_hover_listeners[n].onSelectionChanged(this, w->getSelectionIDString());
|
m_hover_listeners[n].onSelectionChanged(this, w->getSelectionIDString());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (m_rows[0].m_ribbon_type == RIBBON_TOOLBAR) return false;
|
if (m_rows[0].m_ribbon_type == RIBBON_TOOLBAR) return false;
|
||||||
|
|
||||||
@ -390,6 +401,9 @@ void RibbonGridWidget::onRowChange(RibbonWidget* row)
|
|||||||
|
|
||||||
void RibbonGridWidget::scroll(const int x_delta)
|
void RibbonGridWidget::scroll(const int x_delta)
|
||||||
{
|
{
|
||||||
|
// Refuse to scroll when everything is visible
|
||||||
|
if ((int)m_items.size() <= m_row_amount*m_col_amount) return;
|
||||||
|
|
||||||
m_scroll_offset += x_delta;
|
m_scroll_offset += x_delta;
|
||||||
|
|
||||||
const int max_scroll = std::max(m_col_amount, m_needed_cols) - 1;
|
const int max_scroll = std::max(m_col_amount, m_needed_cols) - 1;
|
||||||
|
@ -76,8 +76,16 @@ namespace GUIEngine
|
|||||||
|
|
||||||
int m_scroll_offset;
|
int m_scroll_offset;
|
||||||
int m_needed_cols;
|
int m_needed_cols;
|
||||||
|
|
||||||
|
int m_child_width, m_child_height;
|
||||||
|
|
||||||
|
/** Number of rows and columns. Number of columns can dynamically change, number of row is
|
||||||
|
determined at creation */
|
||||||
|
int m_row_amount;
|
||||||
int m_col_amount;
|
int m_col_amount;
|
||||||
|
|
||||||
int m_max_rows;
|
int m_max_rows;
|
||||||
|
std::vector<int> m_ids;
|
||||||
|
|
||||||
/** Whether this is a "combo" style ribbon grid widget */
|
/** Whether this is a "combo" style ribbon grid widget */
|
||||||
bool m_combo;
|
bool m_combo;
|
||||||
|
@ -26,125 +26,14 @@ using namespace GUIEngine;
|
|||||||
# define round(x) (floor(x+0.5f))
|
# define round(x) (floor(x+0.5f))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
RibbonWidget::RibbonWidget(const RibbonType type)
|
RibbonWidget::RibbonWidget(const RibbonType type, int id)
|
||||||
{
|
{
|
||||||
m_selection = 0;
|
m_selection = 0;
|
||||||
m_ribbon_type = type;
|
m_ribbon_type = type;
|
||||||
m_focus = NULL;
|
m_focus = NULL;
|
||||||
updateSelection();
|
updateSelection();
|
||||||
m_type = WTYPE_RIBBON;
|
m_type = WTYPE_RIBBON;
|
||||||
|
m_given_id = id;
|
||||||
}
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
void RibbonWidget::select(std::string item)
|
|
||||||
{
|
|
||||||
const int subbuttons_amount = m_children.size();
|
|
||||||
|
|
||||||
for(int i=0; i<subbuttons_amount; i++)
|
|
||||||
{
|
|
||||||
if(m_children[i].m_properties[PROP_ID] == item)
|
|
||||||
{
|
|
||||||
m_selection = i;
|
|
||||||
updateSelection();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
bool RibbonWidget::rightPressed()
|
|
||||||
{
|
|
||||||
m_selection++;
|
|
||||||
if(m_selection >= m_children.size())
|
|
||||||
{
|
|
||||||
if(m_event_handler != NULL)
|
|
||||||
{
|
|
||||||
((RibbonGridWidget*)m_event_handler)->scroll(1); // FIXME? - find cleaner way to propagate event to parent
|
|
||||||
m_selection = m_children.size()-1;
|
|
||||||
}
|
|
||||||
else m_selection = 0;
|
|
||||||
}
|
|
||||||
updateSelection();
|
|
||||||
m_focus = m_children.get(m_selection);
|
|
||||||
|
|
||||||
return m_ribbon_type != RIBBON_TOOLBAR;
|
|
||||||
}
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
bool RibbonWidget::leftPressed()
|
|
||||||
{
|
|
||||||
m_selection--;
|
|
||||||
if(m_selection < 0)
|
|
||||||
{
|
|
||||||
if(m_event_handler != NULL)
|
|
||||||
{
|
|
||||||
((RibbonGridWidget*)m_event_handler)->scroll(-1); // FIXME? - find cleaner way to propagate event to parent
|
|
||||||
m_selection = 0;
|
|
||||||
}
|
|
||||||
else m_selection = m_children.size()-1;
|
|
||||||
}
|
|
||||||
updateSelection();
|
|
||||||
m_focus = m_children.get(m_selection);
|
|
||||||
|
|
||||||
return m_ribbon_type != RIBBON_TOOLBAR;
|
|
||||||
}
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
void RibbonWidget::focused()
|
|
||||||
{
|
|
||||||
if(m_focus == NULL) m_focus = m_children.get(m_selection);
|
|
||||||
|
|
||||||
if(m_event_handler != NULL)
|
|
||||||
{
|
|
||||||
GUIEngine::getGUIEnv()->setFocus(m_focus->m_element);
|
|
||||||
((RibbonGridWidget*)m_event_handler)->onRowChange( this );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
bool RibbonWidget::mouseHovered(Widget* child)
|
|
||||||
{
|
|
||||||
const int subbuttons_amount = m_children.size();
|
|
||||||
|
|
||||||
m_focus = child;
|
|
||||||
|
|
||||||
for(int i=0; i<subbuttons_amount; i++)
|
|
||||||
{
|
|
||||||
if(m_children.get(i) == child)
|
|
||||||
{
|
|
||||||
if(m_selection == i) return false; // was already selected, don't send another event
|
|
||||||
if(m_ribbon_type == RIBBON_TOOLBAR) m_selection = i; // don't change selection on hover for others
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateSelection();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
void RibbonWidget::updateSelection()
|
|
||||||
{
|
|
||||||
const int subbuttons_amount = m_children.size();
|
|
||||||
|
|
||||||
for (int i=0; i<subbuttons_amount; i++)
|
|
||||||
{
|
|
||||||
m_children[i].m_selected = (i == m_selection);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subbuttons_amount > 0 && m_ribbon_type == RIBBON_TOOLBAR) m_focus = m_children.get(m_selection);
|
|
||||||
}
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
bool RibbonWidget::transmitEvent(Widget* w, std::string& originator)
|
|
||||||
{
|
|
||||||
const int subbuttons_amount = m_children.size();
|
|
||||||
|
|
||||||
for (int i=0; i<subbuttons_amount; i++)
|
|
||||||
{
|
|
||||||
if (m_children[i].m_properties[PROP_ID] == originator)
|
|
||||||
{
|
|
||||||
m_selection = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateSelection();
|
|
||||||
GUIEngine::getGUIEnv()->setFocus(m_element);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
void RibbonWidget::add()
|
void RibbonWidget::add()
|
||||||
@ -154,7 +43,9 @@ void RibbonWidget::add()
|
|||||||
|
|
||||||
rect<s32> widget_size = rect<s32>(x, y, x + w, y + h);
|
rect<s32> widget_size = rect<s32>(x, y, x + w, y + h);
|
||||||
|
|
||||||
IGUIButton * btn = GUIEngine::getGUIEnv()->addButton(widget_size, m_parent, getNewID(), L"");
|
int id = (m_given_id == -1 ? getNewID() : m_given_id);
|
||||||
|
|
||||||
|
IGUIButton * btn = GUIEngine::getGUIEnv()->addButton(widget_size, m_parent, id, L"");
|
||||||
m_element = btn;
|
m_element = btn;
|
||||||
|
|
||||||
const int subbuttons_amount = m_children.size();
|
const int subbuttons_amount = m_children.size();
|
||||||
@ -304,6 +195,118 @@ void RibbonWidget::add()
|
|||||||
updateSelection();
|
updateSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
void RibbonWidget::select(std::string item)
|
||||||
|
{
|
||||||
|
const int subbuttons_amount = m_children.size();
|
||||||
|
|
||||||
|
for(int i=0; i<subbuttons_amount; i++)
|
||||||
|
{
|
||||||
|
if(m_children[i].m_properties[PROP_ID] == item)
|
||||||
|
{
|
||||||
|
m_selection = i;
|
||||||
|
updateSelection();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
bool RibbonWidget::rightPressed()
|
||||||
|
{
|
||||||
|
m_selection++;
|
||||||
|
if(m_selection >= m_children.size())
|
||||||
|
{
|
||||||
|
if(m_event_handler != NULL)
|
||||||
|
{
|
||||||
|
((RibbonGridWidget*)m_event_handler)->scroll(1); // FIXME? - find cleaner way to propagate event to parent
|
||||||
|
m_selection = m_children.size()-1;
|
||||||
|
}
|
||||||
|
else m_selection = 0;
|
||||||
|
}
|
||||||
|
updateSelection();
|
||||||
|
m_focus = m_children.get(m_selection);
|
||||||
|
|
||||||
|
return m_ribbon_type != RIBBON_TOOLBAR;
|
||||||
|
}
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
bool RibbonWidget::leftPressed()
|
||||||
|
{
|
||||||
|
m_selection--;
|
||||||
|
if(m_selection < 0)
|
||||||
|
{
|
||||||
|
if(m_event_handler != NULL)
|
||||||
|
{
|
||||||
|
((RibbonGridWidget*)m_event_handler)->scroll(-1); // FIXME? - find cleaner way to propagate event to parent
|
||||||
|
m_selection = 0;
|
||||||
|
}
|
||||||
|
else m_selection = m_children.size()-1;
|
||||||
|
}
|
||||||
|
updateSelection();
|
||||||
|
m_focus = m_children.get(m_selection);
|
||||||
|
|
||||||
|
return m_ribbon_type != RIBBON_TOOLBAR;
|
||||||
|
}
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
void RibbonWidget::focused()
|
||||||
|
{
|
||||||
|
if(m_focus == NULL) m_focus = m_children.get(m_selection);
|
||||||
|
|
||||||
|
if(m_event_handler != NULL)
|
||||||
|
{
|
||||||
|
GUIEngine::getGUIEnv()->setFocus(m_focus->m_element);
|
||||||
|
((RibbonGridWidget*)m_event_handler)->onRowChange( this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
bool RibbonWidget::mouseHovered(Widget* child)
|
||||||
|
{
|
||||||
|
const int subbuttons_amount = m_children.size();
|
||||||
|
|
||||||
|
m_focus = child;
|
||||||
|
|
||||||
|
for(int i=0; i<subbuttons_amount; i++)
|
||||||
|
{
|
||||||
|
if(m_children.get(i) == child)
|
||||||
|
{
|
||||||
|
if(m_selection == i) return false; // was already selected, don't send another event
|
||||||
|
if(m_ribbon_type == RIBBON_TOOLBAR) m_selection = i; // don't change selection on hover for others
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateSelection();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
void RibbonWidget::updateSelection()
|
||||||
|
{
|
||||||
|
const int subbuttons_amount = m_children.size();
|
||||||
|
|
||||||
|
for (int i=0; i<subbuttons_amount; i++)
|
||||||
|
{
|
||||||
|
m_children[i].m_selected = (i == m_selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subbuttons_amount > 0 && m_ribbon_type == RIBBON_TOOLBAR) m_focus = m_children.get(m_selection);
|
||||||
|
}
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
bool RibbonWidget::transmitEvent(Widget* w, std::string& originator)
|
||||||
|
{
|
||||||
|
const int subbuttons_amount = m_children.size();
|
||||||
|
|
||||||
|
for (int i=0; i<subbuttons_amount; i++)
|
||||||
|
{
|
||||||
|
if (m_children[i].m_properties[PROP_ID] == originator)
|
||||||
|
{
|
||||||
|
m_selection = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateSelection();
|
||||||
|
GUIEngine::getGUIEnv()->setFocus(m_element);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void RibbonWidget::setLabel(const int id, std::string new_name)
|
void RibbonWidget::setLabel(const int id, std::string new_name)
|
||||||
{
|
{
|
||||||
if(m_labels.size() == 0) return; // ignore this call for ribbons without labels
|
if(m_labels.size() == 0) return; // ignore this call for ribbons without labels
|
||||||
|
@ -46,6 +46,8 @@ namespace GUIEngine
|
|||||||
int m_selection;
|
int m_selection;
|
||||||
RibbonType m_ribbon_type;
|
RibbonType m_ribbon_type;
|
||||||
|
|
||||||
|
int m_given_id;
|
||||||
|
|
||||||
void add();
|
void add();
|
||||||
|
|
||||||
bool rightPressed();
|
bool rightPressed();
|
||||||
@ -60,7 +62,7 @@ namespace GUIEngine
|
|||||||
public:
|
public:
|
||||||
Widget* m_focus;
|
Widget* m_focus;
|
||||||
|
|
||||||
RibbonWidget(const RibbonType type=RIBBON_COMBO);
|
RibbonWidget(const RibbonType type=RIBBON_COMBO, int id=-1);
|
||||||
virtual ~RibbonWidget() {}
|
virtual ~RibbonWidget() {}
|
||||||
|
|
||||||
int getSelection() const { return m_selection; }
|
int getSelection() const { return m_selection; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user