From 92c7fd220506df5f7997d27dbbcdb513e66932a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Thu, 25 Jan 2018 15:40:50 +0100 Subject: Implement memoryview --- qtmips_gui/mainwindow.cpp | 1 + qtmips_gui/memorydock.cpp | 37 +++++++---- qtmips_gui/memorydock.h | 17 ++++- qtmips_gui/memoryview.cpp | 162 +++++++++++++++++++++++++++++++++++++++------ qtmips_gui/memoryview.h | 51 +++++++++++--- qtmips_gui/programdock.cpp | 106 ++++++++++++++++------------- qtmips_gui/programdock.h | 31 ++++++--- qtmips_gui/statictable.cpp | 125 +++++++++++++++++++++++++++------- qtmips_gui/statictable.h | 27 ++++++++ 9 files changed, 432 insertions(+), 125 deletions(-) (limited to 'qtmips_gui') diff --git a/qtmips_gui/mainwindow.cpp b/qtmips_gui/mainwindow.cpp index c064509..0f5d11a 100644 --- a/qtmips_gui/mainwindow.cpp +++ b/qtmips_gui/mainwindow.cpp @@ -104,6 +104,7 @@ void MainWindow::create_core(const machine::MachineConfig &config) { // Setup docks registers->setup(machine); program->setup(machine); + memory->setup(machine); // Set status to ready machine_status(machine::QtMipsMachine::ST_READY); } diff --git a/qtmips_gui/memorydock.cpp b/qtmips_gui/memorydock.cpp index 8998b32..d0bad9c 100644 --- a/qtmips_gui/memorydock.cpp +++ b/qtmips_gui/memorydock.cpp @@ -1,22 +1,35 @@ #include "memorydock.h" +DataView::DataView(QWidget *parent) : MemoryView(parent) { } + +QList DataView::row_widget(std::uint32_t address, QWidget *parent) { + QList widgs; + QLabel *l; + + l = new QLabel(QString("0x%1").arg(address, 8, 16, QChar('0')), parent); + l->setTextInteractionFlags(Qt::TextSelectableByMouse); + widgs.append(l); + + l = new QLabel(parent); + l->setTextInteractionFlags(Qt::TextSelectableByMouse); + if (memory != nullptr) { + l->setText(QString("0x%1").arg(memory->read_word(address), 8, 16, QChar('0'))); + } + else + l->setText(" "); // Just fill it in with some plain text so we don't have just addresses there + widgs.append(l); + + return widgs; +} + MemoryDock::MemoryDock(QWidget *parent) : QDockWidget(parent) { - memory_view = new MemoryView(this); - setWidget(memory_view); + view = new DataView(this); + setWidget(view); setObjectName("Memory"); setWindowTitle("Memory"); } -MemoryDock::~MemoryDock() { - delete memory_view; -} - void MemoryDock::setup(machine::QtMipsMachine *machine) { - if (machine == nullptr) - // TODO reset memory view - return; - - // TODO setup memory view - + view->setup(machine); } diff --git a/qtmips_gui/memorydock.h b/qtmips_gui/memorydock.h index 533451e..612f986 100644 --- a/qtmips_gui/memorydock.h +++ b/qtmips_gui/memorydock.h @@ -2,19 +2,32 @@ #define MEMORYDOCK_H #include +#include +#include #include "qtmipsmachine.h" #include "memoryview.h" +class DataView : public MemoryView { + Q_OBJECT +public: + DataView(QWidget *parent); + +protected: + QList row_widget(std::uint32_t address, QWidget *parent); + +private: + QComboBox *cb_size; +}; + class MemoryDock : public QDockWidget { Q_OBJECT public: MemoryDock(QWidget *parent); - ~MemoryDock(); void setup(machine::QtMipsMachine *machine); private: - MemoryView *memory_view; + DataView *view; }; #endif // MEMORYDOCK_H diff --git a/qtmips_gui/memoryview.cpp b/qtmips_gui/memoryview.cpp index bd5d6d8..c391169 100644 --- a/qtmips_gui/memoryview.cpp +++ b/qtmips_gui/memoryview.cpp @@ -1,47 +1,167 @@ #include "memoryview.h" +/////////////////////////// +// Minimal reserved range in pixels of scroll area (otherwise 10% of height are used) +#define MIN_OFF 10 +/////////////////////////// + +#include +using namespace std; + MemoryView::MemoryView(QWidget *parent) : QWidget(parent) { + memory = nullptr; + addr_0 = 0; + layout = new QVBoxLayout(this); - frame = new QFrame(this); - frame->setFrameShadow(QFrame::Sunken); - frame->setFrameShape(QFrame::StyledPanel); - frame->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - // TODO - layout->addWidget(frame); + memf= new Frame(this); + layout->addWidget(memf); - go_edit = new QLineEdit(this); + + ctl_widg = new QWidget(this); + layout->addWidget(ctl_widg); + + ctl_layout = new QHBoxLayout(ctl_widg); + go_edit = new QLineEdit(ctl_widg); go_edit->setText("0x00000000"); go_edit->setInputMask("\\0\\xHHHHHHHH"); - layout->addWidget(go_edit); + ctl_layout->addWidget(go_edit); connect(go_edit, SIGNAL(editingFinished()), this, SLOT(go_edit_finish())); - + up = new QToolButton(ctl_widg); + up->setArrowType(Qt::UpArrow); + ctl_layout->addWidget(up); + down = new QToolButton(ctl_widg); + down->setArrowType(Qt::DownArrow); + ctl_layout->addWidget(down); } -MemoryView::~MemoryView() { - delete go_edit; - delete frame; - delete layout; +void MemoryView::setup(machine::QtMipsMachine *machine) { + memory = (machine == nullptr) ? nullptr : machine->memory(); + reload_content(); } -void MemoryView::set_center(std::uint32_t address) { - center_addr = address; +void MemoryView::set_focus(std::uint32_t address) { + // TODO center // TODO update view } -std::uint32_t MemoryView::center() { - return center_addr; +std::uint32_t MemoryView::focus() { + // TODO + return 0; +} + +void MemoryView::reload_content() { + int count = memf->widg->count(); + memf->widg->clearRows(); + update_content(count, 0); +} + +void MemoryView::update_content(int count, int shift) { + if (abs(shift) >= memf->widg->count()) { + // This shifts more than we have so just reload whole content + memf->widg->clearRows(); + addr_0 += 4*shift; + for (int i = 0; i <= count; i++) + memf->widg->addRow(row_widget(addr_0 + 4*i, memf->widg)); + return; + } + + int diff = count - memf->widg->count(); + int d_b = shift; + int d_e = diff - shift; + cout << "count:" << memf->widg->count() << " tocount:" << count << " d_b:" << d_b << " d_e:" << d_e << endl; + + if (d_b > 0) + for (int i = 0; i < d_b; i++) { + addr_0 -= 4; + memf->widg->insertRow(row_widget(addr_0, memf->widg), 0); + } + else + for (int i = 0; i > d_b; i--) { + addr_0 += 4; + memf->widg->removeRow(0); + } + if (d_e > 0) + for (int i = 0; i < d_e; i++) + memf->widg->addRow(row_widget(addr_0 + 4*memf->widg->count(), memf->widg)); + else + for (int i = 0; i > d_e; i--) + memf->widg->removeRow(memf->widg->count() - 1); } -void MemoryView::resizeEvent(QResizeEvent *event) { - QWidget::resizeEvent(event); +void MemoryView::go_edit_finish() { // TODO } -void MemoryView::wheelEvent(QWheelEvent *event) { +MemoryView::Frame::Frame(MemoryView *parent) : QAbstractScrollArea(parent) { + mv = parent; + content_y = -3*MIN_OFF/2; // When this is initialized the width is 0 so this uses just min to inialize it + + widg = new StaticTable(this); + setViewport(widg); + + setFrameShadow(QFrame::Sunken); + setFrameShape(QFrame::StyledPanel); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + setContentsMargins(0, 0, 0, 0); +} + +void MemoryView::Frame::focus(unsigned i) { // TODO } -void MemoryView::go_edit_finish() { +unsigned MemoryView::Frame::focussed() { // TODO + return 0; +} + +// This verifies that we are not scrolled too far away down or up and that we have enought height +// We make 10% of height as buffer zone with fixed minimum in pixels +void MemoryView::Frame::check_update() { + int hpart = qMax(height()/10, MIN_OFF); + int req_height = height() + 2*hpart; + + while (!((content_y <= -hpart) && (content_y >= -2*hpart)) || (widg->height() < req_height)) { + cout << "widg.h:" << widg->height() << " req_h:" << req_height << endl; + cout << "content_y:" << content_y << " hpart:" << hpart << endl; + int row_h = widg->row_size(); + cout << "row_h:" << row_h << " columns:" << widg->columns() << endl; + // Calculate how many we need and how much we need to move and update content accordingly + int count = (req_height / row_h) + 1; + int shift = (content_y + hpart + hpart/2)/row_h; + mv->update_content(count * widg->columns(), shift * widg->columns()); + cout << "count:" << count << endl; + // Move and resize widget + content_y -= shift * row_h; + widg->setGeometry(0, content_y, width(), widg->heightForWidth(width())); + } +} + +void MemoryView::Frame::resizeEvent(QResizeEvent *e) { + QAbstractScrollArea::resizeEvent(e); + widg->setGeometry(0, content_y, e->size().width(), widg->heightForWidth(e->size().width())); + check_update(); +} + +void MemoryView::Frame::wheelEvent(QWheelEvent *e) { + QPoint pix = e->pixelDelta(); + QPoint ang = e->angleDelta(); + + if (!pix.isNull()) + content_y += e->pixelDelta().ry(); + // TODO angle scroll + + // TODO smooth scroll + viewport()->move(0, content_y); + viewport()->repaint(0, content_y, width(), height()); + + check_update(); +} + +bool MemoryView::Frame::viewportEvent(QEvent *e) { + bool p = QAbstractScrollArea::viewportEvent(e); + // Pass paint event to viewport widget + if (e->type() == QEvent::Paint) + p = false; + return p; } diff --git a/qtmips_gui/memoryview.h b/qtmips_gui/memoryview.h index e1049e8..be2c8a2 100644 --- a/qtmips_gui/memoryview.h +++ b/qtmips_gui/memoryview.h @@ -2,35 +2,68 @@ #define MEMORYVIEW_H #include -#include +#include #include +#include #include +#include +#include +#include #include +#include +#include "qtmipsmachine.h" +#include "statictable.h" class MemoryView : public QWidget { + Q_OBJECT public: MemoryView(QWidget *parent = nullptr); - ~MemoryView(); - void set_center(std::uint32_t address); - std::uint32_t center(); + virtual void setup(machine::QtMipsMachine*); + + void set_focus(std::uint32_t address); + std::uint32_t focus(); protected: - //virtual QWidget *row_widget(std::uint32_t address) = 0; + const machine::Memory *memory; - void resizeEvent(QResizeEvent *event); - void wheelEvent(QWheelEvent *event); + virtual QList row_widget(std::uint32_t address, QWidget *parent) = 0; QVBoxLayout *layout; + void reload_content(); // reload displayed data + void update_content(int count, int shift); // update content to match given count and shift + private slots: void go_edit_finish(); private: - std::uint32_t center_addr; + unsigned count; + std::uint32_t addr_0; // First address in view + + class Frame : public QAbstractScrollArea { + public: + Frame(MemoryView *parent); + + StaticTable *widg; + void focus(unsigned i); // Focus on given item in widget + unsigned focussed(); // What item is in focus + void check_update(); // Update widget size and content if needed + + protected: + MemoryView *mv; + int content_y; + + bool viewportEvent(QEvent*); + void resizeEvent(QResizeEvent*); + void wheelEvent(QWheelEvent *event); + }; + Frame *memf; - QFrame *frame; + QWidget *ctl_widg; + QHBoxLayout *ctl_layout; QLineEdit *go_edit; + QToolButton *up, *down; }; #endif // MEMORYVIEW_H diff --git a/qtmips_gui/programdock.cpp b/qtmips_gui/programdock.cpp index c885083..9178dce 100644 --- a/qtmips_gui/programdock.cpp +++ b/qtmips_gui/programdock.cpp @@ -1,26 +1,21 @@ #include "programdock.h" #include "qtmipsexception.h" -ProgramDock::ProgramDock(QWidget *parent) : QDockWidget(parent) { - widg = new QWidget(this); - widg_layout = new QBoxLayout(QBoxLayout::TopToBottom, widg); - widg_layout->setSizeConstraint(QLayout::SetMinAndMaxSize); - - memory_view = new MemoryView(widg); - widg_layout->addWidget(memory_view); +ProgramView::ProgramView(QWidget *parent) : MemoryView(parent) { + set_center(0x80020000); // Initialize center address to program start - ctlbox_single = new QComboBox(widg); - ctlbox_single->addItems({ + cb_single = new QComboBox(this); + cb_single->addItems({ "Don't follow", "Follow executing instruction" }); - ctlbox_single->setCurrentIndex(1); - ctlbox_single->hide(); - widg_layout->addWidget(ctlbox_single); - connect(ctlbox_single, SIGNAL(currentIndexChanged(int)), this, SLOT(ctlbox_single_changed(int))); + cb_single->setCurrentIndex(1); + cb_single->hide(); + layout->addWidget(cb_single); + connect(cb_single, SIGNAL(currentIndexChanged(int)), this, SLOT(cb_single_changed(int))); - ctlbox_pipelined = new QComboBox(widg); - ctlbox_pipelined->addItems({ + cb_pipelined = new QComboBox(this); + cb_pipelined->addItems({ "Don't follow", "Follow Instruction fetch stage", "Follow Instruction decode stage", @@ -28,51 +23,68 @@ ProgramDock::ProgramDock(QWidget *parent) : QDockWidget(parent) { "Follow Memory access stage", "Follow Registers write back stage", }); - ctlbox_pipelined->hide(); - ctlbox_pipelined->setCurrentIndex(1); - widg_layout->addWidget(ctlbox_pipelined); - connect(ctlbox_pipelined, SIGNAL(currentIndexChanged(int)), this, SLOT(ctlbox_pipelined_changed(int))); - - setWidget(widg); - setObjectName("Program"); - setWindowTitle("Program"); -} - -ProgramDock::~ProgramDock() { - delete memory_view; - delete ctlbox_single; - delete ctlbox_pipelined; - delete widg_layout; - delete widg; + cb_pipelined->hide(); + cb_pipelined->setCurrentIndex(1); + layout->addWidget(cb_pipelined); + connect(cb_pipelined, SIGNAL(currentIndexChanged(int)), this, SLOT(cb_pipelined_changed(int))); } -void ProgramDock::setup(machine::QtMipsMachine *machine) { - if (machine == nullptr) { - // TODO zero memory viewer +void ProgramView::setup(machine::QtMipsMachine *machine) { + MemoryView::setup(machine); + if (machine == nullptr) return; - } - - // TODO pass to viewer bool pipelined = machine->config().pipelined(); - ctlbox_single->setVisible(!pipelined); - ctlbox_pipelined->setVisible(pipelined); + cb_single->setVisible(!pipelined); + cb_pipelined->setVisible(pipelined); // Sync selection somewhat if (pipelined) { - if (ctlbox_single->currentIndex() == 0) - ctlbox_pipelined->setCurrentIndex(0); - else if (ctlbox_pipelined->currentIndex() == 0) - ctlbox_pipelined->setCurrentIndex(1); + if (cb_single->currentIndex() == 0) + cb_pipelined->setCurrentIndex(0); + else if (cb_pipelined->currentIndex() == 0) + cb_pipelined->setCurrentIndex(1); } else - ctlbox_single->setCurrentIndex(ctlbox_pipelined->currentIndex() == 0 ? 0 : 1); + cb_single->setCurrentIndex(cb_pipelined->currentIndex() == 0 ? 0 : 1); +} + +QList ProgramView::row_widget(std::uint32_t address, QWidget *parent) { + QList widgs; + QLabel *l; + + l = new QLabel(" ", parent); + widgs.append(l); - // TODO also update current setting of memory viewer + l = new QLabel(QString("0x%1").arg(address, 8, 16, QChar('0')), parent); + l->setTextInteractionFlags(Qt::TextSelectableByMouse); + widgs.append(l); + + l = new QLabel(parent); + l->setTextInteractionFlags(Qt::TextSelectableByMouse); + if (memory != nullptr) + l->setText(machine::Instruction(memory->read_word(address)).to_str()); + else + l->setText(" "); // Just fill it in with some plain text so we don't have just addresses there + widgs.append(l); + + return widgs; } -void ProgramDock::ctlbox_single_changed(int index) { +void ProgramView::cb_single_changed(int index) { // TODO set memory view } -void ProgramDock::ctlbox_pipelined_changed(int index) { +void ProgramView::cb_pipelined_changed(int index) { // TODO set memory view } + +ProgramDock::ProgramDock(QWidget *parent) : QDockWidget(parent) { + view = new ProgramView(this); + setWidget(view); + + setObjectName("Program"); + setWindowTitle("Program"); +} + +void ProgramDock::setup(machine::QtMipsMachine *machine) { + view->setup(machine); +} diff --git a/qtmips_gui/programdock.h b/qtmips_gui/programdock.h index 4605a7b..9ed0896 100644 --- a/qtmips_gui/programdock.h +++ b/qtmips_gui/programdock.h @@ -9,25 +9,34 @@ #include "qtmipsmachine.h" #include "memoryview.h" -class ProgramDock : public QDockWidget { +class ProgramView : public MemoryView { Q_OBJECT public: - ProgramDock(QWidget *parent); - ~ProgramDock(); + ProgramView(QWidget *parent); - void setup(machine::QtMipsMachine *machine); + void setup(machine::QtMipsMachine*); + +protected: + QList row_widget(std::uint32_t address, QWidget *parent); private slots: - void ctlbox_single_changed(int index); - void ctlbox_pipelined_changed(int index); + void cb_single_changed(int index); + void cb_pipelined_changed(int index); private: - QWidget *widg; - QBoxLayout *widg_layout; + QComboBox *cb_single; + QComboBox *cb_pipelined; +}; - MemoryView *memory_view; - QComboBox *ctlbox_single; - QComboBox *ctlbox_pipelined; +class ProgramDock : public QDockWidget { + Q_OBJECT +public: + ProgramDock(QWidget *parent); + + void setup(machine::QtMipsMachine *machine); + +private: + ProgramView *view; }; #endif // PROGRAMDOCK_H diff --git a/qtmips_gui/statictable.cpp b/qtmips_gui/statictable.cpp index 8686847..fe8a820 100644 --- a/qtmips_gui/statictable.cpp +++ b/qtmips_gui/statictable.cpp @@ -3,6 +3,7 @@ #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) { @@ -29,21 +30,28 @@ bool StaticTableLayout::hasHeightForWidth() const { } int StaticTableLayout::heightForWidth(int w) const { - // TODO cache value - return layout_height(w); + if (cch_heightForWidth.w != w || cch_heightForWidth.count != items.count()) + cch_heightForWidth.width = layout_height(w); + cch_heightForWidth.w = w; + cch_heightForWidth.count = items.count(); + return cch_heightForWidth.width; } QSize StaticTableLayout::minimumSize() const { - QSize s; + if (cch_minSize.count == items.size()) + return cch_minSize.size; + cch_minSize.count = items.size(); + + cch_minSize.size = QSize(); 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)); + ss = cch_minSize.size.expandedTo(items[i][y]->minimumSize() + QSize(shspace, 0)); } - s = s.expandedTo(ss - QSize(shspace, 0)); + cch_minSize.size = cch_minSize.size.expandedTo(ss - QSize(shspace, 0)); } - s += QSize(2*margin(), 2*margin()); - return s; + cch_minSize.size += QSize(2*margin(), 2*margin()); + return cch_minSize.size; } void StaticTableLayout::setGeometry(const QRect &rect) { @@ -72,13 +80,28 @@ int StaticTableLayout::count() const { } 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(list2vec(w)); +} + +void StaticTableLayout::insertRow(QList w, int i) { + items.insert(i, list2vec(w)); +} + +void StaticTableLayout::removeRow(int i) { + for (int y = 0; y < items[i].size(); y++) { + delete items[i][y]->widget(); + delete items[i][y]; } + items.remove(i); +} - items.append(v); +void StaticTableLayout::clearRows() { + for (int i = 0; i < items.size(); i++) + for (int y = 0; y < items[i].size(); y++) { + delete items[i][y]->widget(); + delete items[i][y]; + } + items.clear(); } void StaticTableLayout::itemRect(QRect &rect, QVector &separators, int i) { @@ -100,7 +123,6 @@ void StaticTableLayout::itemRect(QRect &rect, QVector &separators, int i) { 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; @@ -117,14 +139,32 @@ int StaticTableLayout::columns() { return row_widths.size(); } +int StaticTableLayout::real_row_height() { + return row_height + vspace; +} + int StaticTableLayout::layout_count_approx(const QRect &rect) const { if (items.size() <= 0) return 1; + // Note: for some reason (probably optimalisation) when qlabel is not visible it reports 0 size. So we have to found at least one that is visible + int vis = 0; + while (items[vis].size() <= 0 || !items[vis][0]->widget()->isVisible()) { + vis++; + if (vis >= items.size()) + return 1; // If non is visible then just say that it has to be single column + } + int w = 0; - for (int i = 0; i < items[0].size(); i++) - w += items[0][i]->sizeHint().width() + shspace; + for (int i = 0; i < items[vis].size(); i++) + w += items[vis][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 + + cout << "ST: widht:" << rect.right() << " row_w" << w << " so count:" << width << " we have:" << items.count() << " In 0:" << items[vis].count() << " contains:"; + for (int i = 0; i < items[0].size(); i++) + cout << ((QLabel*)items[0][i]->widget())->text().toStdString() << " "; + cout << endl; + return width <= 0 ? 1 : width; // We have to fit at least one column } @@ -164,22 +204,24 @@ void StaticTableLayout::layout_parms(QRect &rect, int &row_h, QList> // 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()) { + while (layout_size(row_h, row_w, count) > rect.right() && count > 1) { // 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()); + count--; } } void StaticTableLayout::do_layout(const QRect &rect) { + if (cch_do_layout.size == rect.size() && cch_do_layout.count == items.size()) + // No effective change so don't do layout + return; + cch_do_layout.size = rect.size(); + cch_do_layout.count = items.size(); + int row_h; QList> row_w; int count; + cout << "Doing layout" << endl; QRect reff(rect); layout_parms(reff, row_h, row_w, count); @@ -202,6 +244,7 @@ void StaticTableLayout::do_layout(const QRect &rect) { } int StaticTableLayout::layout_height(int width) const { + cout << "Quering height" << endl; QRect reff(0, 0, width, 0); int row_h; QList> row_w; @@ -211,15 +254,51 @@ int StaticTableLayout::layout_height(int width) const { return (row_h + vspace) * (items.size() / count); } +QVector StaticTableLayout::list2vec(QList w) { + QVector v; + for (int i = 0; i < w.size(); i++) { + addChildWidget(w[i]); + v.append(new QWidgetItem(w[i])); + } + return v; +} + StaticTable::StaticTable(QWidget *parent) : QWidget(parent), layout(this) { setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); } +int StaticTable::count() { + return layout.count(); +} + void StaticTable::addRow(QList w) { layout.addRow(w); } +void StaticTable::insertRow(QList w, int i) { + layout.insertRow(w, i); +} + +void StaticTable::removeRow(int i) { + layout.removeRow(i); +} + +void StaticTable::clearRows() { + layout.clearRows(); +} + +int StaticTable::columns() { + return qMax(layout.columns(), 1); +} + +int StaticTable::row_size() { + return layout.real_row_height(); +} + void StaticTable::paintEvent(QPaintEvent*) { + if (layout.columns() <= 0) // Don't paint unless we have at least one column + return; + QPainter p(this); p.setPen(QPen(QColor(200, 200, 200))); @@ -232,7 +311,7 @@ void StaticTable::paintEvent(QPaintEvent*) { if ((col % 2) == (row % 2)) p.setBrush(QBrush(QColor(255, 255, 255))); else - p.setBrush(QBrush(QColor(230, 230, 230))); + p.setBrush(QBrush(QColor(235, 235, 235))); layout.itemRect(rect, separators, i); diff --git a/qtmips_gui/statictable.h b/qtmips_gui/statictable.h index 8248aa3..9249430 100644 --- a/qtmips_gui/statictable.h +++ b/qtmips_gui/statictable.h @@ -31,9 +31,13 @@ public: int count() const override; // This returns number of item blocks void addRow(QList); // This adds row of widgets + void insertRow(QList, int i); // Insert row to given position while shifting all other up + void removeRow(int i); // Remove row + void clearRows(); // Clear all rows from table 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(); + int real_row_height(); protected: int shspace, bhspace, vspace; @@ -47,13 +51,36 @@ protected: 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; + + QVector list2vec(QList); + + struct { + QSize size; + int count; + } cch_do_layout; + mutable struct { + int w, count; + int width; + } cch_heightForWidth; + mutable struct { + int count; + QSize size; + } cch_minSize; + }; class StaticTable : public QWidget { public: StaticTable(QWidget *parent = nullptr); + int count(); void addRow(QList); + void insertRow(QList, int i); + void removeRow(int i); + void clearRows(); + + int columns(); + int row_size(); // return real row size (height) including spacing protected: void paintEvent(QPaintEvent*); -- cgit v1.2.3