DynamicPanels Example

#include <QApplication>
#include <QScreen>
#include <QAction>
#include <QMenuBar>
#include <QStatusBar>
#include <QHeaderView>
#include <QSpinBox>
#include <QLabel>
#include <QMdiArea>
#include <QLineEdit>
#include <QComboBox>
#include <QTextEdit>
#include <QPainter>
#include <QDialog>
#include <QTreeWidget>
#include <QTableWidget>
#include <QTimer>
#include <QPaintEvent>
#include <QOpenGLFunctions>

#include "mainwindow.h"
#include "ui_DynamicPanelsDialogForm.h"

/* MainWindow */
MainWindow::MainWindow()
    : m_mdiArea(new QMdiArea),
    m_formCount(0), m_openGLFormCount(0), m_treeCount(0), m_tableCount(0)
{
    m_mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    m_mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    setCentralWidget(m_mdiArea);
    connect(dockPanelManager(), SIGNAL(panelRequested(DockPanelRequestedArgs*)),
        this, SLOT(panelRequested(DockPanelRequestedArgs*)));

    createActions();
    createMenu();
    createToolBar();
    createStatusBar();

    QWidget* child = createMdiChild();
    child->showMaximized();
    child->setFocus();

#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
    const QRect availableGeometry = screen()->availableGeometry();
#else
    const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry();
#endif
    resize(availableGeometry.width() / 2, availableGeometry.height() / 2);
    move((availableGeometry.width() - width()) / 2, (availableGeometry.height() - height()) / 2);

    readSettings();
}

MainWindow::~MainWindow()
{
    writeSettings();
}

void MainWindow::createActions()
{
    m_fileNewAction = new QAction(QIcon(QStringLiteral(":/res/new16x16.png")), tr("&New"), this);
    m_fileNewAction->setShortcuts(QKeySequence::New);
    m_fileNewAction->setStatusTip(tr("Create a new document"));

    m_fileOpenAction = new QAction(QIcon(QStringLiteral(":/res/open16x16.png")), tr("&Open"), this);
    m_fileOpenAction->setShortcuts(QKeySequence::Open);
    m_fileOpenAction->setStatusTip(tr("Open an existing document"));

    m_fileSaveAction = new QAction(QIcon(QStringLiteral(":/res/save16x16.png")), tr("&Save..."), this);
    m_fileSaveAction->setShortcuts(QKeySequence::Save);
    m_fileSaveAction->setStatusTip(tr("Save the active document"));

    m_filePrintAction = new QAction(QIcon(QStringLiteral(":/res/print16x16.png")), tr("Print"), this);
    m_filePrintAction->setStatusTip(tr("Print the active document"));
    m_filePrintAction->setDisabled(true);
    m_filePrintAction->setDisabled(true);

    m_editCutAction = new QAction(QIcon(QStringLiteral(":/res/cut16x16.png")), tr("&Cut"), this);
    m_editCutAction->setShortcuts(QKeySequence::Cut);
    m_editCutAction->setStatusTip(tr("Cut the selection and put it on the Clipboard"));
    m_editCutAction->setDisabled(true);

    m_editCopyAction = new QAction(QIcon(QStringLiteral(":/res/copy16x16.png")), tr("&Copy"), this);
    m_editCopyAction->setShortcuts(QKeySequence::Copy);
    m_editCopyAction->setStatusTip(tr("Copy the selection and put it on the Clipboard"));
    m_editCopyAction->setDisabled(true);

    m_editUndoAction = new QAction(QIcon(QStringLiteral(":/res/undo16x16.png")), tr("Undo"), this);
    m_editUndoAction->setStatusTip(tr("Undo the last action"));
    m_editUndoAction->setDisabled(true);

    m_editRedoAction = new QAction(QIcon(QStringLiteral(":/res/redo16x16.png")), tr("Redo"), this);
    m_editRedoAction->setStatusTip(tr("Redo the previously undone action"));
    m_editRedoAction->setDisabled(true);

    m_createFormAction = new QAction(tr("Form"), this);
    connect(m_createFormAction, SIGNAL(triggered()), this, SLOT(slot_createForm()));
    m_createTreeAction = new QAction(tr("Tree"), this);
    connect(m_createTreeAction, SIGNAL(triggered()), this, SLOT(slot_createTree()));
    m_createTableAction = new QAction(tr("Table"), this);
    connect(m_createTableAction, SIGNAL(triggered()), this, SLOT(slot_createTable()));
    m_createOpenGLAction = new QAction(tr("OpenGL Form"), this);
    connect(m_createOpenGLAction, SIGNAL(triggered()), this, SLOT(slot_createOpenGL()));

    m_createThreeRowsAction = new QAction(tr("3(three) Rows"), this);
    connect(m_createThreeRowsAction, SIGNAL(triggered()), this, SLOT(slot_createThreeRows()));
    m_createThreeColumnsAction  = new QAction(tr("3(three) Columns"), this);
    connect(m_createThreeColumnsAction, SIGNAL(triggered()), this, SLOT(slot_createThreeColumns()));
    m_createThreeTabsAction = new QAction(tr("3(three) Tabs"), this);
    connect(m_createThreeTabsAction, SIGNAL(triggered()), this, SLOT(slot_createThreeTabs()));
}

void MainWindow::createMenu()
{
    m_fileMenu = menuBar()->addMenu(tr("&Create"));
    m_fileMenu->addAction(m_createFormAction);
    m_fileMenu->addAction(m_createTreeAction);
    m_fileMenu->addAction(m_createTableAction);
    m_fileMenu->addAction(m_createOpenGLAction);
    m_fileMenu->addSeparator();
    m_fileMenu->addAction(m_createThreeRowsAction);
    m_fileMenu->addAction(m_createThreeColumnsAction);
    m_fileMenu->addAction(m_createThreeTabsAction);

    m_editMenu = menuBar()->addMenu(tr("&Edit"));

    m_viewMenu = menuBar()->addMenu(tr("&View"));
    addSaveLoadMenu(m_viewMenu);
    m_viewMenu->addSeparator();
    addStyleMenu(m_viewMenu);

    m_helpMenu = menuBar()->addMenu(tr("&Help"));
    m_helpMenu->addAction(m_aboutAction);
}

void MainWindow::createToolBar()
{
    m_fileToolBar = addToolBar(tr("Standard"), Qtitan::DockBarTop);
    m_fileToolBar->addAction(m_fileNewAction);
    m_fileToolBar->addAction(m_fileOpenAction);
    m_fileToolBar->addAction(m_fileSaveAction);
    m_fileToolBar->addSeparator();
    m_fileToolBar->addAction(m_editCutAction);
    m_fileToolBar->addAction(m_editCopyAction);
    m_fileToolBar->addSeparator();
    m_fileToolBar->addAction(m_editUndoAction);
    m_fileToolBar->addAction(m_editRedoAction);
    m_fileToolBar->addSeparator();
    m_fileToolBar->addAction(m_filePrintAction);

    m_fileToolBar->addWidget(new QLabel(tr("   Style:")));
    QAction* stylesAction = m_fileToolBar->addWidget(createComboBoxStyle());
    stylesAction->setToolTip(tr("Styles switcher"));

    m_fileToolBar->addSeparator();
    m_fileToolBar->addAction(m_aboutAction);
}

void MainWindow::createStatusBar()
{
    statusBar()->showMessage(tr("Ready"));
}

QWidget* MainWindow::createMdiChild()
{
    QTextEdit* child = new QTextEdit;
    m_mdiArea->addSubWindow(child);
    return child;
}

void MainWindow::slot_createForm()
{
    DockWidgetPanel* form = createFormPanel();
    insertDockPanel(form, QSize(220, 200), Qtitan::RightDockPanelArea);
}

void MainWindow::slot_createTree()
{
    DockWidgetPanel* tree = createTreePanel();
    insertDockPanel(tree, QSize(220, 200), Qtitan::LeftDockPanelArea);
}

void MainWindow::slot_createTable()
{
    DockWidgetPanel* table = createTablePanel();
    insertDockPanel(table, QSize(220, 200), Qtitan::BottomDockPanelArea);
}

void MainWindow::slot_createOpenGL()
{
    DockWidgetPanel* openGL = createOpenGLPanel();
    insertDockPanel(openGL, QSize(220, 200), Qtitan::LeftDockPanelArea);
}

void MainWindow::slot_createThreeRows()
{
    DockWidgetPanel* form = createFormPanel();
    DockWidgetPanel* tree = createTreePanel();
    DockWidgetPanel* table = createTablePanel();

    insertDockPanel(form, QSize(220, 200), Qtitan::BottomDockPanelArea);
    insertDockPanel(tree, QSize(220, 200), Qtitan::RightDockPanelArea, form);
    insertDockPanel(table, QSize(220, 200), Qtitan::RightDockPanelArea, form);
}

void MainWindow::slot_createThreeColumns()
{
    DockWidgetPanel* form = createFormPanel();
    DockWidgetPanel* tree = createTreePanel();
    DockWidgetPanel* table = createTablePanel();

    insertDockPanel(form, QSize(220, 200), Qtitan::LeftDockPanelArea);
    insertDockPanel(tree, QSize(220, 200), Qtitan::BottomDockPanelArea, form);
    insertDockPanel(table, QSize(220, 200), Qtitan::BottomDockPanelArea, form);
}

void MainWindow::slot_createThreeTabs()
{
    DockWidgetPanel* form = createFormPanel();
    DockWidgetPanel* tree = createTreePanel();
    DockWidgetPanel* table = createTablePanel();

    insertDockPanel(form, QSize(220, 200), Qtitan::RightDockPanelArea);
    insertDockPanel(tree, QSize(220, 200), Qtitan::InsideDockPanelArea, form);
    insertDockPanel(table, QSize(220, 200), Qtitan::InsideDockPanelArea, form);
}

void MainWindow::panelRequested(DockPanelRequestedArgs* args)
{
    DockWidgetPanel* panel = Q_NULL;
    QString id = args->id();
    if (id.contains("form"))
        panel = createFormPanel();
    else if (id.contains("tree"))
        panel = createTreePanel();
    else if (id.contains("table"))
        panel = createTablePanel();
    else if (id.contains("opengl"))
        panel = createOpenGLPanel();
    else
        panel = new DockWidgetPanel(dockPanelManager()); //Default empty panel.

    if (panel != Q_NULL)
    {
        panel->setId(args->id());
        args->setPanel(panel);
        args->setHandled(true);
    }
}

class DialogForm : public QDialog
{
public:
    DialogForm() { m_uiDialog.setupUi(this); }
    Ui::DialogForm m_uiDialog;
};

DockWidgetPanel* MainWindow::createFormPanel()
{
    DockWidgetPanel* panel = new DockWidgetPanel(tr("Form %1").arg(++m_formCount), dockPanelManager());
    DialogForm* dialog = new DialogForm();
    panel->setWidget(dialog);
    return panel;
}

DockWidgetPanel* MainWindow::createTreePanel()
{
    DockWidgetPanel* panel = new DockWidgetPanel(tr("Tree %1").arg(++m_treeCount), dockPanelManager());

    QTreeWidget* treeWidget = new QTreeWidget;
    treeWidget->setAlternatingRowColors(true);
    treeWidget->setMinimumWidth(190);
    treeWidget->setHeaderHidden(true);

    QStringList strings;
    strings.append(tr("Item 1"));
    QTreeWidgetItem* mainItem = new QTreeWidgetItem(strings);
    mainItem->setCheckState(0, Qt::Checked);
    mainItem->setExpanded(false);
    mainItem->setIcon(0, QIcon(QStringLiteral(":/res/open16x16.png")));
    treeWidget->insertTopLevelItem(0, mainItem);

    strings.clear();
    strings.append(tr("Item 2"));
    QTreeWidgetItem* item = new QTreeWidgetItem(mainItem, strings);
    item->setCheckState(0, Qt::Checked);
    item->setIcon(0, QIcon(QStringLiteral(":/res/open16x16.png")));
    item->setExpanded(true);
    treeWidget->insertTopLevelItem(1, item);

    strings.clear();
    strings.append(tr("Item 3"));
    item = new QTreeWidgetItem(mainItem, strings);
    item->setCheckState(0, Qt::Checked);
    item->setIcon(0, QIcon(QStringLiteral(":/res/open16x16.png")));
    item->setExpanded(true);
    treeWidget->insertTopLevelItem(1, item);

    strings.clear();
    strings.append(tr("Item 4"));
    item = new QTreeWidgetItem(mainItem, strings);
    item->setCheckState(0, Qt::Checked);
    item->setIcon(0, QIcon(QStringLiteral(":/res/open16x16.png")));
    item->setExpanded(true);
    treeWidget->insertTopLevelItem(1, item);

    strings.clear();
    strings.append(tr("Item 5"));
    item = new QTreeWidgetItem(mainItem, strings);
    item->setCheckState(0, Qt::Checked);
    item->setIcon(0, QIcon(QStringLiteral(":/res/open16x16.png")));
    item->setExpanded(true);
    treeWidget->insertTopLevelItem(1, item);

    strings.clear();
    strings.append(tr("Item 6"));
    item = new QTreeWidgetItem(mainItem, strings);
    item->setCheckState(0, Qt::Checked);
    item->setIcon(0, QIcon(QStringLiteral(":/res/open16x16.png")));
    item->setExpanded(true);
    treeWidget->insertTopLevelItem(1, item);
    treeWidget->expandAll();

    panel->setWidget(treeWidget);
    return panel;
}

DockWidgetPanel* MainWindow::createTablePanel()
{
    DockWidgetPanel* panel = new DockWidgetPanel(tr("Table %1").arg(++m_tableCount), dockPanelManager());

    QTableWidget* tableWidget = new QTableWidget;
    tableWidget->setAlternatingRowColors(true);
    tableWidget->setColumnCount(11);
    tableWidget->setRowCount(6);
    tableWidget->setShowGrid(false);
    tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
    tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
    tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);

    tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem(tr("Name")));
    tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem(tr("Path")));
    tableWidget->setHorizontalHeaderItem(2, new QTableWidgetItem(tr("Optimized")));
    tableWidget->setHorizontalHeaderItem(3, new QTableWidgetItem(tr("User Code")));
    tableWidget->setHorizontalHeaderItem(4, new QTableWidgetItem(tr("Symbol Status")));
    tableWidget->setHorizontalHeaderItem(5, new QTableWidgetItem(tr("Symbol File")));
    tableWidget->setHorizontalHeaderItem(6, new QTableWidgetItem(tr("Order")));
    tableWidget->setHorizontalHeaderItem(7, new QTableWidgetItem(tr("Version")));
    tableWidget->setHorizontalHeaderItem(8, new QTableWidgetItem(tr("Timestamp")));
    tableWidget->setHorizontalHeaderItem(9, new QTableWidgetItem(tr("Addresswewe")));
    tableWidget->setHorizontalHeaderItem(10, new QTableWidgetItem(tr("Process")));

    int height = tableWidget->horizontalHeader()->sizeHint().height();

    tableWidget->setRowHeight(0, height);
    tableWidget->setVerticalHeaderItem(0, new QTableWidgetItem(QIcon(QStringLiteral(":/res/modules.png")),tr("")));
    tableWidget->setItem(0, 0, new QTableWidgetItem(tr("ntdll.dll")));
    tableWidget->setItem(0, 1, new QTableWidgetItem(tr("C:/Windows/System32/ntdll.dll")));
    tableWidget->setItem(0, 2, new QTableWidgetItem(tr("N/A")));
    tableWidget->setItem(0, 3, new QTableWidgetItem(tr("N/A")));
    tableWidget->setItem(0, 4, new QTableWidgetItem(tr("Symbols loaded.")));
    tableWidget->setItem(0, 5, new QTableWidgetItem(tr("C:/Qtitan/customstyles.pdb")));
    tableWidget->setItem(0, 6, new QTableWidgetItem(tr("1")));
    tableWidget->setItem(0, 7, new QTableWidgetItem(tr("6.1.7600.16385 (win7_rtm.090713-1255)")));
    tableWidget->setItem(0, 8, new QTableWidgetItem(tr("27.10.2010 8:32")));
    tableWidget->setItem(0, 9, new QTableWidgetItem(tr("773A0000-774DD000")));
    tableWidget->setItem(0, 10, new QTableWidgetItem(tr("[3376] customstyles.exe: Native")));

    tableWidget->setRowHeight(1, height);
    tableWidget->setVerticalHeaderItem(1, new QTableWidgetItem(QIcon(QStringLiteral(":/res/modules.png")),tr("")));
    tableWidget->setItem(1, 0, new QTableWidgetItem(tr("ntdll.dll")));
    tableWidget->setItem(1, 1, new QTableWidgetItem(tr("C:/Windows/System32/kernel32.dll")));
    tableWidget->setItem(1, 2, new QTableWidgetItem(tr("N/A")));
    tableWidget->setItem(1, 3, new QTableWidgetItem(tr("N/A")));
    tableWidget->setItem(1, 4, new QTableWidgetItem(tr("No symbols loaded.")));
    tableWidget->setItem(1, 5, new QTableWidgetItem(tr("")));
    tableWidget->setItem(1, 6, new QTableWidgetItem(tr("2")));
    tableWidget->setItem(1, 7, new QTableWidgetItem(tr("6.1.7600.16385 (win7_rtm.090713-1255)")));
    tableWidget->setItem(1, 8, new QTableWidgetItem(tr("27.10.2010 8:32")));
    tableWidget->setItem(1, 9, new QTableWidgetItem(tr("872A0000-766DD000")));
    tableWidget->setItem(1, 10, new QTableWidgetItem(tr("[3376] customstyles.exe: Native")));

    tableWidget->setRowHeight(2, height);
    tableWidget->setVerticalHeaderItem(2, new QTableWidgetItem(QIcon(QStringLiteral(":/res/modules.png")),tr("")));
    tableWidget->setItem(2, 0, new QTableWidgetItem(tr("kernelBase.dll")));
    tableWidget->setItem(2, 1, new QTableWidgetItem(tr("C:/Windows/System32/kernelBase.dll")));
    tableWidget->setItem(2, 2, new QTableWidgetItem(tr("N/A")));
    tableWidget->setItem(2, 3, new QTableWidgetItem(tr("N/A")));
    tableWidget->setItem(2, 4, new QTableWidgetItem(tr("No symbols loaded.")));
    tableWidget->setItem(2, 5, new QTableWidgetItem(tr("")));
    tableWidget->setItem(2, 6, new QTableWidgetItem(tr("3")));
    tableWidget->setItem(2, 7, new QTableWidgetItem(tr("6.1.7600.16385 (win7_rtm.090713-1255)")));
    tableWidget->setItem(2, 8, new QTableWidgetItem(tr("08.10.2010 8:32")));
    tableWidget->setItem(2, 9, new QTableWidgetItem(tr("772A0000-566DD000")));
    tableWidget->setItem(2, 10, new QTableWidgetItem(tr("[3376] customstyles.exe: Native")));

    tableWidget->setRowHeight(3, height);
    tableWidget->setVerticalHeaderItem(3, new QTableWidgetItem(QIcon(QStringLiteral(":/res/modules.png")),tr("")));
    tableWidget->setItem(3, 0, new QTableWidgetItem(tr("QtCoreed4.dll")));
    tableWidget->setItem(3, 1, new QTableWidgetItem(tr("C:/Qt/4.6.2/Bin/QtCored4.dll")));
    tableWidget->setItem(3, 2, new QTableWidgetItem(tr("N/A")));
    tableWidget->setItem(3, 3, new QTableWidgetItem(tr("N/A")));
    tableWidget->setItem(3, 4, new QTableWidgetItem(tr("Symbols loaded.")));
    tableWidget->setItem(3, 5, new QTableWidgetItem(tr("C:/Qt/4.6.2/lib/QtCored4.pdb")));
    tableWidget->setItem(3, 6, new QTableWidgetItem(tr("4")));
    tableWidget->setItem(3, 7, new QTableWidgetItem(tr("6.1.7600.16385 (win7_rtm.090713-1255)")));
    tableWidget->setItem(3, 8, new QTableWidgetItem(tr("08.10.2010 8:32")));
    tableWidget->setItem(3, 9, new QTableWidgetItem(tr("772A0000-566DD000")));
    tableWidget->setItem(3, 10, new QTableWidgetItem(tr("[3376] customstyles.exe: Native")));

    tableWidget->setRowHeight(4, height);
    tableWidget->setVerticalHeaderItem(4, new QTableWidgetItem(QIcon(QStringLiteral(":/res/modules.png")),tr("")));
    tableWidget->setItem(4, 0, new QTableWidgetItem(tr("user32.dll")));
    tableWidget->setItem(4, 1, new QTableWidgetItem(tr("C:/Windows/System32/user32.dll")));
    tableWidget->setItem(4, 2, new QTableWidgetItem(tr("N/A")));
    tableWidget->setItem(4, 3, new QTableWidgetItem(tr("N/A")));
    tableWidget->setItem(4, 4, new QTableWidgetItem(tr("No symbols loaded.")));
    tableWidget->setItem(4, 5, new QTableWidgetItem(tr("")));
    tableWidget->setItem(4, 6, new QTableWidgetItem(tr("3")));
    tableWidget->setItem(4, 7, new QTableWidgetItem(tr("6.1.7600.16385 (win7_rtm.090713-1255)")));
    tableWidget->setItem(4, 8, new QTableWidgetItem(tr("08.10.2010 8:32")));
    tableWidget->setItem(4, 9, new QTableWidgetItem(tr("552A0000-544AD000")));
    tableWidget->setItem(4, 10, new QTableWidgetItem(tr("[3376] customstyles.exe: Native")));

    tableWidget->setRowHeight(5, height);
    tableWidget->setVerticalHeaderItem(5, new QTableWidgetItem(QIcon(QStringLiteral(":/res/modules.png")),tr("")));
    tableWidget->setItem(5, 0, new QTableWidgetItem(tr("usp10.dll")));
    tableWidget->setItem(5, 1, new QTableWidgetItem(tr("C:/Windows/System32/usp10.dll")));
    tableWidget->setItem(5, 2, new QTableWidgetItem(tr("N/A")));
    tableWidget->setItem(5, 3, new QTableWidgetItem(tr("N/A")));
    tableWidget->setItem(5, 4, new QTableWidgetItem(tr("No symbols loaded.")));
    tableWidget->setItem(5, 5, new QTableWidgetItem(tr("")));
    tableWidget->setItem(5, 6, new QTableWidgetItem(tr("3")));
    tableWidget->setItem(5, 7, new QTableWidgetItem(tr("6.1.7600.16385 (win7_rtm.090713-1255)")));
    tableWidget->setItem(5, 8, new QTableWidgetItem(tr("08.10.2010 8:32")));
    tableWidget->setItem(5, 9, new QTableWidgetItem(tr("552A0000-544AD000")));
    tableWidget->setItem(5, 10, new QTableWidgetItem(tr("[3376] customstyles.exe: Native")));

    panel->setWidget(tableWidget);
    return panel;
}

DockWidgetPanel* MainWindow::createOpenGLPanel()
{
    DockWidgetPanel* panel = new DockWidgetPanel(tr("OpenGL %1").arg(++m_openGLFormCount), dockPanelManager());

    GLWidget* glWidget = new GLWidget(m_openGLFormCount, this);
    QTimer* timer = new QTimer(this);
    connect(timer, &QTimer::timeout, glWidget, &GLWidget::animate);
    timer->start(50);
    panel->setWidget(glWidget);
    return panel;
}

/* Helper */
GLWidget::Helper::Helper(int num)
{
    QLinearGradient gradient(QPointF(50, -20), QPointF(80, 20));
    gradient.setColorAt(0.0, QColor(0xFF, 0x00, 0x00));
    gradient.setColorAt(1.0, QColor(0x73, 0x20, 0x1B));

    m_background = QBrush(QColor(46, 46, 46));
    m_circleBrush = QBrush(gradient);
    m_circlePen = QPen(Qt::black);
    m_circlePen.setWidth(1);
    m_textPen = QPen(Qt::white);
    m_textFont.setPixelSize(50);
    m_number = num;
}

void GLWidget::Helper::paint(QPainter* painter, QPaintEvent *event, int elapsed)
{
    painter->fillRect(event->rect(), m_background);
    painter->translate(event->rect().width()/2, event->rect().height()/2);
    painter->save();
    painter->setBrush(m_circleBrush);
    painter->setPen(m_circlePen);
    painter->rotate(elapsed * 0.030);

    qreal r = elapsed / 1000.0;
    int n = 40;
    for (int i = 0; i < n; ++i)
    {
        painter->rotate(30);
        qreal factor = (i + r) / n;
        qreal radius = 0 + 180.0 * factor;
        qreal circleRadius = 1 + factor * 20;
        painter->drawEllipse(QRectF(radius, -circleRadius, circleRadius * 2, circleRadius * 2));
    }
    painter->restore();
    painter->setPen(m_textPen);
    painter->setFont(m_textFont);
    painter->drawText(QRect(-90, -50, 190, 100), Qt::AlignCenter, QStringLiteral("Qtitan %1").arg(m_number));
}

/* GLWidget */
GLWidget::GLWidget(int num, QWidget *parent)
#ifdef OLD_GLWidget
    : QGLWidget(parent)
#else
    : QOpenGLWidget(parent)
#endif
    , m_helper(new Helper(num))
    , m_elapsed(0)
{
//    makeCurrent();
    setAutoFillBackground(false);
}

GLWidget::~GLWidget()
{
    delete m_helper;
}

void GLWidget::animate()
{
    m_elapsed = (m_elapsed + qobject_cast<QTimer*>(sender())->interval()) % 1000;
    update();
}

void GLWidget::paintEvent(QPaintEvent* event)
{
    QPainter painter;
    painter.begin(this);
    painter.setRenderHint(QPainter::Antialiasing);
    m_helper->paint(&painter, event, m_elapsed);
    painter.end();
}