WindowAppUiFrame.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. #include "WindowAppUiFrame.h"
  2. #include "selectwidget.h"
  3. #include "UiManager.h"
  4. #include "WindowMain.h"
  5. #include "DialogUiOption.h"
  6. #include "WindowAppUiScene.h"
  7. #include "VPCommand.h"
  8. #include "Preferences.h"
  9. #include "VControlObject.h"
  10. WindowAppUiFrame::WindowAppUiFrame(const QString& strTitle, QWidget *parent)
  11. : QMainWindow(parent)
  12. , m_nUiViewHeight(DEFAULT_UIVIEW_HEIGHT)
  13. , m_nUiViewWidth(DEFAULT_UIVIEW_WIDTH)
  14. , actionUndo(nullptr)
  15. , actionRedo(nullptr)
  16. {
  17. ui.setupUi(this);
  18. m_nScrollValueH = 0;
  19. m_nScrollValueV = 0;
  20. // UI元素初始化
  21. this->initUI();
  22. // 初始化布局工具栏
  23. this->initLayoutToolbar();
  24. //// 初始化控件工具栏
  25. //this->initControlToolbar();
  26. this->addToolBar(m_layoutToolbar);
  27. m_layoutToolbar->setMovable(false);
  28. //this->addToolBarBreak();
  29. //this->addToolBar(m_controlToolbar);
  30. //m_controlToolbar->setMovable(false);
  31. // 初始化UiView
  32. ui.widgetUiView->init(strTitle, ui.uiNavView, this, ui.objectController);
  33. // 绑定鸟瞰图缩放时的同步刷新动作
  34. connect(ui.widgetUiView, &WindowAppUiView::navigatorViewRequired, this, [=](bool required, const QTransform& tf)
  35. {
  36. Q_UNUSED(required);
  37. Q_UNUSED(tf);
  38. //ui.uiNavView->setTransform(WindowAppPouView::resetScale(tf));
  39. ui.uiNavView->fitInView(ui.uiNavView->sceneRect(), Qt::KeepAspectRatio);
  40. ui.uiNavView->setVisible(required);
  41. ui.uiNavView->updateMainViewportRegion();
  42. }
  43. );
  44. //// 矩形区域变动时的响应动作
  45. //connect(ui.widgetUiView, &WindowAppUiView::viewportRectChanged, ui.uiNavView, &WindowAppUiNavView::updateMainViewportRegion);
  46. // 统一转换为初始化函数
  47. //ui.widgetUiView->uiScene()->m_pPropertyController = ui.objectController;
  48. //ui.widgetUiView->m_strPageName = strTitle;
  49. // g_pUiManager->registerNewUi(ui.widgetUiView);
  50. //// 将当前Scene绑定到鸟瞰图中进行同步
  51. //ui.uiNavView->setScene((QGraphicsScene*)ui.widgetUiView->scene());
  52. //// 绑定同步的鸟瞰图
  53. //ui.uiNavView->setMainView(ui.widgetUiView);
  54. //// 调整View
  55. //ui.uiNavView->fitInView(ui.uiNavView->sceneRect(), Qt::KeepAspectRatio);
  56. WindowAppUiScene* pScene = ui.widgetUiView->uiScene();
  57. WindowAppUiView* pView = ui.widgetUiView;
  58. WindowAppUiFrame* pFrame = this;
  59. vDebug() << pScene << " " << pView << " " << pFrame;
  60. }
  61. WindowAppUiFrame::~WindowAppUiFrame()
  62. {
  63. }
  64. /// <summary>
  65. /// 获取本Frame下的View指针
  66. /// </summary>
  67. /// <returns></returns>
  68. WindowAppUiView* WindowAppUiFrame::getUiView()
  69. {
  70. return ui.widgetUiView;
  71. }
  72. /// <summary>
  73. /// UI元素初始化
  74. /// </summary>
  75. void WindowAppUiFrame::initUI()
  76. {
  77. //QWidget* mainWidget = new QWidget();
  78. //QVBoxLayout* mainLayout = new QVBoxLayout();
  79. //mainLayout->addWidget(ui.toolbarLayoutFrame, 0, Qt::AlignTop);
  80. //mainLayout->addWidget(ui.toolbarControlFrame, 1, Qt::AlignTop);
  81. //mainLayout->addWidget(ui.widgetUiView);
  82. //mainLayout->setContentsMargins(0, 0, 0, 0);
  83. //mainLayout->setSpacing(0);
  84. //mainWidget->setLayout(mainLayout);
  85. //this->setCentralWidget(mainWidget);
  86. // 2021-8-30 在QMainWindow作为QMdiSubView时,需要将QMainWindow设置为 Widget风格,否则窗体不显示
  87. this->setWindowFlags(Qt::Widget);
  88. ui.widgetUiView->uiScene()->m_pUiFrame = this;
  89. QScrollArea* ScrollArea = new QScrollArea(ui.widget_1);
  90. ScrollArea->setWidget(ui.widgetUiView);//设置滚动条
  91. ui.gridLayout->addWidget(ScrollArea);
  92. connect(ScrollArea->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(horizontalValueChanged(int)));
  93. connect(ScrollArea->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(verticalValueChanged(int)));
  94. //connect(ScrollArea->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(valueChanged(int)));
  95. ui.widgetUiView->resize(this->m_nUiViewWidth, this->m_nUiViewHeight);
  96. // 初始化界面分隔区域
  97. //for (int i = 0; i < thePrefs.listUiStretchFactors.size(); i++)
  98. //{
  99. // ui.splitter->setStretchFactor(i, 4);
  100. //}
  101. //// 更新界面分隔区域
  102. //this->updateSplitterFromPref();
  103. // 先按照默认尺寸进行拆分
  104. ui.splitter->setStretchFactor(0, 4);
  105. ui.splitter->setStretchFactor(1, 2);
  106. //QList<int> list = ui.splitter->sizes();
  107. }
  108. /// <summary>
  109. /// 初始化布局工具栏
  110. /// </summary>
  111. void WindowAppUiFrame::initLayoutToolbar()
  112. {
  113. m_layoutToolbar = new QToolBar();
  114. m_layoutToolbar->setToolButtonStyle(Qt::ToolButtonIconOnly);
  115. QAction* actionZorderTop = new QAction(QIcon(":/image/ZorderTop.png"), ("ZorderTop"));
  116. QAction* actionZorderBottom = new QAction(QIcon(":/image/ZorderBottom.png"), ("ZorderBottom"));
  117. QAction* actionZorderUp = new QAction(QIcon(":/image/ZorderUp.png"), ("ZorderUp"));
  118. QAction* actionZorderDown = new QAction(QIcon(":/image/ZorderDown.png"), ("ZorderDown"));
  119. // QAction* actionAlignLeft = new QAction(QIcon(":/image/AlignLeft.png"), ("Align Left"));
  120. // QAction* actionAlignTop = new QAction(QIcon(":/image/AlignTop.png"), ("Align Top"));
  121. // QAction* actionAlignRight = new QAction(QIcon(":/image/AlignRight.png"), ("Align Right"));
  122. // QAction* actionAlignBottom = new QAction(QIcon(":/image/AlignBottom.png"), ("Align Bottom"));
  123. // QAction* actionSamesize = new QAction(QIcon("./image/Samesize.png"), ("Make same size"));
  124. // QAction* actionZoomIn = new QAction(QIcon(":/image/ZoomOut.png"), ("Zoom In"));
  125. // QAction* actionZoomOut = new QAction(QIcon(":/image/ZoomIn.png"), ("Zoom Out"));
  126. // QAction* actionZoomZero = new QAction(QIcon(":/image/Zoom.png"), ("Zoom Zero"));
  127. QAction* actionOption = new QAction(QIcon(":/image/Option.png"), ("Options"));
  128. // QAction* actionSnap = new QAction(QIcon(":/image/Snap.png"), ("Snap to Grid"));
  129. // 2022-9-29,增加了Undo和Redo操作
  130. actionUndo = new QAction(QIcon(":/image/Undo.png"), ("Undo"));
  131. actionRedo = new QAction(QIcon(":/image/Redo.png"), ("Redo"));
  132. // QAction* actionUpdate = new QAction(QIcon(":/image/Update.png"), ("Update ro Runtime"));
  133. QAction* actionDelete = new QAction(QIcon(":/image/Delete.png"), ("Delete"));
  134. QAction* actionPublish = new QAction(QIcon(":/image/ui_run.png"), ("Publish UI in Runtime"));
  135. m_layoutToolbar->addAction(actionZorderTop);
  136. m_layoutToolbar->addAction(actionZorderBottom);
  137. m_layoutToolbar->addAction(actionZorderUp);
  138. m_layoutToolbar->addAction(actionZorderDown);
  139. m_layoutToolbar->addSeparator();
  140. // m_layoutToolbar->addAction(actionAlignLeft);
  141. // m_layoutToolbar->addAction(actionAlignTop);
  142. // m_layoutToolbar->addAction(actionAlignRight);
  143. // m_layoutToolbar->addAction(actionAlignBottom);
  144. // m_layoutToolbar->addAction(actionSamesize);
  145. // m_layoutToolbar->addSeparator();
  146. // m_layoutToolbar->addAction(actionZoomIn);
  147. // m_layoutToolbar->addAction(actionZoomOut);
  148. // m_layoutToolbar->addAction(actionZoomZero);
  149. m_layoutToolbar->addAction(actionOption);
  150. // m_layoutToolbar->addAction(actionSnap);
  151. m_layoutToolbar->addSeparator();
  152. m_layoutToolbar->addAction(actionUndo);
  153. m_layoutToolbar->addAction(actionRedo);
  154. m_layoutToolbar->addSeparator();
  155. // m_layoutToolbar->addAction(actionUpdate);
  156. m_layoutToolbar->addAction(actionDelete);
  157. m_layoutToolbar->addSeparator();
  158. m_layoutToolbar->addAction(actionPublish);
  159. m_layoutToolbar->setIconSize(QSize(14, 14));
  160. // 工具栏Signal
  161. connect(actionZorderTop, &QAction::triggered, this, &WindowAppUiFrame::onToolZorderTop);
  162. connect(actionZorderBottom, &QAction::triggered, this, &WindowAppUiFrame::onToolZorderBottom);
  163. connect(actionZorderUp, &QAction::triggered, this, &WindowAppUiFrame::onToolZorderUp);
  164. connect(actionZorderDown, &QAction::triggered, this, &WindowAppUiFrame::onToolZorderDown);
  165. connect(actionUndo, &QAction::triggered, this, &WindowAppUiFrame::onToolUndo);
  166. connect(actionRedo, &QAction::triggered, this, &WindowAppUiFrame::onToolRedo);
  167. connect(actionPublish, &QAction::triggered, this, &WindowAppUiFrame::onToolPublish);
  168. connect(actionDelete, &QAction::triggered, this, &WindowAppUiFrame::onToolDelete);
  169. connect(actionOption, &QAction::triggered, this, &WindowAppUiFrame::onToolOption);
  170. // 拆分栏Signal
  171. connect(ui.splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(slotSplitterMoved(int, int)));
  172. }
  173. /// <summary>
  174. /// 拆分条移动时(暂未使用)
  175. /// </summary>
  176. /// <param name="pos"></param>
  177. /// <param name="index"></param>
  178. void WindowAppUiFrame::slotSplitterMoved(int pos, int index)
  179. {
  180. Q_UNUSED(pos);
  181. Q_UNUSED(index);
  182. QList<int> list = ui.splitter->sizes();
  183. // qDebug() << list;
  184. }
  185. //========================================================================
  186. //
  187. // 刻度尺绘制相关
  188. //
  189. //========================================================================
  190. /// <summary>
  191. /// 绘制水平刻度尺
  192. /// </summary>
  193. /// <param name="painter"></param>
  194. /// <param name="pen"></param>
  195. void WindowAppUiFrame::DrawHorizontalScale(QPainter* painter, QPen* pen)
  196. {
  197. int Y = 51;
  198. int X = 4;
  199. //绘制一条水平坐标线
  200. QPoint ptBegin(X, Y);
  201. QPoint ptEnd(this->rect().width(), Y);
  202. painter->drawLine(ptBegin, ptEnd);
  203. float m_fInterval = 4;
  204. float fDrawLeft = 10;
  205. int nIndex = 0;
  206. int nScaleHeight = 8; //刻度线高度
  207. while (fDrawLeft < this->rect().width())
  208. {
  209. if ((nIndex % 2 == 0) && (nIndex % 5 == 0))
  210. {
  211. nScaleHeight = 8;
  212. QString sText = QString::number(nIndex / 10);
  213. painter->drawText(QPoint(fDrawLeft + X + 2, Y - nScaleHeight + 2), sText);
  214. }
  215. else
  216. {
  217. pen->setWidth(1);
  218. painter->setPen(*pen);
  219. //当是中间节点时,长度要比一般的长
  220. nScaleHeight = (nIndex % 4) == 0 ? 4 : 2;
  221. }
  222. //绘制刻度值
  223. painter->drawRect(QRectF((double)fDrawLeft + (double)X, (double)Y - (double)nScaleHeight, 0.1, (double)nScaleHeight));
  224. fDrawLeft += m_fInterval;
  225. nIndex = nIndex + 1;
  226. }
  227. }
  228. /// <summary>
  229. /// 绘制垂直刻度尺
  230. /// </summary>
  231. /// <param name="painter"></param>
  232. /// <param name="pen"></param>
  233. void WindowAppUiFrame::DrawVerticalScale(QPainter* painter, QPen* pen)
  234. {
  235. //绘制一条垂直坐标线
  236. int X = 15 - 1;
  237. int Y = 51;
  238. QPoint ptBegin(X, Y);
  239. QPoint ptEnd(X, ui.widgetUiView->rect().height() - Y);
  240. painter->drawLine(ptBegin, ptEnd);
  241. float m_fInterval = 4;
  242. float fDrawTop = 0;
  243. int nIndex = 0;
  244. int nScaleWidth = 20; //刻度线宽度
  245. while (fDrawTop < this->rect().height())
  246. {
  247. if ((nIndex % 2 == 0) && (nIndex % 5 == 0))
  248. {
  249. nScaleWidth = 8;
  250. QString sText = QString::number(nIndex / 10);
  251. int fontWidth = fontMetrics().width(sText);
  252. int nleft = (((X - nScaleWidth) - fontWidth) / 2) + 4;
  253. painter->drawText(QPoint(nleft, fDrawTop + Y + 10), sText);
  254. }
  255. else
  256. {
  257. pen->setWidth(1);
  258. painter->setPen(*pen);
  259. //当是中间节点时,长度要比一般的长
  260. nScaleWidth = (nIndex % 4) == 0 ? 4 : 2;
  261. }
  262. //绘制刻度值
  263. painter->drawRect(QRectF((double)X - (double)nScaleWidth, (double)fDrawTop + (double)Y, nScaleWidth, 0.1));
  264. fDrawTop += m_fInterval;
  265. nIndex++;
  266. }
  267. }
  268. /// <summary>
  269. /// 绘制界面
  270. /// </summary>
  271. /// <param name=""></param>
  272. void WindowAppUiFrame::paintEvent(QPaintEvent*)
  273. {
  274. QPainter painter(this);
  275. //设置画刷
  276. QPen pen(Qt::black, 1);
  277. pen.setWidth(1);
  278. painter.setPen(pen);
  279. painter.translate(0, 0);
  280. //抗锯齿绘制
  281. painter.setRenderHint(QPainter::Antialiasing);
  282. //绘制水平刻度尺
  283. this->DrawHorizontalScale(&painter, &pen);
  284. //绘制垂直刻度尺
  285. this->DrawVerticalScale(&painter, &pen);
  286. // 刷新Undo菜单启用禁用
  287. this->refreshUndoMenu();
  288. }
  289. /// <summary>
  290. /// 水平滚动条数值改变时,保存数值
  291. /// </summary>
  292. /// <param name="value"></param>
  293. void WindowAppUiFrame::horizontalValueChanged(int value)
  294. {
  295. m_nScrollValueH = value;
  296. }
  297. /// <summary>
  298. /// 垂直滚动条数值改变时,保存数值
  299. /// </summary>
  300. /// <param name="value"></param>
  301. void WindowAppUiFrame::verticalValueChanged(int value)
  302. {
  303. m_nScrollValueV = value;
  304. }
  305. void WindowAppUiFrame::onToolZorderTop()
  306. {
  307. ui.widgetUiView->uiScene()->zorderTopCurrentControl();
  308. }
  309. void WindowAppUiFrame::onToolZorderBottom()
  310. {
  311. ui.widgetUiView->uiScene()->zorderBottomCurrentControl();
  312. }
  313. void WindowAppUiFrame::onToolZorderUp()
  314. {
  315. ui.widgetUiView->uiScene()->zorderUpCurrentControl();
  316. }
  317. void WindowAppUiFrame::onToolZorderDown()
  318. {
  319. ui.widgetUiView->uiScene()->zorderDownCurrentControl();
  320. }
  321. /// <summary>
  322. /// Undo
  323. /// </summary>
  324. void WindowAppUiFrame::onToolUndo()
  325. {
  326. // vDebug() << "WindowAppUiFrame::onToolUndo()";
  327. ui.widgetUiView->uiScene()->m_CommandManager.undo();
  328. }
  329. /// <summary>
  330. /// Redo
  331. /// </summary>
  332. void WindowAppUiFrame::onToolRedo()
  333. {
  334. // vDebug() << "WindowAppUiFrame::onToolRedo()";
  335. ui.widgetUiView->uiScene()->m_CommandManager.redo();
  336. }
  337. //========================================================================
  338. //
  339. // Toolbar 消息处理
  340. //
  341. //========================================================================
  342. /// <summary>
  343. /// UI界面设置
  344. /// </summary>
  345. void WindowAppUiFrame::onToolOption()
  346. {
  347. DialogUiOption dialogUiOption(
  348. this->m_nUiViewWidth,
  349. this->m_nUiViewHeight,
  350. this
  351. );
  352. // 进行UI界面设置
  353. if (dialogUiOption.exec() == QDialog::Accepted)
  354. {
  355. // 保存用户设置的UI宽度和高度
  356. this->m_nUiViewWidth = dialogUiOption.m_nWidth;
  357. this->m_nUiViewHeight = dialogUiOption.m_nHeight;
  358. // 同步修改UiView和UiScene的界面尺寸
  359. ui.widgetUiView->resize(this->m_nUiViewWidth, this->m_nUiViewHeight);
  360. // 调整鸟瞰图View
  361. ui.uiNavView->fitInView(ui.uiNavView->sceneRect(), Qt::KeepAspectRatio);
  362. }
  363. }
  364. /// <summary>
  365. /// Ui控件删除
  366. /// </summary>
  367. void WindowAppUiFrame::onToolDelete()
  368. {
  369. // ui.widgetUiView->uiScene()->deleteCurrentControl();
  370. // 2022-10-19,统一替换成了Undo框架进行删除,但是步骤要复杂一些
  371. WindowAppUiScene* uiScene = ui.widgetUiView->uiScene();
  372. // 获取当前删除的控件
  373. VControlObject* pDelControl = uiScene->getCurrentControl();
  374. if (pDelControl == nullptr)
  375. {
  376. vDebug() << "Ignore, current control is nullptr.";
  377. return;
  378. }
  379. // 求出控件的中心点坐标
  380. // 由于控件并非是QGraphicObject,所以位置需要换算一下
  381. QPoint ptControlPos = pDelControl->m_pWidget->pos();
  382. ptControlPos.setX(ptControlPos.x() + pDelControl->m_pWidget->geometry().width() / 2);
  383. ptControlPos.setY(ptControlPos.y() + pDelControl->m_pWidget->geometry().height() / 2);
  384. //QPoint ptPos = pDelControl->m_pProxyWidget->scenePos().toPoint();
  385. // QPoint ptPos2 = pDelControl->m_pWidget->pos();
  386. // 生成删除指令,调用Undo体系进行删除
  387. UiControlDelCommand* controlDelCommand = new UiControlDelCommand(
  388. uiScene,
  389. pDelControl->m_Type,
  390. pDelControl->m_strID,
  391. ptControlPos,
  392. pDelControl->m_pWidget->size()
  393. );
  394. uiScene->m_CommandManager.executeCommand(controlDelCommand);
  395. }
  396. /// <summary>
  397. /// UI界面发布至Runtime
  398. /// </summary>
  399. void WindowAppUiFrame::onToolPublish()
  400. {
  401. qDebug() << "WindowAppUiFrame::onActionRun.";
  402. // 通过Manager发布所有UI
  403. bool bRet = g_pUiManager->publishAll();
  404. if (bRet)
  405. {
  406. INFORMATION_MESSAGE("Publish to runtime success!");
  407. // 成功发布后,通知主框架把页面切换到Runtime页面
  408. g_pMainWindow->onViewRunTime();
  409. }
  410. else
  411. {
  412. // CRITICAL_MESSAGE("Publish to runtime failed!");
  413. }
  414. }
  415. /// <summary>
  416. /// 序列化支持
  417. /// </summary>
  418. /// <param name="dataStream"></param>
  419. /// <param name="in"></param>
  420. /// <returns></returns>
  421. bool WindowAppUiFrame::serialized(QDataStream& ar, bool in /*= true*/)
  422. {
  423. int paranum;//参数数量
  424. // 保存
  425. if (!in)
  426. {
  427. paranum = 3;
  428. ar << paranum;//先保存参数数量
  429. // 宽和高
  430. ar << (int)1 << m_nUiViewWidth;
  431. ar << (int)2 << m_nUiViewHeight;
  432. ar << (int)3 << ui.splitter->sizes();
  433. }
  434. // 读取
  435. else
  436. {
  437. QList<int> splitters;
  438. int para;
  439. ar >> paranum;//读取参数数量
  440. for (int i = 0; i < paranum; i++)
  441. {
  442. ar >> para;
  443. switch (para)
  444. {
  445. case 1: ar >> m_nUiViewWidth; break;
  446. case 2: ar >> m_nUiViewHeight; break;
  447. case 3: ar >> splitters; break;
  448. default:
  449. {
  450. vWarning() << "Serialized(In) Error";
  451. return false;
  452. }
  453. break;
  454. }
  455. }
  456. // 设置Splitter 在 UI 上无数据的时候的(应该是属性表无数据)Splitter 的 sizes 是无效的
  457. if (splitters.size()==2
  458. && splitters[0] > 0
  459. && splitters[1] > 0)
  460. {
  461. ui.splitter->setSizes(splitters);
  462. }
  463. }
  464. return true;
  465. }
  466. /// <summary>
  467. /// 刷新Undo/Redo按钮
  468. /// </summary>
  469. void WindowAppUiFrame::refreshUndoMenu()
  470. {
  471. if (actionUndo != nullptr)
  472. {
  473. actionUndo->setEnabled( ui.widgetUiView->uiScene()->m_CommandManager.canUndo());
  474. actionRedo->setEnabled( ui.widgetUiView->uiScene()->m_CommandManager.canRedo());
  475. }
  476. }