From d35a19f9d3722468dc2bb4ec7449a0cee07b3b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Tue, 23 Jan 2018 15:36:48 +0100 Subject: Better layout registers This does dynamic layout of registers. This implemntation is just terrible. It works but it's almost unreadable. It's just too much code for such a small feature. But I can't be bothered to refactor it on top of hacking it. --- qtmips_gui/qtmips_gui.pro | 6 +- qtmips_gui/registersdock.cpp | 21 ++-- qtmips_gui/registersdock.h | 4 +- qtmips_gui/statictable.cpp | 255 +++++++++++++++++++++++++++++++++++++++++++ qtmips_gui/statictable.h | 64 +++++++++++ 5 files changed, 335 insertions(+), 15 deletions(-) create mode 100644 qtmips_gui/statictable.cpp create mode 100644 qtmips_gui/statictable.h diff --git a/qtmips_gui/qtmips_gui.pro b/qtmips_gui/qtmips_gui.pro index 4767fe9..4b13d4c 100644 --- a/qtmips_gui/qtmips_gui.pro +++ b/qtmips_gui/qtmips_gui.pro @@ -33,7 +33,8 @@ SOURCES += \ coreview/constant.cpp \ coreview/junction.cpp \ coreview/logicblock.cpp \ - coreview/and.cpp + coreview/and.cpp \ + statictable.cpp HEADERS += \ mainwindow.h \ @@ -55,7 +56,8 @@ HEADERS += \ coreview/constant.h \ coreview/junction.h \ coreview/logicblock.h \ - coreview/and.h + coreview/and.h \ + statictable.h FORMS += \ NewDialog.ui \ diff --git a/qtmips_gui/registersdock.cpp b/qtmips_gui/registersdock.cpp index 809b692..d9d3f2f 100644 --- a/qtmips_gui/registersdock.cpp +++ b/qtmips_gui/registersdock.cpp @@ -37,23 +37,23 @@ static const QString labels[] = { RegistersDock::RegistersDock(QWidget *parent) : QDockWidget(parent) { scrollarea = new QScrollArea(this); - widg = new QWidget(scrollarea); - layout = new QFormLayout(widg); - layout->setSizeConstraint(QLayout::SetMinAndMaxSize); + scrollarea->setWidgetResizable(true); + widg = new StaticTable(scrollarea); #define INIT(X, LABEL) do{ \ - X = new QLabel(widg); \ + X = new QLabel("0x00000000", widg); \ + X->setFixedSize(X->sizeHint()); \ + X->setText(""); \ X->setTextInteractionFlags(Qt::TextSelectableByMouse); \ - layout->addRow(LABEL, X); \ + widg->addRow({new QLabel(LABEL, widg), X}); \ } while(false) - INIT(pc, "pc:"); for (int i = 0; i < 32; i++) - INIT(gp[i], QString("$") + QString::number(i) + QString("/") + labels[i] + QString(":")); - INIT(lo, "lo:"); - INIT(hi, "hi:"); + INIT(gp[i], QString("$") + QString::number(i) + QString("/") + labels[i]); + INIT(pc, "pc"); + INIT(lo, "lo"); + INIT(hi, "hi"); #undef INIT - widg->setLayout(layout); scrollarea->setWidget(widg); setWidget(scrollarea); @@ -67,7 +67,6 @@ RegistersDock::~RegistersDock() { delete lo; for (int i = 0; i < 32; i++) delete gp[i]; - delete layout; delete widg; delete scrollarea; } diff --git a/qtmips_gui/registersdock.h b/qtmips_gui/registersdock.h index 94f4670..ccfc551 100644 --- a/qtmips_gui/registersdock.h +++ b/qtmips_gui/registersdock.h @@ -7,6 +7,7 @@ #include #include #include "qtmipsmachine.h" +#include "statictable.h" class RegistersDock : public QDockWidget { Q_OBJECT @@ -22,9 +23,8 @@ private slots: void hi_lo_changed(bool hi, std::uint32_t val); private: - QWidget *widg; + StaticTable *widg; QScrollArea *scrollarea; - QFormLayout *layout; QLabel *pc; QLabel *hi; diff --git a/qtmips_gui/statictable.cpp b/qtmips_gui/statictable.cpp new file mode 100644 index 0000000..8686847 --- /dev/null +++ b/qtmips_gui/statictable.cpp @@ -0,0 +1,255 @@ +#include "statictable.h" +#include +#include + +#include +using namespace std; + +StaticTableLayout::StaticTableLayout(QWidget *parent, int margin, int horizontal_big_spacing, int horizontal_small_spacing, int vertical_spacing) : QLayout(parent) { + setContentsMargins(margin, margin, margin, margin); + bhspace = horizontal_big_spacing; + shspace = horizontal_small_spacing; + vspace = vertical_spacing; + setSizeConstraint(QLayout::SetMinAndMaxSize); +} + +StaticTableLayout::~StaticTableLayout() { + for (int i = 0; i < items.size(); i++) { + for (int y = 0; y < items[i].size(); y++) + delete items[i][y]; + } +} + +Qt::Orientations StaticTableLayout::expandingDirections() const { + return Qt::Horizontal; +} + +bool StaticTableLayout::hasHeightForWidth() const { + return true; +} + +int StaticTableLayout::heightForWidth(int w) const { + // TODO cache value + return layout_height(w); +} + +QSize StaticTableLayout::minimumSize() const { + QSize s; + for (int i = 0; i < items.size(); i++) { + QSize ss; + for (int y = 0; y < items[i].size(); y++) { + ss = s.expandedTo(items[i][y]->minimumSize() + QSize(shspace, 0)); + } + s = s.expandedTo(ss - QSize(shspace, 0)); + } + s += QSize(2*margin(), 2*margin()); + return s; +} + +void StaticTableLayout::setGeometry(const QRect &rect) { + QLayout::setGeometry(rect); + do_layout(rect); +} + +QSize StaticTableLayout::sizeHint() const { + return minimumSize(); +} + +void StaticTableLayout::addItem(QLayoutItem *item __attribute__((unused))) { + // Just implement it but it does nothing +} + +QLayoutItem *StaticTableLayout::itemAt(int index __attribute__((unused))) const { + return nullptr; // This is just dummy implementation to satisfy reimplementation +} + +QLayoutItem *StaticTableLayout::takeAt(int index __attribute__((unused))) { + return nullptr; // This is just dummy implementation to satisfy reimplementation +} + +int StaticTableLayout::count() const { + return items.size(); +} + +void StaticTableLayout::addRow(QList w) { + QVector v; + for (int i = 0; i < w.size(); i++) { + addChildWidget(w[i]); + v.append(new QWidgetItem(w[i])); + } + + items.append(v); +} + +void StaticTableLayout::itemRect(QRect &rect, QVector &separators, int i) { + separators.clear(); + + int row = i / columns(); + int col = i % columns(); + + int left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + + int x = left; + for (int s = 0; s < col; s++) { + for (int t = 0; t < row_widths[s].size(); t++) + x += row_widths[s][t] + shspace; + x += bhspace - shspace; + } + if (col > 0) // otherwise we are on left edge and there was no previous column so no big space + x -= bhspace/2; + int y = top + (row * (row_height + vspace)); + + + int width = 0; + for (int t = 0; t < row_widths[col].size(); t++) { + width += row_widths[col][t] + shspace; + separators.append(width - shspace/2); + } + if (col <= 0) + width -= bhspace/2; + + rect = QRect(x, y - vspace/2, width - shspace + bhspace, row_height + vspace); + separators.removeLast(); // drop last separator as that one we don't want to see +} + +int StaticTableLayout::columns() { + return row_widths.size(); +} + +int StaticTableLayout::layout_count_approx(const QRect &rect) const { + if (items.size() <= 0) + return 1; + int w = 0; + for (int i = 0; i < items[0].size(); i++) + w += items[0][i]->sizeHint().width() + shspace; + w -= shspace; // subtract lastest spacing + int width = rect.right() / w; // Note: this always rounds down so this always founds maximal possible count + return width <= 0 ? 1 : width; // We have to fit at least one column +} + +int StaticTableLayout::layout_size(int &row_h, QList> &row_w, int count) const { + row_h = 0; + row_w.clear(); + int col = 0; + for (int i = 0; i < items.size(); i++) { + if (row_w.size() <= col) + row_w.append(QList()); + for (int y = 0; y < items[i].size(); y++) { + QSize s = items[i][y]->sizeHint(); + row_h = qMax(row_h, s.height()); + if (row_w[col].size() <= y) + row_w[col].append(0); + row_w[col][y] = qMax(row_w[col][y], s.width()); + } + if (++col >= count) + col = 0; + } + SANITY_ASSERT(row_w.size() <= count, "We should end up with maximum of count columns"); + + int w = 0; + for (int i = 0; i < row_w.size(); i++) { + for (int y = 0; y < row_w[i].size(); y++) + w += row_w[i][y] + shspace; + w += bhspace - shspace; // subtract latest small spacing and add big spacing + } + w -= bhspace; // subtract latest big spacing + return w; +} + +void StaticTableLayout::layout_parms(QRect &rect, int &row_h, QList> &row_w, int &count) const { + int left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + rect = rect.adjusted(left, top, -right, -bottom); + + // Firt let's do orientation count only on first line + count = layout_count_approx(rect); + if (layout_size(row_h, row_w, count) > rect.right()) { + // Not using orientation count go down if we can't fit (if we can then just be happy with what we have) + do { + if (count <= 1) + // TODO meaby warning? + break; // We can't fit it but ignore that. + count--; + } while (layout_size(row_h, row_w, count) <= rect.width()); + } +} + +void StaticTableLayout::do_layout(const QRect &rect) { + int row_h; + QList> row_w; + int count; + + QRect reff(rect); + layout_parms(reff, row_h, row_w, count); + + int col = 0; + int x = reff.x(), y = reff.y(); + for (int i = 0; i < items.size(); i++) { + for (int ii = 0; ii < items[i].size(); ii++) { + items[i][ii]->setGeometry(QRect(x, y, row_w[col][ii], row_h)); + x += row_w[col][ii] + shspace; + } + x += bhspace - shspace; + if (++col >= count) { + col = 0; + x = reff.x(); + y += row_h + vspace; + } + } + row_height = row_h; + row_widths = row_w; +} + +int StaticTableLayout::layout_height(int width) const { + QRect reff(0, 0, width, 0); + int row_h; + QList> row_w; + int count; + layout_parms(reff, row_h, row_w, count); + + return (row_h + vspace) * (items.size() / count); +} + +StaticTable::StaticTable(QWidget *parent) : QWidget(parent), layout(this) { + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); +} + +void StaticTable::addRow(QList w) { + layout.addRow(w); +} + +void StaticTable::paintEvent(QPaintEvent*) { + QPainter p(this); + p.setPen(QPen(QColor(200, 200, 200))); + + QRect rect; + QVector separators; + for (int i = 0; i < layout.count(); i++) { + int row = i / layout.columns(); + int col = i % layout.columns(); + + if ((col % 2) == (row % 2)) + p.setBrush(QBrush(QColor(255, 255, 255))); + else + p.setBrush(QBrush(QColor(230, 230, 230))); + + layout.itemRect(rect, separators, i); + + int x = rect.left(); // just to store x + if (col <= 0) // this is left most row + rect.setLeft(-2); + if (col >= (layout.columns() - 1)) + rect.setRight(width()); + if (row <= 0) + rect.setTop(-2);; + + p.drawRect(rect); + + for (int s = 0; s < separators.size(); s++) { + int sep_x = x + separators[s]; + p.drawLine(sep_x, rect.top(), sep_x, rect.bottom()); + } + } + +} diff --git a/qtmips_gui/statictable.h b/qtmips_gui/statictable.h new file mode 100644 index 0000000..8248aa3 --- /dev/null +++ b/qtmips_gui/statictable.h @@ -0,0 +1,64 @@ +#ifndef STATICTABLE_H +#define STATICTABLE_H + +#include +#include +#include +#include + +/* + * This implements new layout and widget in the same time. + * Basic idea is that we need some table view that can also fill in horizontal space. + * This widget paints simple table under neath the widgets and lays them out in to them. + * It shows more than one column when there is enought horizontal space. + */ + +class StaticTableLayout : public QLayout { +public: + StaticTableLayout(QWidget *parent, int margin = 4, int horizontal_big_spacing = 4, int horizontal_small_spacing = 8, int vertical_spacing = 4); + ~StaticTableLayout(); + + Qt::Orientations expandingDirections() const override; + bool hasHeightForWidth() const override; + int heightForWidth(int) const override; + QSize minimumSize() const override; + void setGeometry(const QRect &rect) override; + QSize sizeHint() const override; + + void addItem(QLayoutItem *item) override; + QLayoutItem *itemAt(int index) const override; + QLayoutItem *takeAt(int index) override; + int count() const override; // This returns number of item blocks + + void addRow(QList); // This adds row of widgets + + void itemRect(QRect &rect, QVector &separators, int i); // This returns single item rectable (if expad_margin and it's on edge also count in margin) + int columns(); + +protected: + int shspace, bhspace, vspace; + QVector> items; + + int row_height; + QList> row_widths; + + int layout_count_approx(const QRect &rect) const; + int layout_size(int &row_h, QList> &row_w, int count) const; + void layout_parms(QRect &rect, int &row_h, QList> &row_w, int &count) const; + void do_layout(const QRect &rect); + int layout_height(int width) const; +}; + +class StaticTable : public QWidget { +public: + StaticTable(QWidget *parent = nullptr); + + void addRow(QList); + +protected: + void paintEvent(QPaintEvent*); + + StaticTableLayout layout; +}; + +#endif // STATICTABLE_H -- cgit v1.2.3