QtNovelUI/libSplitView/SplitPanel.cpp

229 lines
6.7 KiB
C++

#include "SplitPanel.h"
#include "DockPanel.h"
#include <QPainter>
#include <libConfig.h>
using namespace split_frame;
using namespace split_panel;
using namespace Config;
DragSplitter::DragSplitter(split_frame::SplitType split, split_frame::ViewRes *parent)
: QFrame(parent->widget()){
this->setFrameShape(QFrame::Shape::WinPanel);
this->setFrameShadow(QFrame::Shadow::Raised);
switch (split) {
case split_frame::SplitType::SPLIT_H_LFIRST:
case split_frame::SplitType::SPLIT_H_RFIRST:
this->setCursor(Qt::CursorShape::SplitHCursor);
break;
default:
this->setCursor(Qt::CursorShape::SizeVerCursor);
}
}
void DragSplitter::mouseMoveEvent(QMouseEvent *event)
{
QFrame::mouseMoveEvent(event);
emit this->adjustRequest(mapToParent(event->pos()));
}
//=====================================================
SplitPanel::SplitPanel(ResManager *mgr, SplitType split)
: QWidget(nullptr),
manager_inst(mgr),
parent_inst(nullptr),
splitter_inst(new DragSplitter(split, this))
{
connect(this->splitter_inst, &DragSplitter::adjustRequest, this, &SplitPanel::splitter_adjust);
this->split_info = std::make_tuple(split, 0.5, 8);
}
#include <QDebug>
SplitPanel::~SplitPanel() {
}
void SplitPanel::resizeEvent(QResizeEvent *e)
{
QWidget::resizeEvent(e);
this->sync_status();
}
ResManager *SplitPanel::splitManager() const { return this->manager_inst; }
SplitView *SplitPanel::parentRes() const { return parent_inst; }
void SplitPanel::setParentRes(SplitView *inst) {
this->parent_inst = inst;
if(inst){
this->setParent(inst->widget());
}
else{
this->setParent(nullptr);
}
}
qulonglong SplitPanel::hashCode() const { return (qulonglong)this; }
void SplitPanel::setVisible(bool state)
{
QWidget::setVisible(state);
}
bool SplitPanel::isVisible() const
{
return QWidget::isVisible();
}
void SplitPanel::initViews(ViewRes *a, ViewRes *b)
{
a->setParentRes(this);
manager_inst->appendPresentView(dynamic_cast<ViewBase*>(a));
b->setParentRes(this);
manager_inst->appendPresentView(dynamic_cast<ViewBase*>(b));
this->split_member = std::make_pair(a, b);
}
QWidget *SplitPanel::widget() const { return const_cast<SplitPanel *>(this); }
QSizeF SplitPanel::stiffSize() const
{
auto size_a = split_member.first->stiffSize();
auto size_b = split_member.second->stiffSize();
switch (this->splitType()) {
case SplitType::SPLIT_H_LFIRST:
case SplitType::SPLIT_H_RFIRST:
return QSizeF(size_a.width() + size_b.width() + std::get<2>(split_info), std::max(size_a.height(), size_b.height()));
default:
return QSizeF(std::max(size_a.width(), size_b.width()), size_a.height() + size_b.height() + std::get<2>(split_info));
}
}
QRectF SplitPanel::outlineRect() const { return this->rect(); }
void SplitPanel::setOutline(const QRectF &outline)
{
if(outline != this->outlineRect()){
this->setGeometry(outline.toRect());
this->sync_status();
}
}
std::pair<ViewRes *, int> SplitPanel::except(ViewRes *inst) const
{
if(!contains(inst))
throw new SimpleException<QString>("运行异常", "传入的视图实例不属于本组件");
if(split_member.first == inst)
return std::make_pair(split_member.second, 1);
return std::make_pair(split_member.first, 0);
}
bool SplitPanel::contains(ViewRes *inst) const
{
return split_member.first == inst || split_member.second == inst;
}
void SplitPanel::replaceView(ViewRes *_new, ViewRes *_old)
{
if(!contains(_old)){
throw new SimpleException<QString>("运行异常", "指定替换的视图不属于本组件");
}
auto elsev = except(_old);
_new->setParentRes(this);
switch (elsev.second) {
case 0:
this->split_member = std::make_pair(elsev.first, _new);
break;
default:
this->split_member = std::make_pair(_new, elsev.first);
}
_old->setParentRes(nullptr);
sync_status();
this->update();
}
float SplitPanel::splitterWidth() const
{
return std::get<2>(split_info);
}
float SplitPanel::splitterPos() const
{
return std::get<1>(split_info);
}
SplitType SplitPanel::splitType() const
{
return std::get<0>(split_info);
}
void SplitPanel::setSplitInfo(float pos, float width)
{
this->split_info = std::make_tuple(std::get<0>(split_info), pos, width);
this->sync_status();
this->update();
}
void SplitPanel::sync_status()
{
auto total_w = this->width();
auto total_h = this->height();
switch (std::get<0>(split_info)) {
case SplitType::SPLIT_H_LFIRST:
case SplitType::SPLIT_H_RFIRST: {
auto width_a = total_w * std::get<1>(split_info);
auto width_b = total_w - width_a - std::get<2>(split_info);
auto first = this->split_member.first;
auto second = this->split_member.second;
first->setOutline(QRectF(0, 0, width_a, total_h));
second->setOutline(QRectF(width_a + std::get<2>(split_info), 0, width_b, total_h));
this->splitter_inst->setGeometry(QRect(width_a, 0, std::get<2>(split_info), total_h));
} break;
case SplitType::SPLIT_V_BFIRST:
case SplitType::SPLIT_V_TFIRST: {
auto height_a = total_h * std::get<1>(split_info);
auto height_b = total_h - height_a - std::get<2>(split_info);
auto first = this->split_member.first;
auto second = this->split_member.second;
first->setOutline(QRectF(0, 0, total_w, height_a));
second->setOutline(QRectF(0, height_a + std::get<2>(split_info) - 1, total_w, height_b + 1));
splitter_inst->setGeometry(QRect(0, height_a, total_w, std::get<2>(split_info)));
} break;
}
split_member.first->setVisible(true);
split_member.second->setVisible(true);
}
void SplitPanel::splitter_adjust(const QPoint &pos)
{
switch (std::get<0>(split_info)) {
case SplitType::SPLIT_H_LFIRST:
case SplitType::SPLIT_H_RFIRST:{
auto lwidth = split_member.first->stiffSize().width();
auto rwidth = split_member.second->stiffSize().width();
if(pos.x() >= lwidth && pos.x() <= this->width() - rwidth - std::get<2>(split_info))
this->split_info = std::make_tuple(std::get<0>(split_info), pos.x()/(float)this->width(), std::get<2>(split_info));
}break;
case SplitType::SPLIT_V_BFIRST:
case SplitType::SPLIT_V_TFIRST:{
auto theight = split_member.first->stiffSize().height();
auto bheight = split_member.second->stiffSize().height();
if(pos.y() >= theight && pos.y() <= this->height() - bheight - std::get<2>(split_info))
this->split_info = std::make_tuple(std::get<0>(split_info), pos.y()/(float)this->height(), std::get<2>(split_info));
}break;
}
this->sync_status();
}