QtNovelUI/libSplitView/SplitWindow.cpp

234 lines
6.4 KiB
C++

#include "SplitWindow.h"
#include "DockPanel.h"
#include "SplitPanel.h"
#include <QApplication>
#include <QDebug>
#include <QDrag>
#include <QHBoxLayout>
#include <QLineF>
#include <QMimeData>
#include <QPainter>
#include <QPushButton>
#include <QResizeEvent>
#include <QStyleOption>
#include <QWindow>
#include <libConfig.h>
using namespace split_window;
using namespace split_frame;
SplitWindow::SplitWindow(QWidget *parent)
: QMainWindow(parent),
active(true),
unused_stack(new QToolBar(this)),
accept_port(new accept_panel::AcceptPanel(this, this)),
view_root(nullptr) {
accept_port->setVisible(false);
this->addToolBar(Qt::ToolBarArea::LeftToolBarArea, unused_stack);
}
SplitWindow::~SplitWindow() {this->active = false;}
void SplitWindow::tempShow(split_frame::DockType t, split_frame::ViewBase *target)
{
this->temp_show = target;
target->setVisible(true);
}
void SplitWindow::setPresentTarget(split_frame::ViewRes *inst)
{
if(inst && this->view_root != inst){
this->takeCentralWidget();
this->view_root = nullptr;
inst->setParentRes(nullptr);
inst->widget()->setParent(this);
this->setCentralWidget(inst->widget());
} else if (!inst) {
this->takeCentralWidget();
}
this->view_root = inst;
this->update();
}
bool SplitWindow::eventFilter(QObject *sender, QEvent *ev)
{
switch (ev->type()) {
case QEvent::Type::DragMove: {
if (sender->isWidgetType() || sender->isWindowType()) {
auto evn_pos = static_cast<QDragMoveEvent *>(ev)->pos();
QPoint global_pos;
if (sender->isWindowType()) {
dynamic_cast<QWindow *>(sender)->requestActivate();
global_pos = dynamic_cast<QWindow *>(sender)->mapToGlobal(evn_pos);
} else if (sender->isWidgetType()) {
global_pos = dynamic_cast<QWidget *>(sender)->mapToGlobal(evn_pos);
}
for (auto &cmp : this->presents_store) {
auto local_pos = cmp->widget()->mapFromGlobal(global_pos);
auto rect_shape = cmp->outlineRect();
rect_shape.moveTopLeft(QPointF());
if (rect_shape.contains(local_pos) && cmp->widget()->isActiveWindow()) {
accept_port->bindWith(cmp);
accept_port->raise();
accept_port->setVisible(true);
break;
}
}
}
} break;
case QEvent::Type::MouseButtonRelease:
accept_port->setVisible(false);
break;
default:
break;
}
return QMainWindow::eventFilter(sender, ev);
}
void SplitWindow::addListener(split_frame::FreedomViewsListener *lsn)
{
if(listener_list.contains(lsn))
return;
listener_list << lsn;
}
void SplitWindow::removeListener(split_frame::FreedomViewsListener *lsn)
{
this->listener_list.removeAll(lsn);
}
void SplitWindow::appendPresentView(split_frame::ViewBase *inst)
{
if(this->active && inst)
this->presents_store[inst->hashCode()] = inst;
}
void SplitWindow::removePresentView(split_frame::ViewBase *inst)
{
if(this->active && inst)
this->presents_store.remove(inst->hashCode());
}
bool SplitWindow::isPresented(split_frame::ViewBase *inst) const
{
return inst && presents_store.contains(inst->hashCode());
}
#include <libConfig.h>
void SplitWindow::doRetrieve(split_frame::ViewBase *inst)
{
if(!isPresented(inst)){
throw new Config::SimpleException<QString>("参数错误", "无法回收空闲视图!");
}
// 呈现视图结构调整
if(inst == temp_show){
temp_show->setVisible(false);
return;
}
else if (inst == view_root) {
setPresentTarget();
inst->setParentRes(nullptr);
}
else if(inst->parentRes() == view_root){
auto pinst = inst->parentRes();
auto remains = pinst->except(inst);
inst->setParentRes(nullptr);
remains.first->setParentRes(nullptr);
setPresentTarget(remains.first);
delete pinst;
}
else if(inst->parentRes()){
auto pinst = inst->parentRes();
auto remains = pinst->except(inst);
remains.first->setParentRes(nullptr);
inst->setParentRes(nullptr);
auto ppinst = pinst->parentRes();
ppinst->replaceView(remains.first, pinst);
delete pinst;
}
inst->setParentRes(nullptr);
inst->setVisible(false);
removePresentView(inst);
// 当前视图已被回收
for(auto &lsn : listener_list)
lsn->freedomAppend(inst);
}
void SplitWindow::doClose(split_frame::ViewBase *inst)
{
if(isPresented(inst))
throw new Config::SimpleException<QString>("编码异常", "不能关闭非空闲视图!");
// 回收当前视图
for(auto &lsn : listener_list)
lsn->aboutToBeDelete(inst);
delete inst;
}
void SplitWindow::siblingAttach(ViewBase *view, ViewBase *pos, SplitType ori)
{
if(isPresented(view) && view != temp_show){
throw new Config::SimpleException<QString>("参数错误", "只能使用空闲视图吸附重组!");
}
if(!isPresented(pos)){
throw new Config::SimpleException<QString>("参数错误", "不能依据空闲视图吸附重组!");
}
auto remains_frm = pos->parentRes();
auto split_slot = new split_panel::SplitPanel(this, ori);
if(pos == view_root){
setPresentTarget(split_slot);
}
else{
if(!remains_frm)
throw new Config::SimpleException<QString>("参数错误", "指定吸附视图父引用为空");
remains_frm->replaceView(split_slot, pos);
}
switch (ori) {
case SplitType::SPLIT_H_LFIRST:
split_slot->initViews(view, pos);
split_slot->setSplitInfo(0.333, 8);
break;
case SplitType::SPLIT_H_RFIRST:
split_slot->initViews(pos, view);
split_slot->setSplitInfo(0.666, 8);
break;
case SplitType::SPLIT_V_TFIRST:
split_slot->initViews(view, pos);
split_slot->setSplitInfo(0.333, 8);
break;
case SplitType::SPLIT_V_BFIRST:
split_slot->initViews(pos, view);
split_slot->setSplitInfo(0.666, 8);
break;
}
for(auto &lsn : listener_list)
lsn->freedomRemove(view);
}
ViewBase *SplitWindow::adjustView() const
{
return adjust_target;
}
void SplitWindow::setAdjustView(split_frame::ViewBase *target)
{
this->adjust_target = target;
}