CmQtEditorWindow.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. #include "CmQtEditorWindow.h"
  2. #include <QtWidgets/QTabWidget>
  3. #include <QtWidgets/QPushButton>
  4. #include <QtWidgets/QLayout>
  5. #include <QtWidgets/QLabel>
  6. #include <QtWidgets/QApplication>
  7. #include <QtGui/QMouseEvent>
  8. #include <QtGui/QPainter>
  9. #include <QtCore/QTimer>
  10. #include "CmDebug.h"
  11. #include "CmWindowDockManager.h"
  12. #include "CmEditorWindowManager.h"
  13. namespace CamelotEditor
  14. {
  15. QtEditorWindow::QtEditorWindow(QWidget* parent, const QString& name, const QString& title)
  16. :QWidget(parent), mResizeMode(RM_NONE), mMoveMode(false), mIsDocked(false), mName(name)
  17. {
  18. setupUi(title);
  19. }
  20. void QtEditorWindow::setupUi(QString title)
  21. {
  22. setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
  23. //setAttribute(Qt::WA_NoBackground, true);
  24. //setAutoFillBackground(false);
  25. //
  26. mTimer = new QTimer(this);
  27. /************************************************************************/
  28. /* TITLE BAR */
  29. /************************************************************************/
  30. mTitleBar = new QWidget(this);
  31. mTitleBar->setMouseTracking(true);
  32. mLblTitle = new QLabel(this);
  33. mLblTitle->setAttribute(Qt::WA_TransparentForMouseEvents);
  34. mBtnClose = new QPushButton(this);
  35. QHBoxLayout* titleLayout = new QHBoxLayout(this);
  36. titleLayout->setMargin(0);
  37. titleLayout->addWidget(mLblTitle, 1);
  38. titleLayout->addWidget(mBtnClose);
  39. mTitleBar->setLayout(titleLayout);
  40. /************************************************************************/
  41. /* CENTRAL LAYOUT */
  42. /************************************************************************/
  43. mCentralWidget = new QWidget(this);
  44. mContentWidget = new QWidget(this);
  45. QVBoxLayout* centralLayout = new QVBoxLayout(this);
  46. centralLayout->setMargin(0);
  47. centralLayout->addWidget(mCentralWidget);
  48. setLayout(centralLayout);
  49. QVBoxLayout* mainLayout = new QVBoxLayout(this);
  50. mainLayout->setMargin(0);
  51. mainLayout->setContentsMargins(2, 0, 2, 2);
  52. mainLayout->setSpacing(0);
  53. mainLayout->addWidget(mTitleBar);
  54. mainLayout->addWidget(mContentWidget, 1);
  55. mCentralWidget->setLayout(mainLayout);
  56. setObjectNames();
  57. retranslateUi(title);
  58. setupSignals();
  59. }
  60. void QtEditorWindow::setupSignals()
  61. {
  62. connect(mBtnClose, SIGNAL(clicked()), this, SLOT(closeWindow()));
  63. connect(mTimer, SIGNAL(timeout()), this, SLOT(timerUpdate()));
  64. }
  65. void QtEditorWindow::retranslateUi(QString title)
  66. {
  67. mLblTitle->setText(title);
  68. mBtnClose->setText(tr("Close"));
  69. }
  70. void QtEditorWindow::setObjectNames()
  71. {
  72. mTitleBar->setObjectName(QStringLiteral("TitleBar"));
  73. mLblTitle->setObjectName(QStringLiteral("LblTitle"));
  74. mBtnClose->setObjectName(QStringLiteral("BtnClose"));
  75. mCentralWidget->setObjectName(QStringLiteral("CentralWidget"));
  76. mContentWidget->setObjectName(QStringLiteral("ContentWidget"));
  77. }
  78. QSizePolicy QtEditorWindow::sizePolicy() const
  79. {
  80. return QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  81. }
  82. void QtEditorWindow::undock()
  83. {
  84. if(mIsDocked)
  85. {
  86. setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
  87. mIsDocked = false;
  88. }
  89. }
  90. void QtEditorWindow::dock()
  91. {
  92. if(!mIsDocked)
  93. {
  94. setWindowFlags(Qt::Widget);
  95. mIsDocked = true;
  96. }
  97. }
  98. WindowLayoutDesc QtEditorWindow::getLayoutDesc() const
  99. {
  100. WindowLayoutDesc desc;
  101. desc.width = geometry().width();
  102. desc.height = geometry().height();
  103. desc.left = geometry().x();
  104. desc.top = geometry().y();
  105. desc.screenIdx = -1;
  106. desc.name = getName();
  107. desc.maximized = false;
  108. desc.dockState = WDS_FLOATING;
  109. if(isDocked())
  110. {
  111. WindowDragDropLocation dockLocation = gWindowDockManager().getDockLocation(this);
  112. switch(dockLocation)
  113. {
  114. case CM_WINDROP_LEFT:
  115. desc.dockState = WDS_LEFT;
  116. break;
  117. case CM_WINDROP_RIGHT:
  118. desc.dockState = WDS_RIGHT;
  119. break;
  120. case CM_WINDROP_BOTTOM:
  121. desc.dockState = WDS_BOTTOM;
  122. break;
  123. case CM_WINDROP_TOP:
  124. desc.dockState = WDS_TOP;
  125. break;
  126. case CM_WINDROP_CENTER:
  127. desc.dockState = WDS_CENTER;
  128. break;
  129. default:
  130. assert(false);
  131. }
  132. desc.dockParentName = gWindowDockManager().getDockParentName(this);
  133. }
  134. else
  135. {
  136. desc.dockState = WDS_FLOATING;
  137. desc.dockParentName = "";
  138. }
  139. return desc;
  140. }
  141. void QtEditorWindow::restoreFromLayoutDesc(const WindowLayoutDesc& desc)
  142. {
  143. setGeometry(desc.left, desc.top, desc.width, desc.height);
  144. if(desc.dockState != WDS_FLOATING)
  145. {
  146. WindowDragDropLocation dockLocation = CM_WINDROP_NONE;
  147. switch(desc.dockState)
  148. {
  149. case WDS_LEFT:
  150. dockLocation = CM_WINDROP_LEFT;
  151. break;
  152. case WDS_RIGHT:
  153. dockLocation = CM_WINDROP_RIGHT;
  154. break;
  155. case WDS_BOTTOM:
  156. dockLocation = CM_WINDROP_BOTTOM;
  157. break;
  158. case WDS_TOP:
  159. dockLocation = CM_WINDROP_TOP;
  160. break;
  161. case WDS_CENTER:
  162. dockLocation = CM_WINDROP_CENTER;
  163. break;
  164. }
  165. QtEditorWindow* dockParent = nullptr;
  166. if(gWindowDockManager().getRootDockNodeName() != desc.dockParentName)
  167. dockParent = gEditorWindowManager().getOpenWindow(desc.dockParentName);
  168. gWindowDockManager().dockWindow(this, dockParent, dockLocation);
  169. }
  170. }
  171. void QtEditorWindow::enterEvent(QEvent *e)
  172. {
  173. mTimer->start(100);
  174. }
  175. void QtEditorWindow::leaveEvent(QEvent *e)
  176. {
  177. mTimer->stop();
  178. }
  179. void QtEditorWindow::mousePressEvent(QMouseEvent* event)
  180. {
  181. if(event->buttons() & Qt::LeftButton)
  182. {
  183. if(isOverResizeArea(event->globalPos()))
  184. {
  185. //setUpdatesEnabled(false);
  186. mResizeMode = getResizeMode(event->globalPos());
  187. }
  188. else if(isOverDragArea(event->globalPos()))
  189. {
  190. mMoveMode = true;
  191. QPoint globalTopLeft = mapToGlobal(QPoint(0, 0));
  192. mDragOffset = QPoint(globalTopLeft.x() - event->globalPos().x(), globalTopLeft.y() - event->globalPos().y());
  193. }
  194. event->accept();
  195. }
  196. QWidget::mousePressEvent(event);
  197. }
  198. void QtEditorWindow::mouseReleaseEvent(QMouseEvent* event)
  199. {
  200. if(mMoveMode)
  201. {
  202. gWindowDockManager().windowReleased(this, event->globalPos());
  203. }
  204. mMoveMode = false;
  205. mResizeMode = RM_NONE;
  206. //setUpdatesEnabled(true);
  207. QWidget::mouseReleaseEvent(event);
  208. }
  209. void QtEditorWindow::mouseMoveEvent(QMouseEvent* event)
  210. {
  211. if(mMoveMode)
  212. {
  213. QPoint globalPos = mapToGlobal(event->pos());
  214. gWindowDockManager().windowDragged(this, globalPos);
  215. if(!mIsDocked)
  216. move(event->globalPos() + mDragOffset);
  217. event->accept();
  218. }
  219. else if(mResizeMode != RM_NONE)
  220. {
  221. if(!isDocked())
  222. {
  223. int left = geometry().left();
  224. int width = geometry().width();
  225. int top = geometry().top();
  226. int height = geometry().height();
  227. int leftOld = left;
  228. int topOld = top;
  229. if (mResizeMode & RM_LEFT)
  230. {
  231. width = width + (left - event->globalPos().x());
  232. left = event->globalPos().x();
  233. }
  234. if(mResizeMode & RM_RIGHT)
  235. {
  236. width = event->globalPos().x() - left;
  237. }
  238. if(mResizeMode & RM_TOP)
  239. {
  240. height = height + (top - event->globalPos().y());
  241. top = event->globalPos().y();
  242. }
  243. if(mResizeMode & RM_BOTTOM)
  244. {
  245. height = event->globalPos().y() - top;
  246. }
  247. // Check if we have reached width or height limit. We need to do some special
  248. // steps otherwise the window will move (instead of resize) after the limit is reached
  249. if(width < minimumWidth())
  250. {
  251. left = leftOld;
  252. width = minimumWidth();
  253. }
  254. if(height < minimumHeight())
  255. {
  256. top = topOld;
  257. height = minimumHeight();
  258. }
  259. setGeometry(left, top, width, height);
  260. update();
  261. }
  262. }
  263. QWidget::mouseMoveEvent(event);
  264. }
  265. void QtEditorWindow::timerUpdate()
  266. {
  267. if(!isDocked())
  268. {
  269. if(underMouse())
  270. {
  271. ResizeMode resizeMode = getResizeMode(QCursor::pos());
  272. switch(resizeMode)
  273. {
  274. case RM_LEFT:
  275. setCursor(Qt::SizeHorCursor);
  276. break;
  277. case RM_RIGHT:
  278. setCursor(Qt::SizeHorCursor);
  279. break;
  280. case RM_TOP:
  281. setCursor(Qt::SizeVerCursor);
  282. break;
  283. case RM_BOTTOM:
  284. setCursor(Qt::SizeVerCursor);
  285. break;
  286. case (ResizeMode)(RM_BOTTOM | RM_RIGHT):
  287. setCursor(Qt::SizeFDiagCursor);
  288. break;
  289. case (ResizeMode)(RM_TOP | RM_LEFT):
  290. setCursor(Qt::SizeFDiagCursor);
  291. break;
  292. case (ResizeMode)(RM_BOTTOM | RM_LEFT):
  293. setCursor(Qt::SizeBDiagCursor);
  294. break;
  295. case (ResizeMode)(RM_TOP | RM_RIGHT):
  296. setCursor(Qt::SizeBDiagCursor);
  297. break;
  298. case RM_NONE:
  299. setCursor(Qt::ArrowCursor);
  300. break;
  301. }
  302. }
  303. else
  304. {
  305. if(cursor().shape() != Qt::ArrowCursor)
  306. unsetCursor();
  307. }
  308. }
  309. }
  310. void QtEditorWindow::closeWindow()
  311. {
  312. gWindowDockManager().windowClosed(this); // TODO - Hook this up to use onClosed signal as well
  313. onClosed(this);
  314. close();
  315. }
  316. QtEditorWindow::ResizeMode QtEditorWindow::getResizeMode(QPoint mousePos)
  317. {
  318. QPoint localMousePos = mapFromGlobal(mousePos);
  319. QPoint topLeft = mapFromParent(geometry().topLeft());
  320. QPoint botRight = mapFromParent(geometry().bottomRight());
  321. int distFromRight = botRight.x() - localMousePos.x();
  322. int distFromLeft = localMousePos.x() - topLeft.x();
  323. int distFromBot = botRight.y() - localMousePos.y();
  324. int distFromTop = localMousePos.y() - topLeft.y();
  325. if(distFromRight <= RESIZE_BORDER_SIZE && distFromRight >= 0 && distFromBot <= RESIZE_BORDER_SIZE && distFromBot >= 0)
  326. return (ResizeMode)(RM_BOTTOM | RM_RIGHT);
  327. if(distFromLeft <= RESIZE_BORDER_SIZE && distFromLeft >= 0 && distFromTop <= RESIZE_BORDER_SIZE && distFromTop >= 0)
  328. return (ResizeMode)(RM_TOP | RM_LEFT);
  329. if(distFromLeft <= RESIZE_BORDER_SIZE && distFromLeft >= 0 && distFromBot <= RESIZE_BORDER_SIZE && distFromBot >= 0)
  330. return (ResizeMode)(RM_BOTTOM | RM_LEFT);
  331. if(distFromRight <= RESIZE_BORDER_SIZE && distFromRight >= 0 && distFromTop <= RESIZE_BORDER_SIZE && distFromTop >= 0)
  332. return (ResizeMode)(RM_TOP | RM_RIGHT);
  333. if(distFromRight <= RESIZE_BORDER_SIZE && distFromRight >= 0)
  334. return RM_RIGHT;
  335. if(distFromLeft <= RESIZE_BORDER_SIZE && distFromLeft >= 0)
  336. return RM_LEFT;
  337. if(distFromBot <= RESIZE_BORDER_SIZE && distFromBot >= 0)
  338. return RM_BOTTOM;
  339. if(distFromTop <= RESIZE_BORDER_SIZE && distFromTop >= 0)
  340. return RM_TOP;
  341. return RM_NONE;
  342. }
  343. bool QtEditorWindow::isOverResizeArea(QPoint mousePos)
  344. {
  345. QPoint localMousePos = mapFromGlobal(mousePos);
  346. int distFromRight = geometry().width() - localMousePos.x();
  347. int distFromLeft = localMousePos.x();
  348. int distFromBot = geometry().height() - localMousePos.y();
  349. int distFromTop = localMousePos.y();
  350. if(distFromRight <= RESIZE_BORDER_SIZE && distFromRight >= 0)
  351. return true;
  352. if(distFromLeft <= RESIZE_BORDER_SIZE && distFromLeft >= 0)
  353. return true;
  354. if(distFromBot <= RESIZE_BORDER_SIZE && distFromBot >= 0)
  355. return true;
  356. if(distFromTop <= RESIZE_BORDER_SIZE && distFromTop >= 0)
  357. return true;
  358. return false;
  359. }
  360. bool QtEditorWindow::isOverDragArea(QPoint mousePos)
  361. {
  362. if(getResizeMode(mousePos) != RM_NONE)
  363. return false;
  364. QPoint localMousePos = mapFromGlobal(mousePos);
  365. int distFromTop = localMousePos.y();
  366. if(distFromTop <= TITLE_BAR_HEIGHT)
  367. return true;
  368. return false;
  369. }
  370. }