From c8d3638b9ebc24e4766714da1c9f961e350799c6 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Tue, 28 Oct 2014 11:19:24 +0100 Subject: qeditor: introduce new "sexy register display" Change-Id: Ib938b4be71d2c7623851dbc3c211f96105077d7d --- utils/regtools/qeditor/qeditor.pro | 2 +- utils/regtools/qeditor/regdisplaypanel.cpp | 13 +- utils/regtools/qeditor/regdisplaypanel.h | 2 +- utils/regtools/qeditor/regedit.cpp | 54 +++--- utils/regtools/qeditor/regedit.h | 6 +- utils/regtools/qeditor/utils.cpp | 261 ++++++++++++++++++++--------- utils/regtools/qeditor/utils.h | 82 +++++++-- 7 files changed, 286 insertions(+), 134 deletions(-) (limited to 'utils/regtools/qeditor') diff --git a/utils/regtools/qeditor/qeditor.pro b/utils/regtools/qeditor/qeditor.pro index 39b6c76cc9..eecc0aba3f 100644 --- a/utils/regtools/qeditor/qeditor.pro +++ b/utils/regtools/qeditor/qeditor.pro @@ -12,7 +12,7 @@ libsocdesc.commands = cd ../lib && make QMAKE_EXTRA_TARGETS += libsocdesc PRE_TARGETDEPS += libsocdesc -VERSION = 2.0.3 +VERSION = 2.0.4 DEFINES += APP_VERSION=\\\"$$VERSION\\\" diff --git a/utils/regtools/qeditor/regdisplaypanel.cpp b/utils/regtools/qeditor/regdisplaypanel.cpp index 3dbdb54241..167c776cce 100644 --- a/utils/regtools/qeditor/regdisplaypanel.cpp +++ b/utils/regtools/qeditor/regdisplaypanel.cpp @@ -196,7 +196,7 @@ RegDisplayPanel::RegDisplayPanel(QWidget *parent, IoBackend *io_backend, const S raw_val_layout->addWidget(m_raw_val_edit); raw_val_layout->addStretch(); - m_value_table = new GrowingTableView; + m_value_table = new GrowingTableView(); m_value_model = new RegFieldTableModel(m_value_table); // view takes ownership m_value_model->SetRegister(m_reg.GetReg()); m_value_model->SetReadOnly(read_only); @@ -208,7 +208,7 @@ RegDisplayPanel::RegDisplayPanel(QWidget *parent, IoBackend *io_backend, const S // FIXME we cannot use setAlternatingRowColors() because we override the // background color, should it be part of the model ? - SocFieldCachedItemDelegate *m_table_delegate = new SocFieldCachedItemDelegate(this); + m_table_delegate = new SocFieldCachedItemDelegate(this); m_table_edit_factory = new QItemEditorFactory(); SocFieldCachedEditorCreator *m_table_edit_creator = new SocFieldCachedEditorCreator(); // FIXME see QTBUG-30392 @@ -217,8 +217,10 @@ RegDisplayPanel::RegDisplayPanel(QWidget *parent, IoBackend *io_backend, const S m_table_delegate->setItemEditorFactory(m_table_edit_factory); m_value_table->setItemDelegate(m_table_delegate); - m_sexy_display = new RegSexyDisplay(reg_ref, this); - m_sexy_display->setFont(m_reg_font); + m_sexy_display2 = new Unscroll(this); + m_sexy_display2->setFont(m_reg_font); + m_sexy_display2->setModel(m_value_model); + m_sexy_display2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_desc = new QLabel(this); m_desc->setTextFormat(Qt::RichText); @@ -228,8 +230,9 @@ RegDisplayPanel::RegDisplayPanel(QWidget *parent, IoBackend *io_backend, const S right_layout->addLayout(top_layout); if(raw_val_layout) right_layout->addLayout(raw_val_layout); - right_layout->addWidget(m_sexy_display); + right_layout->addWidget(m_sexy_display2); right_layout->addWidget(m_value_table); + right_layout->addStretch(); setTitle("Register Description"); m_viewport = new QWidget; diff --git a/utils/regtools/qeditor/regdisplaypanel.h b/utils/regtools/qeditor/regdisplaypanel.h index 313fc7e369..9a692778fe 100644 --- a/utils/regtools/qeditor/regdisplaypanel.h +++ b/utils/regtools/qeditor/regdisplaypanel.h @@ -105,7 +105,7 @@ protected: const SocRegRef& m_reg; bool m_allow_write; RegLineEdit *m_raw_val_edit; - RegSexyDisplay *m_sexy_display; + Unscroll< RegSexyDisplay2 > *m_sexy_display2; GrowingTableView *m_value_table; RegFieldTableModel *m_value_model; QStyledItemDelegate *m_table_delegate; diff --git a/utils/regtools/qeditor/regedit.cpp b/utils/regtools/qeditor/regedit.cpp index 9dca6280e0..851e054eb0 100644 --- a/utils/regtools/qeditor/regedit.cpp +++ b/utils/regtools/qeditor/regedit.cpp @@ -336,47 +336,33 @@ RegEditPanel::RegEditPanel(SocRegRef ref, QWidget *parent) top_layout->addLayout(name_layout); top_layout->addWidget(m_desc_group, 1); - m_sexy_display = new RegSexyDisplay(m_ref, this); - m_sexy_display->setFont(m_reg_font); + m_value_table = new QTableView(this); + m_value_model = new RegFieldTableModel(m_value_table); // view takes ownership + m_value_model->SetRegister(m_ref.GetReg()); + m_value_model->SetReadOnly(true); + m_value_table->setModel(m_value_model); + m_value_table->verticalHeader()->setVisible(false); + m_value_table->horizontalHeader()->setStretchLastSection(true); + m_value_table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + // FIXME we cannot use setAlternatingRowColors() because we override the + // background color, should it be part of the model ? + m_table_delegate = new SocFieldCachedItemDelegate(this); + m_value_table->setItemDelegate(m_table_delegate); + m_value_table->resizeColumnsToContents(); + + m_sexy_display2 = new Unscroll(this); + m_sexy_display2->setFont(m_reg_font); + m_sexy_display2->setModel(m_value_model); + m_sexy_display2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - m_field_table = new QTableWidget; - m_field_table->setRowCount(m_ref.GetReg().field.size()); - m_field_table->setColumnCount(4); - for(size_t row = 0; row < m_ref.GetReg().field.size(); row++) - { - const soc_reg_field_t& field = m_ref.GetReg().field[row]; - QString bits_str; - if(field.first_bit == field.last_bit) - bits_str.sprintf("%d", field.first_bit); - else - bits_str.sprintf("%d:%d", field.last_bit, field.first_bit); - QTableWidgetItem *item = new QTableWidgetItem(bits_str); - item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter); - item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - m_field_table->setItem(row, 1, item); - item = new QTableWidgetItem(QString(field.name.c_str())); - item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - m_field_table->setItem(row, 2, item); - item = new QTableWidgetItem(QString(field.desc.c_str())); - item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - m_field_table->setItem(row, 3, item); - UpdateWarning(row); - } - m_field_table->setHorizontalHeaderItem(0, new QTableWidgetItem("")); - m_field_table->setHorizontalHeaderItem(1, new QTableWidgetItem("Bits")); - m_field_table->setHorizontalHeaderItem(2, new QTableWidgetItem("Name")); - m_field_table->setHorizontalHeaderItem(3, new QTableWidgetItem("Description")); - m_field_table->verticalHeader()->setVisible(false); - m_field_table->resizeColumnsToContents(); - m_field_table->horizontalHeader()->setStretchLastSection(true); QHBoxLayout *field_layout = new QHBoxLayout; - field_layout->addWidget(m_field_table); + field_layout->addWidget(m_value_table); m_field_group = new QGroupBox("Flags", this); m_field_group->setLayout(field_layout); QVBoxLayout *layout = new QVBoxLayout; layout->addLayout(top_layout, 0); - layout->addWidget(m_sexy_display, 0); + layout->addWidget(m_sexy_display2, 0); layout->addWidget(m_field_group); UpdateFormula(); diff --git a/utils/regtools/qeditor/regedit.h b/utils/regtools/qeditor/regedit.h index 96c4875833..c56f0d9026 100644 --- a/utils/regtools/qeditor/regedit.h +++ b/utils/regtools/qeditor/regedit.h @@ -185,10 +185,12 @@ protected: QComboBox *m_formula_combo; QLineEdit *m_formula_string_edit; QPushButton *m_formula_string_gen; - RegSexyDisplay *m_sexy_display; + Unscroll< RegSexyDisplay2 > *m_sexy_display2; MyTextEditor *m_desc_edit; QGroupBox *m_field_group; - QTableWidget *m_field_table; + QTableView *m_value_table; + RegFieldTableModel *m_value_model; + QStyledItemDelegate *m_table_delegate; }; class FieldEditPanel : public QWidget, public AbstractRegEditPanel diff --git a/utils/regtools/qeditor/utils.cpp b/utils/regtools/qeditor/utils.cpp index 4116dbcc81..e4a872ed49 100644 --- a/utils/regtools/qeditor/utils.cpp +++ b/utils/regtools/qeditor/utils.cpp @@ -669,104 +669,178 @@ void RegFieldTableModel::RecomputeTheme() } /** - * RegSexyDisplay + * RegSexyDisplay2 */ -RegSexyDisplay::RegSexyDisplay(const SocRegRef& reg, QWidget *parent) - :QWidget(parent), m_reg(reg) + +RegSexyDisplay2::RegSexyDisplay2(QWidget *parent) + :QAbstractItemView(parent) +{ + m_is_dirty = true; + // the frame around the register is ugly, disable it + setFrameShape(QFrame::NoFrame); +} + +QModelIndex RegSexyDisplay2::indexAt(const QPoint& point) const +{ + Q_UNUSED(point); + return QModelIndex(); +} + +void RegSexyDisplay2::scrollTo(const QModelIndex& index, ScrollHint hint) +{ + Q_UNUSED(index); + Q_UNUSED(hint); +} + +QRect RegSexyDisplay2::visualRect(const QModelIndex& index) const +{ + Q_UNUSED(index); + return QRect(); +} + +bool RegSexyDisplay2::isIndexHidden(const QModelIndex& index) const +{ + Q_UNUSED(index); + return false; +} + +QModelIndex RegSexyDisplay2::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) +{ + Q_UNUSED(cursorAction); + Q_UNUSED(modifiers); + return QModelIndex(); +} + +void RegSexyDisplay2::setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags flags) +{ + Q_UNUSED(rect); + Q_UNUSED(flags); +} + +int RegSexyDisplay2::verticalOffset() const +{ + return verticalScrollBar()->value(); +} + +int RegSexyDisplay2::horizontalOffset() const +{ + return horizontalScrollBar()->value(); +} + +void RegSexyDisplay2::scrollContentsBy(int dx, int dy) +{ + viewport()->scroll(dx, dy); +} + +void RegSexyDisplay2::setModel(QAbstractItemModel *model) { - m_size = QSize(); + QAbstractItemView::setModel(model); + m_is_dirty = true; } -int RegSexyDisplay::separatorSize() const +void RegSexyDisplay2::dataChanged(const QModelIndex &topLeft, + const QModelIndex &bottomRight) +{ + m_is_dirty = true; + QAbstractItemView::dataChanged(topLeft, bottomRight); +} + +void RegSexyDisplay2::rowsInserted(const QModelIndex &parent, int start, int end) +{ + m_is_dirty = true; + QAbstractItemView::rowsInserted(parent, start, end); +} + +void RegSexyDisplay2::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +{ + m_is_dirty = true; + QAbstractItemView::rowsAboutToBeRemoved(parent, start, end); +} + +int RegSexyDisplay2::GetSeparatorSize() const { return 1; } -int RegSexyDisplay::marginSize() const +int RegSexyDisplay2::GetMarginSize() const { - return fontMetrics().height() / 3; + return viewOptions().fontMetrics.height() / 3; } -int RegSexyDisplay::textSep() const +int RegSexyDisplay2::GetHeaderTextSep() const { - return marginSize() / 2; + return GetMarginSize() / 2; } -int RegSexyDisplay::headerHeight() const +int RegSexyDisplay2::GetHeaderHeight() const { - return 2 * marginSize() + textSep() + 2 * fontMetrics().height(); + return 2 * GetMarginSize() + GetHeaderTextSep() + 2 * viewOptions().fontMetrics.height(); } -int RegSexyDisplay::columnWidth() const +int RegSexyDisplay2::GetColumnWidth() const { - return 2 * marginSize() + fontMetrics().height(); + return 2 * GetMarginSize() + viewOptions().fontMetrics.height(); } -int RegSexyDisplay::maxContentHeight() const +int RegSexyDisplay2::GetMaxContentHeight() const { int max = 0; - QFontMetrics metrics = fontMetrics(); - for(size_t i = 0; i < m_reg.GetReg().field.size(); i++) + QFontMetrics metrics = viewOptions().fontMetrics; + if(model()) { - QString s = QString::fromStdString(m_reg.GetReg().field[i].name); - // add extra spaces arounds - s = " " + s + " "; - max = qMax(max, metrics.boundingRect(s).width()); + for(int i = 0; i < model()->rowCount(); i++) + { + QModelIndex index = model()->index(i, 1, rootIndex()); + QString s = model()->data(index).toString(); + max = qMax(max, metrics.boundingRect(s).width()); + } } - return 2 * marginSize() + max; -} - -int RegSexyDisplay::gapHeight() const -{ - return marginSize() / 2; + return 2 * GetMarginSize() + max; } -QSize RegSexyDisplay::minimumSizeHint() const +int RegSexyDisplay2::GetGapHeight() const { - /* cache computation because it's expensive */ - if(m_size.isValid()) - return m_size; - /* width: display 32 columns + 33 vertical separators */ - m_size.setWidth(32 * columnWidth() + 33 * separatorSize()); - /* height: one separator + two digits + one separator + margin + separator - * + names + separator */ - m_size.setHeight(4 * separatorSize() + headerHeight() + gapHeight() + maxContentHeight()); - return m_size; + return GetMarginSize() / 2; } -QSize RegSexyDisplay::sizeHint() const +QRegion RegSexyDisplay2::visualRegionForSelection(const QItemSelection& selection) const { - return minimumSizeHint(); + Q_UNUSED(selection); + return QRegion(); } -void RegSexyDisplay::paintEvent(QPaintEvent *event) +void RegSexyDisplay2::paintEvent(QPaintEvent *event) { - // FIXME could be optimised with QStaticText Q_UNUSED(event); - int txt_h = fontMetrics().height(); - int sep_sz = separatorSize(); - int w = width(); - int h = height() - 1; - int col_w = (w - 33 * sep_sz) / 32; - int hdr_h = headerHeight(); - int gap_h = gapHeight(); - int tot_w = 33 * sep_sz + 32 * col_w; - int margin = marginSize(); - int txt_sep = textSep(); + int txt_h = viewOptions().fontMetrics.height(); + int sep_sz = GetSeparatorSize(); + int w = qMax(m_minimum_width, viewport()->width()); + int h = qMax(m_minimum_height, viewport()->height()); + int nr_bits = 32; + int col_w = (w - (nr_bits + 1) * sep_sz) / nr_bits; + int hdr_h = GetHeaderHeight(); + int gap_h = GetGapHeight(); + int tot_w = (nr_bits + 1) * sep_sz + nr_bits * col_w; + int margin = GetMarginSize(); + int txt_sep = GetHeaderTextSep(); int tot_hdr_sz = 2 * sep_sz + hdr_h; - // computer xshift + int x_shift = (w - tot_w) / 2; #define ith_col_x(i) (x_shift + (i) * (sep_sz + col_w)) - QPainter painter(this); - QBrush back_brush = palette().base(); - QBrush line_brush = palette().dark(); + QPainter painter(viewport()); + painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); + painter.translate(-horizontalScrollBar()->value(), -verticalScrollBar()->value()); + QStyleOptionViewItem option = viewOptions(); + QBrush back_brush = option.palette.base(); + QBrush line_brush = option.palette.dark(); // fill interesting zone with base + painter.fillRect(event->rect(), option.palette.window()); painter.fillRect(x_shift, 0, tot_w, h, back_brush); // draw top and bottom lines - painter.setPen(QPen(palette().dark(), sep_sz)); + painter.setPen(QPen(line_brush, sep_sz)); painter.fillRect(x_shift, 0, tot_w, sep_sz, line_brush); painter.fillRect(x_shift, h - sep_sz, tot_w, sep_sz, line_brush); // draw intemediate lines @@ -776,38 +850,76 @@ void RegSexyDisplay::paintEvent(QPaintEvent *event) painter.fillRect(ith_col_x(0), sep_sz + hdr_h, tot_w, sep_sz, line_brush); painter.fillRect(ith_col_x(0), tot_hdr_sz + gap_h, tot_w, sep_sz, line_brush); // redraw some lines but wider - for(int i = 4; i < 32; i += 4) + for(int i = 4; i < nr_bits; i += 4) painter.fillRect(ith_col_x(i) - sep_sz, 0, 3 * sep_sz, tot_hdr_sz, line_brush); // draw numbers in the header painter.setPen(palette().brush(QPalette::ButtonText).color()); - for(int i = 0; i < 32; i++) + for(int i = 0; i < nr_bits; i++) { QRect r(ith_col_x(i), sep_sz + margin, col_w, txt_h); - painter.drawText(r, Qt::AlignCenter, QString("%1").arg((31 - i) / 10)); + painter.drawText(r, Qt::AlignCenter, QString("%1").arg((nr_bits - 1 - i) / 10)); r.translate(0, txt_h + txt_sep); - painter.drawText(r, Qt::AlignCenter, QString("%1").arg((31 - i) % 10)); + painter.drawText(r, Qt::AlignCenter, QString("%1").arg((nr_bits - 1 - i) % 10)); } // display content - for(size_t i = 0; i < m_reg.GetReg().field.size(); i++) + if(model()) { - const soc_reg_field_t& field = m_reg.GetReg().field[i]; - QRect r(QPoint(ith_col_x(31 - field.last_bit) + sep_sz, tot_hdr_sz), - QPoint(ith_col_x(32 - field.first_bit), h - sep_sz)); - painter.fillRect(r.x() - sep_sz, r.y(), sep_sz, r.height(), line_brush); - painter.fillRect(r.right(), r.y(), sep_sz, r.height(), line_brush); - r.setY(r.y() + gap_h + sep_sz); - // draw rotated text - painter.save(); - painter.translate(r.bottomLeft()); - painter.rotate(-90); - //painter.fillRect(QRect(0, 0, r.height(), r.width()), QBrush(Qt::red)); - QRect r2(0, 0, r.height(), r.width()); - painter.drawText(r2, Qt::AlignCenter, QString::fromStdString(field.name)); - painter.restore(); + for(int i = 0; i < model()->rowCount(); i++) + { + QVariant vrange = model()->data(model()->index(i, 0, rootIndex())); + if(!vrange.canConvert< SocFieldBitRange >()) + continue; + SocFieldBitRange range = vrange.value< SocFieldBitRange >(); + QString name = model()->data(model()->index(i, 1, rootIndex())).toString(); + QRect r(QPoint(ith_col_x(nr_bits - 1 - range.GetLastBit()) + sep_sz, tot_hdr_sz), + QPoint(ith_col_x(nr_bits - range.GetFirstBit()), h - sep_sz)); + painter.fillRect(r.x() - sep_sz, r.y(), sep_sz, r.height(), line_brush); + painter.fillRect(r.right(), r.y(), sep_sz, r.height(), line_brush); + r.setY(r.y() + gap_h + sep_sz); + // draw rotated text + painter.save(); + painter.translate(r.bottomLeft()); + painter.rotate(-90); + //painter.fillRect(QRect(0, 0, r.height(), r.width()), QBrush(Qt::red)); + QRect r2(0, 0, r.height(), r.width()); + painter.drawText(r2, Qt::AlignCenter, name); + painter.restore(); + } } #undef ith_col_x } +void RegSexyDisplay2::RecomputeGeometry() +{ + if(!m_is_dirty) + return; + /* height: header + gap + sep + content + sep */ + m_minimum_height = 0; + m_minimum_height += GetHeaderHeight() + GetGapHeight(); + m_minimum_height += 2 * GetSeparatorSize() + GetMaxContentHeight(); + /* width: sep + (col + sep) * n */ + m_minimum_width = GetSeparatorSize() * 33 + GetColumnWidth() * 32; + m_is_dirty = false; + viewport()->update(); +} + +void RegSexyDisplay2::resizeEvent(QResizeEvent*) +{ + m_is_dirty = true; + RecomputeGeometry(); + updateGeometries(); +} + +void RegSexyDisplay2::updateGeometries() +{ + horizontalScrollBar()->setSingleStep(1); + horizontalScrollBar()->setPageStep(viewport()->width()); + horizontalScrollBar()->setRange(0, qMax(0, m_minimum_width - viewport()->width())); + verticalScrollBar()->setSingleStep(1); + verticalScrollBar()->setPageStep(viewport()->height()); + verticalScrollBar()->setRange(0, qMax(0, m_minimum_height - viewport()->height())); +} + /** * GrowingTableView */ @@ -831,7 +943,6 @@ void GrowingTableView::DataChanged(const QModelIndex& tl, const QModelIndex& br) { Q_UNUSED(tl); Q_UNUSED(br); - resizeRowsToContents(); resizeColumnsToContents(); int h = contentsMargins().top() + contentsMargins().bottom(); h += horizontalHeader()->height(); diff --git a/utils/regtools/qeditor/utils.h b/utils/regtools/qeditor/utils.h index c78b0a40e4..078f3a85d7 100644 --- a/utils/regtools/qeditor/utils.h +++ b/utils/regtools/qeditor/utils.h @@ -37,6 +37,7 @@ #include #include #include +#include #include "settings.h" #include "backend.h" @@ -292,28 +293,77 @@ protected: bool m_read_only; }; -class RegSexyDisplay : public QWidget +class RegSexyDisplay2 : public QAbstractItemView { Q_OBJECT public: - RegSexyDisplay(const SocRegRef& reg, QWidget *parent = 0); + RegSexyDisplay2(QWidget *parent = 0); + virtual QModelIndex indexAt(const QPoint& point) const; + virtual void scrollTo(const QModelIndex& index, ScrollHint hint = EnsureVisible); + virtual QRect visualRect(const QModelIndex& index ) const; + virtual void setModel(QAbstractItemModel *model); - QSize minimumSizeHint() const; - QSize sizeHint() const; +protected slots: + virtual void dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); + virtual void rowsInserted(const QModelIndex &parent, int start, int end); + virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); + virtual void scrollContentsBy(int dx, int dy); + virtual void updateGeometries(); protected: - int marginSize() const; - int separatorSize() const; - int columnWidth() const; - int headerHeight() const; - int gapHeight() const; - int maxContentHeight() const; - int textSep() const; - void paintEvent(QPaintEvent *event); - -private: - SocRegRef m_reg; - mutable QSize m_size; + int GetMarginSize() const; // margin in cells + int GetSeparatorSize() const; // size of lines betweens cells + int GetColumnWidth() const; // width of a 1-bit column (excluding separators) + int GetHeaderHeight() const; // height of the header (excluding separators) + int GetGapHeight() const; // height of gap between header and fields + int GetMaxContentHeight() const; // maximum height of field columns + int GetHeaderTextSep() const; // height between digits in header + void RecomputeGeometry(); + + virtual bool isIndexHidden(const QModelIndex& index) const; + virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers); + virtual void setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags flags); + virtual int verticalOffset() const; + virtual int horizontalOffset() const; + virtual QRegion visualRegionForSelection(const QItemSelection& selection) const; + virtual void paintEvent(QPaintEvent *event); + virtual void resizeEvent(QResizeEvent* event); + + bool m_is_dirty; + int m_minimum_width, m_minimum_height; +}; + +/** + * The Qt designers chose to make QAbstractItemView a QAbstractScrollArea, so + * that the table scrolls when it doesn't fit. This might be a problem when + * one wants to put several tables on top of another, and the whole set into a + * big scrollable area, because QAbstractScrollArea provides dummy values as + * (minimum) size hints...So the big scroll area has no way of knowing the actual + * size of the widget inside and it ends being a scrollable table inside another + * scrollable, which is just super weird. + * The Unscroll class provides a workaround this behaviour: it expects T + * to derive from QAbstractScrollArea and provides correct (minimum) size hints, + * based on the value of the scroll bars. + */ +template +class Unscroll : public T +{ +public: + Unscroll(QWidget *parent = 0):T(parent) {} + virtual QSize sizeHint() const + { + QScrollBar *hsb = this->horizontalScrollBar(); + QScrollBar *vsb = this->verticalScrollBar(); + int w = hsb->maximum() - hsb->minimum() + hsb->pageStep(); + int h = vsb->maximum() - vsb->minimum() + vsb->pageStep(); + QMargins m = this->contentsMargins(); + return QSize(m.left() + w + m.right(), m.top() + h + m.bottom()); + } + + virtual QSize minimumSizeHint() const + { + return sizeHint(); + } }; class GrowingTableView : public QTableView -- cgit v1.2.3