137 lines
6.4 KiB
C++
137 lines
6.4 KiB
C++
#include "qgui.h"
|
|
#include <QPainter>
|
|
#include <QResizeEvent>
|
|
|
|
const int AlignRight = Qt::AlignRight | Qt::AlignVCenter;
|
|
|
|
int operator*(const QString& key, QTreeView &table) {
|
|
return ((TreeWidget&)table).fdmap.at(key);
|
|
}
|
|
int operator*(const char *key, QTreeView &table) {
|
|
return ((TreeWidget&)table).fdmap.at(key);
|
|
}
|
|
|
|
TreeWidget::TreeWidget(std::initializer_list<ColAttr> colAttrs, QWidget *parent) : QTreeWidget{parent} {
|
|
header()->setMinimumSectionSize(16);
|
|
int i = 0;
|
|
auto item = headerItem();
|
|
for(auto attr = colAttrs.begin(); attr < colAttrs.end(); ++attr) {
|
|
item->setText(i, attr->text);
|
|
item->setData(i, FieldRole, attr->field);
|
|
if(attr->width > 0) header()->resizeSection(i, attr->width);
|
|
if(attr->resizeMode != QHeaderView::Interactive) {
|
|
if(attr->resizeMode==QHeaderView::Stretch && attr->width > 0) {
|
|
item->setData(i, WidthRole, attr->width);
|
|
noStretch = false;
|
|
} else header()->setSectionResizeMode(i, attr->resizeMode);
|
|
}
|
|
fdmap.emplace(attr->field, i++);
|
|
}
|
|
hasRowNum = i && colAttrs.begin()->field=="_num_";
|
|
connect(header(), &QHeaderView::sectionResized, this, &TreeWidget::onSectionResized);
|
|
header()->installEventFilter(this);
|
|
}
|
|
bool TreeWidget::eventFilter(QObject *watched, QEvent *event) {
|
|
if(isSectionResized && event->type()==QEvent::Leave && watched==header()) {
|
|
isSectionResized = false;
|
|
auto item = headerItem();
|
|
for(int cc=0; cc<columnCount(); cc++) if(item->data(cc, WidthRole).isValid()) item->setData(cc, WidthRole, header()->sectionSize(cc));
|
|
}
|
|
return QTreeWidget::eventFilter(watched, event);
|
|
}
|
|
void TreeWidget::resizeEvent(QResizeEvent *event) {
|
|
QTreeWidget::resizeEvent(event);
|
|
if(noStretch || event->size().width() == event->oldSize().width()) return;
|
|
adjSections(-1, 0);
|
|
}
|
|
void TreeWidget::drawRow(QPainter *painter, const QStyleOptionViewItem &options, const QModelIndex &index) const {
|
|
QTreeWidget::drawRow(painter, options, index);
|
|
if(columnWidth(0)>40) return;
|
|
if(hasRowNum) {
|
|
QRect rect(options.rect.left(), options.rect.top(), columnWidth(0), options.rect.height());
|
|
painter->fillRect(rect, QColor(128, 128, 128, 32));
|
|
painter->drawText(rect, Qt::AlignCenter, QString::number(index.row()+1));
|
|
}
|
|
if(hasGrid) {
|
|
QBrush color({128, 128, 128, 128});
|
|
painter->fillRect(options.rect.left(), options.rect.bottom(), options.rect.width(), 1, color);
|
|
QRect rec(options.rect.left()-1, options.rect.top(), 1, options.rect.height());
|
|
auto end = columnCount() - 1;
|
|
for(int i=0; i<end; i++) {
|
|
rec.translate(columnWidth(i), 0);
|
|
painter->fillRect(rec, color);
|
|
}
|
|
}
|
|
}
|
|
void TreeWidget::onSectionResized(int logicalIndex, int oldSize, int newSize) {
|
|
if(blocked || noStretch || newSize==0 || oldSize==0) return;
|
|
if(! headerItem()->data(logicalIndex, WidthRole).isValid()) return;
|
|
if(adjSections(logicalIndex, newSize)) isSectionResized = true;
|
|
}
|
|
bool TreeWidget::adjSections(int index, int size) {
|
|
auto item = headerItem();
|
|
int remain = header()->width() - size, stretchWidth = 0, width;
|
|
for(int cc=0; cc<columnCount(); cc++) if(cc!=index) {
|
|
if((width = item->data(cc, WidthRole).toInt()) > 0) stretchWidth += width;
|
|
else remain -= header()->sectionSize(cc);
|
|
}
|
|
if(remain<=0 || stretchWidth==0) return false;
|
|
auto min = header()->minimumSectionSize();
|
|
blocked = true;
|
|
for(int cc=0; cc<columnCount(); cc++) if(cc!=index && (width = item->data(cc, WidthRole).toInt()) > 0) header()->resizeSection(cc, qMax(min, width * remain / stretchWidth));
|
|
blocked = false;
|
|
return true;
|
|
}
|
|
|
|
Table::Table(std::initializer_list<ColAttr> colAttrs, int rows, QWidget *parent) : QTableWidget{rows, (int)colAttrs.size(), parent} {
|
|
int i = 0;
|
|
for(auto attr = colAttrs.begin(); attr < colAttrs.end(); ++attr) {
|
|
auto item = horizontalHeaderItem(i);
|
|
if(item==0) setHorizontalHeaderItem(i, item = new QTableWidgetItem);
|
|
item->setText(attr->text);
|
|
item->setData(FieldRole, attr->field);
|
|
if(attr->width > 0) horizontalHeader()->resizeSection(i, attr->width);
|
|
if(attr->resizeMode != QHeaderView::Interactive) {
|
|
if(attr->resizeMode==QHeaderView::Stretch && attr->width > 0) {
|
|
item->setData(WidthRole, attr->width);
|
|
noStretch = false;
|
|
} else horizontalHeader()->setSectionResizeMode(i, attr->resizeMode);
|
|
}
|
|
fdmap.emplace(attr->field, i++);
|
|
}
|
|
connect(horizontalHeader(), &QHeaderView::sectionResized, this, &Table::onSectionResized);
|
|
horizontalHeader()->installEventFilter(this);
|
|
}
|
|
bool Table::eventFilter(QObject *watched, QEvent *event) {
|
|
if(isSectionResized && event->type()==QEvent::Leave && watched==horizontalHeader()) {
|
|
isSectionResized = false;
|
|
QTableWidgetItem *item;
|
|
for(int cc=0; cc<columnCount(); cc++) if((item = horizontalHeaderItem(cc)) && item->data(WidthRole).isValid()) item->setData(WidthRole, horizontalHeader()->sectionSize(cc));
|
|
}
|
|
return QTableWidget::eventFilter(watched, event);
|
|
}
|
|
void Table::resizeEvent(QResizeEvent *event) {
|
|
QTableWidget::resizeEvent(event);
|
|
if(noStretch || event->size().width() == event->oldSize().width()) return;
|
|
adjSections(-1, 0);
|
|
}
|
|
void Table::onSectionResized(int logicalIndex, int oldSize, int newSize) {
|
|
if(blocked || noStretch || newSize==0 || oldSize==0) return;
|
|
if(! horizontalHeaderItem(logicalIndex)->data(WidthRole).isValid()) return;
|
|
if(adjSections(logicalIndex, newSize)) isSectionResized = true;
|
|
}
|
|
bool Table::adjSections(int index, int size) {
|
|
QTableWidgetItem *item;
|
|
int remain = horizontalHeader()->width() - size, stretchWidth = 0, width;
|
|
for(int cc=0; cc<columnCount(); cc++) if(cc!=index && (item = horizontalHeaderItem(cc))) {
|
|
if((width = item->data(WidthRole).toInt()) > 0) stretchWidth += width;
|
|
else remain -= horizontalHeader()->sectionSize(cc);
|
|
}
|
|
if(remain<=0 || stretchWidth==0) return false;
|
|
auto min = horizontalHeader()->minimumSectionSize();
|
|
blocked = true;
|
|
for(int cc=0; cc<columnCount(); cc++) if(cc!=index && (item = horizontalHeaderItem(cc)) && (width = item->data(WidthRole).toInt()) > 0) horizontalHeader()->resizeSection(cc, qMax(min, width * remain / stretchWidth));
|
|
blocked = false;
|
|
return true;
|
|
}
|