I have lots of custom Qt widgets that have their own layouts and contain lists of even more widgets.
I ended up having a ManagerWidget that controls everything (including listening to all events) and propagating them to the widget that needs to update its content. It seems there are too many methods that just pass the information along.
Is there a better way of doing this? Connecting the classes through signal/slots doesn't really work in this case because there's a map of them and I wouldn't know which one was fired.
Would the Mediator pattern fit in this case?
class ManagerWidget : public QWidget {
public:
map<ID, MainWidgetContainer*> mainWidgetMap;
RecordsContainer *recentRecords; // This widget can contain any number of widgets, each showing a record
// events are caught here and propagated to the widgets
void AddNewEntry(ID id) {
MainWidgetContainer *w = new MainWidgetContainer(id);
mainWidgetMap.insert(id, w);
}
void UpdatePictureWidget(ID id) {
mainWidgetMap.value(id)->UpdatePictureWidget();
}
void AddXItem(ID id, Type1 k) {
if(id == 0)
recentRecords->AddXItem(k);
else
mainWidgetMap.value(id)->AddXItem(k);
}
void UpdateEntry(ID id, string newName) { }
};
class MainWidgetContainer : public QWidget {
public:
NameWidget *name;
PictureWidget *pic;
RecordsContainer *records; // This widget can contain any number of widgets, each showing a record
MainWidgetContainer(ID id) {
name = new NameWidget(id);
records = new RecordsContainer();
pic = new PictureWidget();
// setup layout and add items to records as they come in later
}
AddXItem(Type1 k) { records->AddXItem(k); }
UpdatePictureWidget() { pic->Update(); }
};
class RecordsContainer : public QWidget {
public:
map<Type1, Item*> itemMap;
AddXItem(Type1 k) {
Item *item = new Item(k);
itemMap.insert(k, item);
mainLayout->addWidget(item);
}
AddYItem(Type2 k);
// etc
};
Related
I am using the JUCE framework to create an audio plugin. I have created a Knob class which inherits from the Component class. My Knob class contains references to a Slider & a Label.
In my AudioProcessorEditor class, I initialize several Knob objects. However, none of the Components are visible at run-time. Am I doing something wrong or missing a step?
I have tried declaring Slider & Label objects directly inside of my AudioProcessorEditor class. When I do that, I am able to see the Slider & Label objects successfully at run-time. So I get the feeling that the issue involves my Knob class.
Knob.h
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
class Knob : public Component
{
public:
Knob(String, AudioProcessorEditor*);
~Knob();
void paint (Graphics&) override;
void resized() override;
String Name;
Label *KnobLabel;
Slider *KnobSlider;
AudioProcessorEditor *APE;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Knob)
};
Knob.cpp
#include "Knob.h"
Knob::Knob(String name, AudioProcessorEditor *ape)
{
// In your constructor, you should add any child components, and
// initialise any special settings that your component needs.
this->Name = name;
APE = ape;
KnobLabel = new Label(name);
KnobLabel->setColour(0x1000281, Colours::antiquewhite);
KnobLabel->setAlwaysOnTop(true);
KnobLabel->setFont(10);
KnobSlider = new Slider();
KnobSlider->setAlwaysOnTop(true);
addAndMakeVisible(KnobLabel);
addAndMakeVisible(KnobSlider);
}
void Knob::paint (Graphics& g)
{
/* This demo code just fills the component's background and
draws some placeholder text to get you started.
You should replace everything in this method with your own
drawing code..
*/
g.setColour(Colours::white);
g.fillAll();
}
void Knob::resized()
{
// This method is where you should set the bounds of any child
// components that your component contains..
auto bounds = getLocalBounds();
KnobSlider->setBounds(bounds.removeFromTop(getHeight()*8));
KnobLabel->setBounds(bounds);
}
PluginEditor.h
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
#include "PluginProcessor.h"
#include "Knob.h"
#include "Model.h"
class MoonlightAudioProcessorEditor : public AudioProcessorEditor
{
public:
MoonlightAudioProcessorEditor (MoonlightAudioProcessor&);
~MoonlightAudioProcessorEditor();
void paint (Graphics&) override;
void resized() override;
Knob *OrbitKnob;
Knob *SpaceKnob;
Knob *InertiaKnob;
void ConfigureUI();
private:
OwnedArray<Knob> Knobs;
ComponentBoundsConstrainer ResizeBounds;
ResizableCornerComponent *Resizer;
MoonlightAudioProcessor& processor;
};
PluginEditor.cpp
#include "PluginProcessor.h"
#include "PluginEditor.h"
MoonlightAudioProcessorEditor::MoonlightAudioProcessorEditor (MoonlightAudioProcessor& p)
: AudioProcessorEditor (&p), processor (p)
{
setSize (400, 300);
ConfigureUI();
}
void MoonlightAudioProcessorEditor::ConfigureUI()
{
OrbitKnob = new Knob("Orbit", this);
SpaceKnob = new Knob("Space", this);
InertiaKnob = new Knob("Inertia", this);
Knobs.add(OrbitKnob);
Knobs.add(SpaceKnob);
Knobs.add(InertiaKnob);
for (Knob *knob : Knobs)
{
knob->KnobSlider->addListener(this);
addAndMakeVisible(knob);
knob->setAlwaysOnTop(true);
}
ResizeBounds.setSizeLimits(DEFAULT_WIDTH,
DEFAULT_HEIGHT,
MAX_WIDTH,
MAX_HEIGHT);
Resizer = new ResizableCornerComponent(this, &ResizeBounds);
addAndMakeVisible(Resizer);
setSize(processor._UIWidth, processor._UIHeight);
}
void MoonlightAudioProcessorEditor::paint (Graphics& g)
{
g.setColour (Colours::black);
g.fillAll();
}
void MoonlightAudioProcessorEditor::resized()
{
int width = getWidth();
int height = getHeight();
auto bounds = getLocalBounds();
auto graphicBounds = bounds.removeFromTop(height*.8);
auto orbitBounds = bounds.removeFromLeft(width/3);
auto spaceBounds = bounds.removeFromLeft(width/3);
if (OrbitKnob != nullptr)
{
OrbitKnob->setBounds(orbitBounds);
}
if (SpaceKnob != nullptr)
{
SpaceKnob->setBounds(spaceBounds);
}
if (InertiaKnob != nullptr)
{
InertiaKnob->setBounds(bounds);
}
if (Resizer != nullptr)
{
Resizer->setBounds(width - 16, height - 16, 16, 16);
}
processor._UIWidth = width;
processor._UIHeight = height;
}
Also, I have been using the AudioPluginHost application provided with JUCE to test my plugin. A lot of times the application will crash from a segmentation fault. Then I rebuild the plugin without changing anything and it will work.
I ended up figuring it out.
My components were being initialized after I set the size. A lot of the display logic was in the resize() function so I needed to set the size after component initialization.
You left out a call to Component::Paint(g) in Knob::Paint(Graphics& g)
In my programm, I fill my interface with a lot of checkbox by this way :
void VGCCC::addMaterialToUI(QDomNodeList _materialNodeList, QWidget* _areaWidget, QLayout* _layout, QWidget* _layoutWidget, int _maTable)
{
for(int i=0; i< _materialNodeList.count();i++)
{
QDomElement materialElement = _materialNodeList.at(i).toElement();
QString elementFile = materialElement.attribute("file");
QString elementId = materialElement.attribute("id");
QString elementLabel = elementId;
elementLabel += " - ";
elementLabel += materialElement.attribute("label");
QCheckBox* checkbox = new QCheckBox(elementLabel);
_layout->addWidget(checkbox);
_layoutWidget->adjustSize();
_areaWidget->setMinimumHeight(_layoutWidget->height());
_areaWidget->setMinimumWidth(_layoutWidget->width());
configuration c;
c.path = (m_igmPath+elementFile).toStdString();
c.id = elementId.toInt();
c.name = elementLabel.toStdString();
if(_maTable==0)
{
m_materialSectionMap[checkbox] = c;
}
else
{
m_materialPostMap[checkbox] = c;
}
}
}
I would like to know how to retrieve these "abstract" checkbox. More exactly, if one of these checkbox is checked, I would like to call another function like this :
connect(anyCheckbox,SIGNAL(stateChanged(anyCheckbox)), this, SLOT(doSomethingFunctionIfCheckboxIsChecked()));
The difficulty is that in my UI, these checkbox didn't exist, so I can't connect them to my function. How can I solve it ?
You can e.g. collect pointers to your checkbox objects to a list so can access or "retrieve" them later.
You can connect each checkbox's stateChanged signal to a same slot which is then called when state of any of the checkboxes is changed. In the slot you can cast the sender() to a checkbox if you need to know which specific checkbox is in question. Another alternative is to use QSignalMapper.
In your class declaration:
private slots:
void checkboxStateChanged(int state)
private:
QList<QCheckBox*> m_checkboxes;
In your class definition:
void VGCCC::addMaterialToUI(QDomNodeList _materialNodeList, QWidget* _areaWidget, QLayout* _layout, QWidget* _layoutWidget, int _maTable)
{
...
QCheckBox* checkbox = new QCheckBox(elementLabel);
m_checkboxes.append(checkbox);
connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(checkboxStateChanged(int)));
...
}
void VGCCC::checkboxStateChanged(int state)
{
// Here your can e.g. call doSomethingFunctionIfCheckboxIsChecked()
QCheckBox* checkbox = qobject_cast<QCheckBox*>(sender());
if (checkbox)
{
// checkbox points to the object whose state changed
}
}
In our application that uses Qt 4 and supports touch input, we use the QFileDialog with the options QFileDialog::DontUseNativeDialog and QFileDialog::ExistingFiles.
The first is needed because we set our own stylesheet and that does not work with the native dialog. The second is for needed for selecting multiple files, which is what we want to do.
The problem ist that one can not select multiple files with touch input in the QFileDialog, because we have no "shift" or "ctrl"-key available. In Windows the problem is solved by adding checkboxes to the items. QFileDialog has no checkboxes.
I tried to manipulate the QFileDialog to make it displays check boxes for the items, but I failed.
I tried to exchanged the QFileSystemModel that is used by the underlying QTreeView and QListView, but this breaks the signal-slot connections between the model and the dialog. I could not find a way to restore them because they are burried deep in the private intestants of the dialog.
At this moment the only solution I can imagine is writing a whole new dialog, but I would like to avoid the effort.
So is there a way to add checkboxes to the QFileDialog model views ?
Do you have another idea how selecting multiple files could be made possible?
Is the problem fixed in Qt 5? We want to update anyway.
Thank you for your Help.
As I failed to add checkboxes to the item views, I implemented a "hacky" work-around. It adds an extra checkable button to the dialog that acts as a "ctrl"-key. When the button is checked, multiple files can be selected. The solution is a little bit ugly, because it relies on knowing the internals of the dialog, but it does the job.
So here is the code for the header ...
// file touchfiledialog.h
/*
Event filter that is used to add a shift modifier to left mouse button events.
This is used as a helper class for the TouchFileDialog
*/
class EventFilterCtrlModifier : public QObject
{
Q_OBJECT;
bool addCtrlModifier;
public:
EventFilterCtrlModifier( QObject* parent);
void setAddCtrlModifier(bool b);
protected:
virtual bool eventFilter( QObject* watched, QEvent* e);
};
/*
TouchDialog adds the possibility to select multiple files with touch input to the QFileDialog.
This is done by adding an extra button which can be used as control key replacement.
*/
class QTOOLS_API TouchFileDialog : public QFileDialog
{
Q_OBJECT
EventFilterCtrlModifier* listViewEventFilter;
EventFilterCtrlModifier* treeViewEventFilter;
bool initialized;
public:
TouchFileDialog( QWidget* parent);
protected:
virtual void showEvent( QShowEvent* e);
private slots:
void activateCtrlModifier(bool b);
private:
void initObjectsForMultipleFileSelection();
};
with the implementation ...
// file touchfiledialog.cpp
#include "touchfiledialog.h"
EventFilterCtrlModifier::EventFilterCtrlModifier(QObject* parent)
: QObject(parent)
, addCtrlModifier(false)
{
}
void EventFilterCtrlModifier::setAddCtrlModifier(bool b)
{
addCtrlModifier = b;
}
bool EventFilterCtrlModifier::eventFilter(QObject* watched, QEvent* e)
{
QEvent::Type type = e->type();
if( type == QEvent::MouseButtonPress || type == QEvent::MouseButtonRelease)
{
if( addCtrlModifier)
{
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(e);
// Create and post a new event with ctrl modifier if the event does not already have one.
if( !mouseEvent->modifiers().testFlag(Qt::ControlModifier))
{
QMouseEvent* newEventWithModifier = new QMouseEvent(
type,
mouseEvent->pos(),
mouseEvent->globalPos(),
mouseEvent->button(),
mouseEvent->buttons(),
mouseEvent->modifiers() | Qt::ControlModifier
);
QCoreApplication::postEvent(watched, newEventWithModifier);
return true; // absorb the original event
}
}
}
return false;
}
//#######################################################################################
TouchFileDialog::TouchFileDialog(QWidget* parent)
: QFileDialog(parent)
, listViewEventFilter(NULL)
, treeViewEventFilter(NULL)
, initialized(false)
{
}
void TouchFileDialog::showEvent(QShowEvent* e)
{
// install objects that are needed for multiple file selection if needed
if( !initialized)
{
if( fileMode() == QFileDialog::ExistingFiles)
{
initObjectsForMultipleFileSelection();
}
initialized = true;
}
QFileDialog::showEvent(e);
}
void TouchFileDialog::initObjectsForMultipleFileSelection()
{
// install event filter to item views that are used to add ctrl modifiers to mouse events
listViewEventFilter = new EventFilterCtrlModifier(this);
QListView* listView = findChild<QListView*>();
listView->viewport()->installEventFilter(listViewEventFilter);
treeViewEventFilter = new EventFilterCtrlModifier(this);
QTreeView* treeView = findChild<QTreeView*>();
treeView->viewport()->installEventFilter(treeViewEventFilter);
QGridLayout* dialogLayout = static_cast<QGridLayout*>(layout()); // Ugly because it makes assumptions about the internals of the QFileDialog
QPushButton* pushButtonSelectMultiple = new QPushButton(this);
pushButtonSelectMultiple->setText(tr("Select multiple"));
pushButtonSelectMultiple->setCheckable(true);
connect( pushButtonSelectMultiple, SIGNAL(toggled(bool)), this, SLOT(activateCtrlModifier(bool)));
dialogLayout->addWidget(pushButtonSelectMultiple, 2, 0);
}
void ZFFileDialog::activateCtrlModifier(bool b)
{
listViewEventFilter->setAddCtrlModifier(b);
treeViewEventFilter->setAddCtrlModifier(b);
}
The TouchFileDialog installs an event filter to the item views that will add a ControlModifier to the mouse events of the views when the corresponging button in the dialog is checked.
Feel free to post other solutions, because this is somewhat improvised.
I would like to build up dialog same as Qt Creator "Options" tab that left side page titles with scroll bar and detailed page on the right side.
It would be really helpful if there were code samples or sample applications for reference.
Qt Creator Source Code
Qt Creator has it source code both in Gitorious and in GitHub. But because Qt Creator is such a large and complex project, it can be overwhelming finding its sub parts.
The Github version is very searchable. It ends up that the source related to the nice options page in Qt Creator uses the IOptionsPage as the base class for any of the pages that show up in the Options dialog.
https://github.com/qtproject/qt-creator/search?utf8=%E2%9C%93&q=ioptionspage&type=Code
The ioptionspage.cpp has all the comments explaining the purpose of the different slots.
https://github.com/qtproject/qt-creator/blob/9926fc2ab12ccaa02b7f03b416c54cd58ef30b31/src/plugins/coreplugin/dialogs/ioptionspage.cpp
Basically for Qt Creators options page, it has an interface that is used by several different sub modules.
https://github.com/qtproject/qt-creator/blob/9926fc2ab12ccaa02b7f03b416c54cd58ef30b31/src/plugins/coreplugin/dialogs/ioptionspage.h
#ifndef IOPTIONSPAGE_H
#define IOPTIONSPAGE_H
#include <coreplugin/id.h>
#include <QIcon>
#include <QObject>
#include <QStringList>
namespace Core {
class CORE_EXPORT IOptionsPage : public QObject
{
Q_OBJECT
public:
IOptionsPage(QObject *parent = 0);
virtual ~IOptionsPage();
Id id() const { return m_id; }
QString displayName() const { return m_displayName; }
Id category() const { return m_category; }
QString displayCategory() const { return m_displayCategory; }
QIcon categoryIcon() const { return QIcon(m_categoryIcon); }
virtual bool matches(const QString &searchKeyWord) const;
virtual QWidget *widget() = 0;
virtual void apply() = 0;
virtual void finish() = 0;
protected:
void setId(Id id) { m_id = id; }
void setDisplayName(const QString &displayName) { m_displayName = displayName; }
void setCategory(Id category) { m_category = category; }
void setDisplayCategory(const QString &displayCategory) { m_displayCategory = displayCategory; }
void setCategoryIcon(const QString &categoryIcon) { m_categoryIcon = categoryIcon; }
Id m_id;
Id m_category;
QString m_displayName;
QString m_displayCategory;
QString m_categoryIcon;
mutable bool m_keywordsInitialized;
mutable QStringList m_keywords;
};
/*
Alternative way for providing option pages instead of adding IOptionsPage
objects into the plugin manager pool. Should only be used if creation of the
actual option pages is not possible or too expensive at Qt Creator startup.
(Like the designer integration, which needs to initialize designer plugins
before the options pages get available.)
*/
class CORE_EXPORT IOptionsPageProvider : public QObject
{
Q_OBJECT
public:
IOptionsPageProvider(QObject *parent = 0) : QObject(parent) {}
Id category() const { return m_category; }
QString displayCategory() const { return m_displayCategory; }
QIcon categoryIcon() const { return QIcon(m_categoryIcon); }
virtual QList<IOptionsPage *> pages() const = 0;
virtual bool matches(const QString & /* searchKeyWord*/) const = 0;
protected:
void setCategory(Id category) { m_category = category; }
void setDisplayCategory(const QString &displayCategory) { m_displayCategory = displayCategory; }
void setCategoryIcon(const QString &categoryIcon) { m_categoryIcon = categoryIcon; }
Id m_category;
QString m_displayCategory;
QString m_categoryIcon;
};
} // namespace Core
#endif // IOPTIONSPAGE_H
The search box uses an index the all the titles/labels of the children of each options page that gets added.
bool Core::IOptionsPage::matches(const QString &searchKeyWord) const
{
if (!m_keywordsInitialized) {
IOptionsPage *that = const_cast<IOptionsPage *>(this);
QWidget *widget = that->widget();
if (!widget)
return false;
// find common subwidgets
foreach (const QLabel *label, widget->findChildren<QLabel *>())
m_keywords << label->text();
foreach (const QCheckBox *checkbox, widget->findChildren<QCheckBox *>())
m_keywords << checkbox->text();
foreach (const QPushButton *pushButton, widget->findChildren<QPushButton *>())
m_keywords << pushButton->text();
foreach (const QGroupBox *groupBox, widget->findChildren<QGroupBox *>())
m_keywords << groupBox->title();
// clean up accelerators
QMutableStringListIterator it(m_keywords);
while (it.hasNext())
it.next().remove(QLatin1Char('&'));
m_keywordsInitialized = true;
}
foreach (const QString &keyword, m_keywords)
if (keyword.contains(searchKeyWord, Qt::CaseInsensitive))
return true;
return false;
}
Finding the rest of the components of the original dialog may take some time, but it is doable.
Included Example
When in Qt Creator > Welcome (tab) > Examples, the best one for a complex settings dialog is probably:
Tab Dialog Example
http://doc.qt.io/qt-5/qtwidgets-dialogs-tabdialog-example.html
Persistent Settings
QSettings is probably the best bet for storing settings. Other options include XML, and JSON. Qt 5 has a great implementation of JSON.
Hope that helps.
I'm trying to write an OO menu system for a game, loosely based on the idea of a Model,View,Controller. In my app so far I've named the views "renderers" and the models are without a suffix. I created a generic menu class which stores the items of a menu, which are menu_item objects, and there is also a menu renderer class which creates renderers for each item and renders them. The problem is I'm not sure where to store the data and logic to do with where on the screen each item should be positioned, and how to check if it is being hovered over, etc. My original idea was to store and set a selected property on each menu item, which could be rendered differently by different views, but even then how to I deal with positioning the graphical elements that make up the button?
Code excerpts so far follow: (more code at https://gist.github.com/3422226)
/**
* Abstract menu model
*
* Menus have many items and have properties such as a title
*/
class menu {
protected:
std::string _title;
std::vector<menu_item*> _items;
public:
std::string get_title();
void set_title(std::string);
std::vector<menu_item*> get_items();
};
class menu_controller: public controller {
private:
menu* _menu;
public:
menu_controller(menu*);
virtual void update();
};
class menu_item {
protected:
std::string _title;
public:
menu_item(std::string title);
virtual ~menu_item();
std::string get_title();
};
class menu_renderer: public renderer {
private:
menu* _menu;
bitmap _background_bitmap;
static font _title_font;
std::map<menu_item*, menu_item_renderer*> _item_renderers;
public:
menu_renderer(menu*);
virtual void render();
};
font menu_renderer::_title_font = NULL;
menu_renderer::menu_renderer(menu* menu) {
_menu = menu;
_background_bitmap = ::load_bitmap("blackjack_menu_bg.jpg");
if (!_title_font)
_title_font = ::load_font("maven_pro_regular.ttf",48);
}
void menu_renderer::render() {
::draw_bitmap(_background_bitmap, 0, 0);
/* Draw the menu title */
const char* title = _menu->get_title().c_str();
int title_width = ::text_width(_title_font, title);
::draw_text(title, color_white, _title_font, screen_width() - title_width - 20, 20);
/* Render each menu item */
std::vector<menu_item*> items = _menu->get_items();
for (std::vector<menu_item*>::iterator it = items.begin(); it != items.end(); ++it) {
menu_item* item = *it;
if (!_item_renderers.count(item))
_item_renderers[item] = new menu_item_renderer(item, it - items.begin());
_item_renderers[item]->render();
}
}
class menu_item_renderer: public renderer {
private:
unsigned _order;
menu_item* _item;
static font _title_font;
public:
menu_item_renderer(menu_item*, unsigned);
virtual ~menu_item_renderer();
virtual void render();
};
font menu_item_renderer::_title_font = NULL;
menu_item_renderer::menu_item_renderer(menu_item* item, unsigned order) {
_item = item;
_order = order;
if (!_title_font)
_title_font = ::load_font("maven_pro_regular.ttf",24);
}
menu_item_renderer::~menu_item_renderer() {
// TODO Auto-generated destructor stub
}
void menu_item_renderer::render() {
const char* title = _item->get_title().c_str();
int title_width = ::text_width(_title_font, title);
unsigned y = 44 * _order + 20;
::fill_rectangle(color_red, 20, y, title_width + 40, 34);
::draw_text(title, color_white, _title_font, 30, y + 5);
}
Your Model class menu needs a add_view(menuview *v) and update() method.
Then you can delegate the update of your widget to the derived View (menu_renderer or a cli_menu_renderer).
The Controller needs to know the Model (as member), when the Controller runs (or executes a Command) and has to update the Model with a Setter (like m_menu_model->set_selected(item, state)) and the Model calls update() on Setters.
Your Controller menu_controller has a update method, there you could also ask for Input, like if (menuview->toggle_select()) m_menu_model->toggle_selected(); (which all menuviews have to implement) and invoke the setter, but thats a inflexible coupling of View and Controller (you could check MVC with the Command Pattern for a more advanced combination).
For the Position you can set member vars like int m_x, m_y, m_w, m_h.
But these members are specific to a View with GUI, so only the derived View needs them.
Then you could use these values to compare against mouse Positions and use a MouseOver Detection Method like this:
// View menu_item
bool menu_item::over()
{
if (::mouse_x > m_x
&& ::mouse_x < m_x + m_w
&& ::mouse_y > m_y
&& ::mouse_y < m_y + m_h) {
return true;
}
return false;
}
// update on gui menu item
bool menu_item::update()
{
if (over()) {
m_over = true;
}
else {
m_over = false;
}
// onclick for the idea
if ((::mouse_b & 1) && m_over) {
// here you could invoke a callback or fire event
m_selected = 1;
} else {
m_selected = 0;
}
return m_selected;
}
// update the command line interface menu item
bool cli_menu_item::update()
{
if ((::enterKeyPressed & 1) && m_selected) {
// here you could invoke a callback or fire event
m_selected = 1;
} else {
m_selected = 0;
}
return m_selected;
}
void menu_item_renderer::render() {
// update widgets
_item->update();
// ...
}
// Model
void menu::add_view(menuview *v) {
m_view=v;
}
void menu::update() {
if (m_view) m_view->update();
}
bool menu::set_selected(int item, int state) {
m_item[index]=state;
update();
}