Pith - whittle
#include "ui/DiffTableModel.h"
#include "ui/PanelTableView.h"
#include <QAbstractItemModel>
#include <QEvent>
#include <QHeaderView>
#include <QPainter>
#include <QPalette>
#include <QProxyStyle>
#include <QStyledItemDelegate>
#include <QStyleOptionViewItem>
#include <QStyle>

namespace whittle {
	namespace {

		constexpr int kCellPadding = 3;
		constexpr int kCheckGap    = 2;

		class CellSeparatorDelegate : public QStyledItemDelegate {
		public:
			using QStyledItemDelegate::QStyledItemDelegate;

			void initStyleOption(QStyleOptionViewItem* opt,
				const QModelIndex& ix) const override {
				QStyledItemDelegate::initStyleOption(opt, ix);
				opt->state &= ~QStyle::State_HasFocus;
				if (ix.column() == DiffTableModel::Name) {
					opt->textElideMode = Qt::ElideLeft;
					opt->features &= ~QStyleOptionViewItem::WrapText;
				}
			}

			void paint(QPainter* p, const QStyleOptionViewItem& opt,
				const QModelIndex& ix) const override {
				QStyleOptionViewItem padded = opt;
				padded.rect.adjust(kCellPadding, 0, 0, 0);
				if (opt.state & QStyle::State_Selected)
					p->fillRect(opt.rect, opt.palette.brush(QPalette::Highlight));
				QStyledItemDelegate::paint(p, padded, ix);
				if (!ix.model()) return;

				p->save();
				p->setPen(opt.palette.color(QPalette::Mid));
				p->drawLine(opt.rect.bottomLeft(), opt.rect.bottomRight());
				if (ix.column() != ix.model()->columnCount() - 1)
					p->drawLine(opt.rect.topRight(), opt.rect.bottomRight());
				p->restore();
			}

			bool editorEvent(QEvent* e, QAbstractItemModel* model,
				const QStyleOptionViewItem& opt,
				const QModelIndex& ix) override {
				QStyleOptionViewItem padded = opt;
				padded.rect.adjust(kCellPadding, 0, 0, 0);
				return QStyledItemDelegate::editorEvent(e, model, padded, ix);
			}

			QSize sizeHint(const QStyleOptionViewItem& opt,
				const QModelIndex& ix) const override {
				QSize s = QStyledItemDelegate::sizeHint(opt, ix);
				s.rwidth() += kCellPadding;
				if (ix.flags() & Qt::ItemIsUserCheckable) s.rwidth() += kCheckGap;
				return s;
			}

		};

		class CheckGapStyle : public QProxyStyle {
		public:
			QRect subElementRect(SubElement se, const QStyleOption* opt,
				const QWidget* w) const override {
				QRect r = QProxyStyle::subElementRect(se, opt, w);
				if (se == SE_ItemViewItemText)
					if (const auto* vi = qstyleoption_cast<const QStyleOptionViewItem*>(opt))
						if (vi->features & QStyleOptionViewItem::HasCheckIndicator)
							r.adjust(kCheckGap, 0, 0, 0);
						return r;
					}
				};

			} 

			PanelTableView::PanelTableView(QWidget* parent) : QTableView(parent) {
				setShowGrid(false);
				setItemDelegate(new CellSeparatorDelegate(this));
				auto* gapStyle = new CheckGapStyle;
				gapStyle->setParent(this);
				setStyle(gapStyle);

				setSelectionMode(QAbstractItemView::NoSelection);
				setFocusPolicy(Qt::NoFocus);
				setEditTriggers(QAbstractItemView::NoEditTriggers);

				auto* hh = horizontalHeader();
				hh->setStretchLastSection(false);
				hh->setSectionResizeMode(QHeaderView::Interactive);
				hh->setHighlightSections(false);
				verticalHeader()->setVisible(false);

				connect(hh, &QHeaderView::sectionResized, this, [this](int, int, int) {
					if (!m_applying) m_userSized = true;
				});
			}

			void PanelTableView::resetColumnProportions() {
				m_userSized = false;
				applyProportions();
			}

			void PanelTableView::resizeEvent(QResizeEvent* e) {
				QTableView::resizeEvent(e);
				applyProportions();
			}

			void PanelTableView::applyProportions() {
				if (m_userSized || !model()) return;
				if (model()->columnCount() < DiffTableModel::ColumnCount) return;

				const int w = viewport()->width();
				if (w <= 0) return;

				const int name = w * 50 / 100;
				const int size = w * 13 / 100;
				const int mod  = w * 24 / 100;

				m_applying = true;
				setColumnWidth(DiffTableModel::Name,     name);
				setColumnWidth(DiffTableModel::Size,     size);
				setColumnWidth(DiffTableModel::Modified, mod);
				setColumnWidth(DiffTableModel::TimeDiff, w - name - size - mod);
				m_applying = false;
			}

		}