532 lines
17 KiB
C++
532 lines
17 KiB
C++
#include "splitpanel.h"
|
|
#include "baseview.h"
|
|
#include "splitview.h"
|
|
#include <QApplication>
|
|
#include <QDebug>
|
|
#include <QDrag>
|
|
#include <QHBoxLayout>
|
|
#include <QLineF>
|
|
#include <QMimeData>
|
|
#include <QPainter>
|
|
#include <QPushButton>
|
|
#include <QResizeEvent>
|
|
#include <QStyleOption>
|
|
#include <libConfig.h>
|
|
|
|
namespace SplitFrame {
|
|
|
|
/**
|
|
* @brief 承接堆放操作及设定摆放位置
|
|
*/
|
|
class SPLITVIEW_EXPORT AttachPanel : public QWidget {
|
|
enum class ActiveArea { LEFT, RIGHT, TOP, BOTTOM, CENTER, NONE };
|
|
|
|
public:
|
|
AttachPanel(ViewPresent *host);
|
|
|
|
void bindAttachment(RectCom *widget);
|
|
RectCom *attachmentTarget() const;
|
|
|
|
virtual void paintEvent(QPaintEvent *event) override;
|
|
virtual void dragMoveEvent(QDragMoveEvent *event) override;
|
|
virtual void dragEnterEvent(QDragEnterEvent *event) override;
|
|
virtual void dropEvent(QDropEvent *event) override;
|
|
|
|
private:
|
|
ViewPresent *const adjust_host;
|
|
RectCom *current_target;
|
|
ActiveArea active_comp;
|
|
|
|
std::tuple<QRectF, QRectF, QRectF, QRectF, QRectF> view_rects() const;
|
|
};
|
|
|
|
} // namespace SplitFrame
|
|
|
|
using namespace SplitFrame;
|
|
using namespace Config;
|
|
|
|
AttachPanel::AttachPanel(ViewPresent *host) : QWidget(host->bind()), adjust_host(host) {
|
|
setWindowOpacity(50);
|
|
setAcceptDrops(true);
|
|
}
|
|
|
|
void AttachPanel::bindAttachment(RectCom *widget) { this->current_target = widget; }
|
|
|
|
RectCom *AttachPanel::attachmentTarget() const { return this->current_target; }
|
|
|
|
void AttachPanel::paintEvent(QPaintEvent *event) {
|
|
QWidget::paintEvent(event);
|
|
|
|
QPainter p(this);
|
|
p.setBrush(Qt::lightGray);
|
|
p.fillRect(this->rect(), Qt::lightGray);
|
|
|
|
auto rect = this->rect();
|
|
p.setPen(QPen(Qt::black, 4));
|
|
switch (active_comp) {
|
|
case ActiveArea::LEFT:
|
|
p.fillRect(QRectF(rect.topLeft(), QSizeF(rect.width() / 2, rect.height())), Qt::gray);
|
|
break;
|
|
case ActiveArea::RIGHT:
|
|
p.fillRect(QRectF(rect.center() - QPointF(0, rect.height() / 2), QSizeF(rect.width() / 2, rect.height())), Qt::gray);
|
|
break;
|
|
case ActiveArea::TOP:
|
|
p.fillRect(QRectF(rect.topLeft(), QSizeF(rect.width(), rect.height() / 2)), Qt::gray);
|
|
break;
|
|
case ActiveArea::BOTTOM:
|
|
p.fillRect(QRectF(rect.center() - QPointF(rect.width() / 2, 0), QSizeF(rect.width(), rect.height() / 2)), Qt::gray);
|
|
break;
|
|
case ActiveArea::CENTER:
|
|
if (attachmentTarget()->canReplace())
|
|
p.fillRect(rect, Qt::gray);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
p.setBrush(Qt::transparent);
|
|
p.setPen(QPen(Qt::black, 1));
|
|
|
|
auto x_views = view_rects();
|
|
QVector<QRectF> rects;
|
|
rects << std::get<0>(x_views);
|
|
rects << std::get<1>(x_views);
|
|
rects << std::get<2>(x_views);
|
|
rects << std::get<3>(x_views);
|
|
if (attachmentTarget()->canReplace())
|
|
rects << std::get<4>(x_views);
|
|
p.drawRects(rects);
|
|
}
|
|
|
|
void AttachPanel::dragMoveEvent(QDragMoveEvent *event) {
|
|
QWidget::dragMoveEvent(event);
|
|
|
|
auto tuple_list = view_rects();
|
|
if (std::get<0>(tuple_list).contains(event->pos())) {
|
|
this->active_comp = ActiveArea::LEFT;
|
|
} else if (std::get<1>(tuple_list).contains(event->pos())) {
|
|
this->active_comp = ActiveArea::RIGHT;
|
|
|
|
} else if (std::get<2>(tuple_list).contains(event->pos())) {
|
|
this->active_comp = ActiveArea::TOP;
|
|
|
|
} else if (std::get<3>(tuple_list).contains(event->pos())) {
|
|
this->active_comp = ActiveArea::BOTTOM;
|
|
|
|
} else if (std::get<4>(tuple_list).contains(event->pos())) {
|
|
this->active_comp = ActiveArea::CENTER;
|
|
} else {
|
|
this->active_comp = ActiveArea::NONE;
|
|
}
|
|
|
|
this->update();
|
|
}
|
|
|
|
void AttachPanel::dragEnterEvent(QDragEnterEvent *event) {
|
|
QWidget::dragEnterEvent(event);
|
|
|
|
if (adjust_host->adjustState())
|
|
event->acceptProposedAction();
|
|
}
|
|
|
|
void AttachPanel::dropEvent(QDropEvent *event) {
|
|
QWidget::dropEvent(event);
|
|
event->acceptProposedAction();
|
|
|
|
auto xfrom = adjust_host->adjustView();
|
|
auto target = this->attachmentTarget();
|
|
|
|
if (target != xfrom && active_comp != ActiveArea::NONE) {
|
|
if (active_comp == ActiveArea::CENTER && !target->canReplace()) {
|
|
} else {
|
|
static_cast<SplitRect *>(xfrom->parentRes())->removeComp(xfrom);
|
|
adjust_host->objsRelateRebuild();
|
|
|
|
auto ptarget = static_cast<SplitRect *>(target->parentRes());
|
|
auto target_rect = target->outline();
|
|
|
|
RectCom *new_split = nullptr;
|
|
switch (this->active_comp) {
|
|
case ActiveArea::LEFT: {
|
|
new_split = new SplitView(xfrom, target, adjust_host->bind());
|
|
static_cast<SplitView *>(new_split)->setSplitInfo(SplitType::SPLIT_H, target_rect.width() / 2, adjust_host->splitterWidth(), false);
|
|
} break;
|
|
case ActiveArea::RIGHT: {
|
|
new_split = new SplitView(target, xfrom, adjust_host->bind());
|
|
static_cast<SplitView *>(new_split)->setSplitInfo(SplitType::SPLIT_H, target_rect.width() / 2, adjust_host->splitterWidth(), false);
|
|
} break;
|
|
case ActiveArea::TOP: {
|
|
new_split = new SplitView(xfrom, target, adjust_host->bind());
|
|
static_cast<SplitView *>(new_split)->setSplitInfo(SplitType::SPLIT_V, target_rect.height() / 2, adjust_host->splitterWidth(), false);
|
|
} break;
|
|
case ActiveArea::BOTTOM: {
|
|
new_split = new SplitView(target, xfrom, adjust_host->bind());
|
|
static_cast<SplitView *>(new_split)->setSplitInfo(SplitType::SPLIT_V, target_rect.height() / 2, adjust_host->splitterWidth(), false);
|
|
} break;
|
|
case ActiveArea::CENTER: {
|
|
new_split = xfrom;
|
|
adjust_host->markFreedom(target);
|
|
} break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
ptarget->replaceComp(new_split, target);
|
|
new_split->relayout(target_rect);
|
|
adjust_host->objsRelateRebuild();
|
|
}
|
|
}
|
|
|
|
adjust_host->setAdjustView();
|
|
this->setVisible(false);
|
|
}
|
|
|
|
std::tuple<QRectF, QRectF, QRectF, QRectF, QRectF> AttachPanel::view_rects() const {
|
|
auto rect = this->rect();
|
|
|
|
auto boder_len = std::min(rect.width() - 4, rect.height() - 4);
|
|
auto rect_length = std::min(boder_len * 4 / 5, 300);
|
|
auto rect_height = rect_length / 3;
|
|
|
|
auto lt0 = rect.center() - QPoint(rect_height / 2, rect_length / 2);
|
|
auto lt1 = rect.center() - QPoint(rect_length / 2, rect_height / 2);
|
|
|
|
return std::make_tuple(QRectF(lt1 - QPointF(3, 0), QSizeF(rect_height, rect_height)),
|
|
QRectF(lt1 + QPoint(rect_height * 2 + 3, 0), QSizeF(rect_height, rect_height)),
|
|
QRectF(lt0 - QPointF(0, 3), QSizeF(rect_height, rect_height)),
|
|
QRectF(lt0 + QPointF(0, rect_height * 2 + 3), QSizeF(rect_height, rect_height)),
|
|
QRectF(lt1 + QPointF(rect_height, 0), QSizeF(rect_height, rect_height)));
|
|
}
|
|
|
|
ViewPresent::ViewPresent(QWidget *parent) : QWidget(parent), accept_panel(new AttachPanel(this)) {
|
|
accept_panel->hide();
|
|
setMouseTracking(true);
|
|
}
|
|
|
|
ViewPresent::~ViewPresent() { accept_panel->deleteLater(); }
|
|
|
|
void ViewPresent::addListener(FreedomViewsListener *lsn) {
|
|
if (lsn_list.contains(lsn))
|
|
return;
|
|
lsn_list << lsn;
|
|
}
|
|
|
|
void ViewPresent::removeListener(FreedomViewsListener *lsn) { lsn_list.removeAll(lsn); }
|
|
|
|
void ViewPresent::regist_basepanel(RectCom *it) {
|
|
if (this->all_func_views.contains(it))
|
|
return;
|
|
|
|
dynamic_cast<BaseView *>(it)->installPerceptionHandle(this);
|
|
all_func_views << it;
|
|
}
|
|
|
|
void ViewPresent::markFreedom(ViewRes *view, bool add) {
|
|
if (!view)
|
|
return;
|
|
|
|
auto cinst = static_cast<RectCom *>(view);
|
|
if (add) {
|
|
if (!freedom_views.contains(cinst)) {
|
|
freedom_views << cinst;
|
|
|
|
auto fview = static_cast<BaseView *>(view);
|
|
for (auto &lsn : lsn_list)
|
|
lsn->freedomAppended(cinst, fview->viewIcon(), fview->title());
|
|
}
|
|
|
|
cinst->bind()->setVisible(false);
|
|
cinst->setParentRes(nullptr);
|
|
} else {
|
|
if (freedom_views.contains(cinst)) {
|
|
freedom_views.removeAll(cinst);
|
|
|
|
for (auto &lsn : lsn_list)
|
|
lsn->freedomRemoved(cinst);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ViewPresent::purge(ViewRes *target) {
|
|
if (!target)
|
|
return;
|
|
|
|
auto cinst = static_cast<RectCom *>(target);
|
|
if (!all_func_views.contains(cinst))
|
|
throw new SimpleException<bool>("参数非法", "目标实例不属于本ViewPresent");
|
|
|
|
cinst->bind()->setVisible(false);
|
|
target->setParentRes(nullptr);
|
|
if (temp_visible_view.second == cinst)
|
|
temp_visible_view.second = nullptr;
|
|
|
|
all_func_views.removeAll(cinst);
|
|
freedom_views.removeAll(cinst);
|
|
display_members = nullptr;
|
|
objsRelateRebuild();
|
|
|
|
delete cinst;
|
|
}
|
|
|
|
void ViewPresent::temporaryVisible(DockType t, RectCom *target) {
|
|
if (target != nullptr && !this->freedom_views.contains(target))
|
|
throw new SimpleException<QString>("参数异常", "非闲置视图不可以设置为临时视图");
|
|
|
|
if (this->temp_visible_view.second) {
|
|
markFreedom(temp_visible_view.second);
|
|
}
|
|
|
|
temp_visible_view = std::make_pair(t, target);
|
|
if (temp_visible_view.second) {
|
|
temp_visible_view.second->setParentRes(this);
|
|
temp_visible_view.second->bind()->setVisible(true);
|
|
objsRelateRebuild();
|
|
} else
|
|
relayout();
|
|
}
|
|
|
|
bool ViewPresent::isTemporaryView(RectCom *view) { return this->temp_visible_view.second == view; }
|
|
|
|
void ViewPresent::setAdjustView(RectCom *one) {
|
|
if (one) {
|
|
this->adjust_view_temp = one;
|
|
dynamic_cast<ViewRes *>(adjust_view_temp)->bind()->setVisible(false);
|
|
dynamic_cast<ViewRes *>(adjust_view_temp)->bind()->repaint();
|
|
} else {
|
|
dynamic_cast<ViewRes *>(adjust_view_temp)->bind()->setVisible(true);
|
|
dynamic_cast<ViewRes *>(adjust_view_temp)->bind()->repaint();
|
|
this->adjust_view_temp = one;
|
|
}
|
|
}
|
|
|
|
bool ViewPresent::adjustState() const { return this->adjust_view_temp != nullptr; }
|
|
|
|
RectCom *ViewPresent::adjustView() const { return this->adjust_view_temp; }
|
|
|
|
QObject *ViewPresent::globalEventFilter() const { return dynamic_cast<QObject *>(const_cast<ViewPresent *>(this)); }
|
|
|
|
SplitRect *ViewPresent::createSplit(RectCom *first, RectCom *next) {
|
|
auto inst = new SplitView(first, next, this);
|
|
return inst;
|
|
}
|
|
|
|
const QList<RectCom *> ViewPresent::freedomViews() const {
|
|
QList<RectCom *> ret_list;
|
|
for (auto &vit : freedom_views)
|
|
ret_list << vit;
|
|
|
|
return ret_list;
|
|
}
|
|
|
|
void ViewPresent::resetEngross(RectCom *view) {
|
|
for (auto &vit : all_func_views)
|
|
vit->pRelease();
|
|
|
|
temp_visible_view = std::make_pair(DockType::LEFT, nullptr);
|
|
display_members = nullptr;
|
|
|
|
if (freedom_views.contains(view))
|
|
freedom_views.removeAll(view);
|
|
|
|
view->setParentRes(this);
|
|
view->bind()->setVisible(true);
|
|
display_members = view;
|
|
|
|
objsRelateRebuild();
|
|
}
|
|
|
|
bool ViewPresent::eventFilter(QObject *watched, QEvent *event) {
|
|
auto adjust_state = adjustState();
|
|
|
|
if (adjust_state && event->type() == QEvent::DragEnter) {
|
|
for (auto &v : all_func_views) {
|
|
if (v->contains((QWidget *)watched) && !isTemporaryView(v)) {
|
|
auto outline = v->outline();
|
|
QPoint gpos(v->bind()->mapToGlobal(outline.topLeft().toPoint()));
|
|
QPoint localpos(mapFromGlobal(gpos));
|
|
|
|
accept_panel->raise();
|
|
accept_panel->setGeometry(QRect(localpos, outline.size().toSize()));
|
|
accept_panel->setVisible(true);
|
|
|
|
accept_panel->bindAttachment(v);
|
|
event->accept();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (event->type() == QEvent::Drop) {
|
|
accept_panel->hide();
|
|
accept_panel->lower();
|
|
}
|
|
|
|
if (this->temp_visible_view.second && event->type() == QEvent::MouseButtonPress) {
|
|
if (!temp_visible_view.second->contains((QWidget *)watched)) {
|
|
temporaryVisible(DockType::LEFT, nullptr);
|
|
}
|
|
}
|
|
|
|
return QWidget::eventFilter(watched, event);
|
|
}
|
|
|
|
QWidget *ViewPresent::bind() const { return const_cast<ViewPresent *>(this); }
|
|
|
|
bool ViewPresent::contains(QWidget *) const { return false; }
|
|
|
|
ViewPresent *ViewPresent::viewPanel() const { return const_cast<ViewPresent *>(this); }
|
|
|
|
void ViewPresent::objsRelateRebuild() {
|
|
setParentRes();
|
|
|
|
relayout();
|
|
update();
|
|
}
|
|
|
|
std::pair<RectCom *, RectCom *> ViewPresent::child() const { return std::make_pair(display_members, nullptr); }
|
|
|
|
void ViewPresent::replaceComp(RectCom *view, RectCom *old) {
|
|
if (display_members != old)
|
|
throw new SimpleException<QString>("参数错误", "指定替换的界面不属于此界面");
|
|
|
|
if (display_members == view)
|
|
return;
|
|
|
|
view->setParentRes(this);
|
|
display_members = view;
|
|
|
|
objsRelateRebuild();
|
|
}
|
|
|
|
float ViewPresent::splitterWidth() const { return std::get<2>(split_info_store); }
|
|
|
|
float ViewPresent::splitterPos() const { return std::get<1>(split_info_store); }
|
|
|
|
SplitType ViewPresent::splitType() const { return std::get<0>(split_info_store); }
|
|
|
|
void ViewPresent::setSplitInfo(SplitType type, float pos, float width, bool relayout) {
|
|
this->split_info_store = std::make_tuple(type, pos, width);
|
|
if (relayout)
|
|
this->relayout();
|
|
}
|
|
|
|
QRectF ViewPresent::outline() const { return this->rect(); }
|
|
|
|
void ViewPresent::relayout(const QRectF &outline) {
|
|
setGeometry(outline.toRect());
|
|
relayout();
|
|
}
|
|
|
|
QString ViewPresent::title() const { return ""; }
|
|
|
|
bool ViewPresent::canReplace() const { return true; }
|
|
|
|
void ViewPresent::pRelease() { throw new SimpleException<bool>("非法操作", "不允许对ViewPanel调用pRelease"); }
|
|
|
|
void ViewPresent::pClose() { throw new SimpleException<bool>("非法操作", "不允许对ViewPanel调用pClose"); }
|
|
|
|
void ViewPresent::registElement(QWidget *) { throw new SimpleException<bool>("非法操作", "不允许对ViewPanel调用registElement"); }
|
|
|
|
void ViewPresent::setParentRes(ViewRes *) {
|
|
if (display_members) {
|
|
display_members->setParentRes(this);
|
|
}
|
|
|
|
if (temp_visible_view.second) {
|
|
temp_visible_view.second->setParentRes(this);
|
|
}
|
|
}
|
|
|
|
ViewRes *ViewPresent::parentRes() const { return nullptr; }
|
|
|
|
void ViewPresent::paintEvent(QPaintEvent *ev) {
|
|
QWidget::paintEvent(ev);
|
|
|
|
if (display_members) {
|
|
display_members->bind()->setVisible(true);
|
|
display_members->bind()->update();
|
|
}
|
|
|
|
if (temp_visible_view.second) {
|
|
temp_visible_view.second->bind()->setVisible(true);
|
|
temp_visible_view.second->bind()->update();
|
|
}
|
|
|
|
for (auto &it : freedom_views) {
|
|
if (it == temp_visible_view.second)
|
|
return;
|
|
|
|
it->bind()->setVisible(false);
|
|
it->bind()->update();
|
|
}
|
|
}
|
|
|
|
void ViewPresent::removeComp(RectCom *child_inst) {
|
|
if (!child_inst)
|
|
return;
|
|
|
|
if (temp_visible_view.second == child_inst) {
|
|
temp_visible_view = std::make_pair(DockType::LEFT, nullptr);
|
|
|
|
freedom_views.removeAll(child_inst);
|
|
for (auto &lsn : lsn_list)
|
|
lsn->freedomRemoved(child_inst);
|
|
} else {
|
|
if (display_members != child_inst)
|
|
throw new SimpleException<QString>("参数非法", "不允许移除隐藏的自由视图");
|
|
|
|
display_members = nullptr;
|
|
}
|
|
|
|
child_inst->setParentRes(nullptr);
|
|
objsRelateRebuild();
|
|
}
|
|
|
|
void ViewPresent::resizeEvent(QResizeEvent *ev) {
|
|
QWidget::resizeEvent(ev);
|
|
relayout();
|
|
}
|
|
void ViewPresent::mousePressEvent(QMouseEvent *event) { QWidget::mousePressEvent(event); }
|
|
void ViewPresent::mouseReleaseEvent(QMouseEvent *event) { QWidget::mouseReleaseEvent(event); }
|
|
void ViewPresent::mouseMoveEvent(QMouseEvent *event) { QWidget::mouseMoveEvent(event); }
|
|
|
|
void ViewPresent::relayout() {
|
|
if (display_members) {
|
|
display_members->relayout(this->rect());
|
|
}
|
|
|
|
if (temp_visible_view.second) {
|
|
auto vrect = this->rect();
|
|
|
|
QRectF cube;
|
|
switch (temp_visible_view.first) {
|
|
case DockType::LEFT:
|
|
cube = QRectF(QPointF(), QSizeF(300, this->height()));
|
|
break;
|
|
case DockType::RIGHT:
|
|
cube = QRectF(vrect.topRight() - QPointF(300, 0), QSizeF(300, this->height()));
|
|
break;
|
|
case DockType::TOP:
|
|
cube = QRectF(QPointF(), QSizeF(this->width(), 300));
|
|
break;
|
|
case DockType::BOTTOM:
|
|
cube = QRectF(vrect.bottomLeft() - QPointF(0, 300), QSizeF(this->width(), 300));
|
|
break;
|
|
}
|
|
|
|
temp_visible_view.second->relayout(cube);
|
|
}
|
|
|
|
update();
|
|
}
|
|
|
|
RectCom *ViewPresent::create_base_panel(QWidget *bview, const QIcon &icon, const QString &title, bool empty_flag, bool replace_flag) {
|
|
auto vinst = new BaseView(title, bview, empty_flag, replace_flag);
|
|
bview->setParent(vinst);
|
|
|
|
bview->setMouseTracking(true);
|
|
vinst->setTitle(title);
|
|
vinst->setIcon(icon);
|
|
return vinst;
|
|
}
|