PageRenderTime 56ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/src/common/Lgi/GMdi.cpp

#
C++ | 681 lines | 587 code | 70 blank | 24 comment | 99 complexity | 0e3574ace3ddb50b4be963d4cef254b5 MD5 | raw file
Possible License(s): LGPL-2.1, Unlicense
  1. #include "Lgi.h"
  2. #include "GMdi.h"
  3. #include <stdio.h>
  4. enum GMdiDrag
  5. {
  6. DragNone = 0,
  7. DragMove = 0x01,
  8. DragLeft = 0x02,
  9. DragTop = 0x04,
  10. DragRight = 0x08,
  11. DragBottom = 0x10,
  12. DragClose = 0x20,
  13. DragSystem = 0x40
  14. };
  15. class GMdiChildPrivate
  16. {
  17. public:
  18. GMdiChild *Child;
  19. GRect Title;
  20. GRect Close;
  21. GRect System;
  22. int Fy;
  23. GMdiDrag Drag;
  24. int Ox, Oy;
  25. bool CloseDown;
  26. bool CloseOnUp;
  27. GMdiChildPrivate(GMdiChild *c)
  28. {
  29. CloseOnUp = false;
  30. Child = c;
  31. CloseDown = false;
  32. Fy = SysFont->GetHeight() + 1;
  33. Title.ZOff(-1, -1);
  34. Close.ZOff(-1, -1);
  35. System.ZOff(-1, -1);
  36. }
  37. GMdiDrag HitTest(GMouse &m)
  38. {
  39. GMdiDrag Hit = DragNone;
  40. if (Child->WindowFromPoint(m.x, m.y) == Child)
  41. {
  42. if (!Child->GetClient().Overlap(m.x, m.y))
  43. {
  44. if (System.Overlap(m.x, m.y))
  45. {
  46. Hit = DragSystem;
  47. }
  48. else if (Close.Overlap(m.x, m.y))
  49. {
  50. Hit = DragClose;
  51. }
  52. else if (Title.Overlap(m.x, m.y))
  53. {
  54. Hit = DragMove;
  55. }
  56. else
  57. {
  58. GRect c = Child->GLayout::GetClient();
  59. int Corner = 24;
  60. if (m.x < c.x1 + Corner)
  61. {
  62. (int&)Hit |= DragLeft;
  63. }
  64. if (m.x > c.x2 - Corner)
  65. {
  66. (int&)Hit |= DragRight;
  67. }
  68. if (m.y < c.y1 + Corner)
  69. {
  70. (int&)Hit |= DragTop;
  71. }
  72. if (m.y > c.y2 - Corner)
  73. {
  74. (int&)Hit |= DragBottom;
  75. }
  76. }
  77. }
  78. }
  79. return Hit;
  80. }
  81. };
  82. GMdiChild::GMdiChild()
  83. {
  84. #ifdef BEOS
  85. DeleteObj(_View);
  86. #endif
  87. d = new GMdiChildPrivate(this);
  88. GdcPt2 m(100, d->Fy + 8);
  89. SetMinimumSize(m);
  90. #ifdef WIN32
  91. SetStyle(GetStyle() | WS_CLIPSIBLINGS);
  92. #endif
  93. }
  94. GMdiChild::~GMdiChild()
  95. {
  96. DeleteObj(d);
  97. }
  98. bool GMdiChild::Attach(GViewI *p)
  99. {
  100. #ifdef BEOS
  101. bool s = true;
  102. GFlags::Visible(true);
  103. if (!p->Children.HasItem(this))
  104. {
  105. p->Children.Insert(this);
  106. }
  107. SetParent(p);
  108. Invalidate();
  109. #else
  110. bool s = GLayout::Attach(p);
  111. #endif
  112. if (s) AttachChildren();
  113. return s;
  114. }
  115. char *GMdiChild::Name()
  116. {
  117. return GView::Name();
  118. }
  119. bool GMdiChild::Name(const char *n)
  120. {
  121. bool s = GView::Name(n);
  122. Invalidate((GRect*)0, false, true);
  123. return s;
  124. }
  125. GRect &GMdiChild::GetClient(bool ClientSpace)
  126. {
  127. static GRect r;
  128. r = GLayout::GetClient(ClientSpace);
  129. r.Size(3, 3);
  130. r.y1 += d->Fy + 2;
  131. r.Size(1, 1);
  132. return r;
  133. }
  134. bool GMdiChild::Pour()
  135. {
  136. GRect c = GetClient();
  137. GRegion Client(c);
  138. GRegion Update;
  139. for (GViewI *w = Children.First(); w; w = Children.Next())
  140. {
  141. GRect OldPos = w->GetPos();
  142. Update.Union(&OldPos);
  143. if (w->Pour(Client))
  144. {
  145. GRect p = w->GetPos();
  146. if (!w->Visible())
  147. {
  148. w->Visible(true);
  149. }
  150. // w->Invalidate();
  151. Client.Subtract(&w->GetPos());
  152. Update.Subtract(&w->GetPos());
  153. }
  154. else
  155. {
  156. // non-pourable
  157. }
  158. }
  159. return true;
  160. }
  161. void GMdiChild::OnPaint(GSurface *pDC)
  162. {
  163. GRect p = GLayout::GetClient();
  164. // Border
  165. LgiWideBorder(pDC, p, RAISED);
  166. pDC->Colour(LC_MED, 24);
  167. pDC->Box(&p);
  168. p.Size(1, 1);
  169. // Title bar
  170. char *n = Name();
  171. if (!n) n = "";
  172. d->Title.ZOff(p.X()-1, d->Fy + 1);
  173. d->Title.Offset(p.x1, p.y1);
  174. d->System = d->Title;
  175. d->System.x2 = d->System.x1 + d->System.Y() - 1;
  176. // Title text
  177. bool Top = false;
  178. if (GetParent())
  179. {
  180. GViewIterator *it = GetParent()->IterateViews();
  181. Top = it->Last() == (GViewI*)this;
  182. DeleteObj(it);
  183. }
  184. SysFont->Colour(Top ? LC_ACTIVE_TITLE_TEXT : LC_INACTIVE_TITLE_TEXT, Top ? LC_ACTIVE_TITLE : LC_INACTIVE_TITLE);
  185. SysFont->Transparent(false);
  186. GDisplayString ds(SysFont, n);
  187. ds.Draw(pDC, d->System.x2 + 1, d->Title.y1 + 1, &d->Title);
  188. // System button
  189. GRect r = d->System;
  190. r.Size(2, 1);
  191. pDC->Colour(LC_BLACK, 24);
  192. pDC->Box(&r);
  193. r.Size(1, 1);
  194. pDC->Colour(LC_WHITE, 24);
  195. pDC->Rectangle(&r);
  196. pDC->Colour(LC_BLACK, 24);
  197. for (int k=r.y1 + 1; k < r.y2 - 1; k += 2)
  198. {
  199. pDC->Line(r.x1 + 1, k, r.x2 - 1, k);
  200. }
  201. // Close button
  202. d->Close = d->Title;
  203. d->Close.x1 = d->Close.x2 - d->Close.Y() + 1;
  204. d->Close.Size(2, 2);
  205. r = d->Close;
  206. LgiWideBorder(pDC, r, d->CloseDown ? SUNKEN : RAISED);
  207. pDC->Colour(LC_MED, 24);
  208. pDC->Rectangle(&r);
  209. int Cx = d->Close.x1 + (d->Close.X() >> 1) - 1 + d->CloseDown;
  210. int Cy = d->Close.y1 + (d->Close.Y() >> 1) - 1 + d->CloseDown;
  211. int s = 3;
  212. pDC->Colour(Rgb24(108,108,108), 24);
  213. pDC->Line(Cx-s, Cy-s+1, Cx+s-1, Cy+s);
  214. pDC->Line(Cx-s+1, Cy-s, Cx+s, Cy+s-1);
  215. pDC->Line(Cx-s, Cy+s-1, Cx+s-1, Cy-s);
  216. pDC->Line(Cx-s+1, Cy+s, Cx+s, Cy-s+1);
  217. pDC->Colour(LC_BLACK, 24);
  218. pDC->Line(Cx-s, Cy-s, Cx+s, Cy+s);
  219. pDC->Line(Cx-s, Cy+s, Cx+s, Cy-s);
  220. // Client
  221. GRect Client = GetClient();
  222. Client.Size(-1, -1);
  223. pDC->Colour(LC_MED, 24);
  224. pDC->Box(&Client);
  225. if (!Children.First())
  226. {
  227. Client.Size(1, 1);
  228. pDC->Colour(LC_WORKSPACE, 24);
  229. pDC->Rectangle(&Client);
  230. }
  231. Pour();
  232. }
  233. void GMdiChild::OnMouseClick(GMouse &m)
  234. {
  235. if (m.Left())
  236. {
  237. Raise();
  238. if (m.Down())
  239. {
  240. GRect c = GLayout::GetClient();
  241. d->Drag = DragNone;
  242. d->Ox = d->Oy = -1;
  243. d->Drag = d->HitTest(m);
  244. if (d->Drag)
  245. {
  246. Capture(true);
  247. }
  248. if (d->Drag == DragSystem)
  249. {
  250. if (m.Double())
  251. {
  252. d->CloseOnUp = true;
  253. }
  254. else
  255. {
  256. /*
  257. GdcPt2 p(d->System.x1, d->System.y2+1);
  258. PointToScreen(p);
  259. GSubMenu *Sub = new GSubMenu;
  260. if (Sub)
  261. {
  262. Sub->AppendItem("Close", 1, true);
  263. Close = Sub->Float(this, p.x, p.y, true) == 1;
  264. DeleteObj(Sub);
  265. }
  266. */
  267. }
  268. }
  269. else if (d->Drag == DragClose)
  270. {
  271. d->CloseDown = true;
  272. Invalidate(&d->Close);
  273. }
  274. else if (d->Drag == DragMove)
  275. {
  276. d->Ox = m.x - c.x1;
  277. d->Oy = m.y - c.y1;
  278. }
  279. else
  280. {
  281. if (d->Drag & DragLeft)
  282. {
  283. d->Ox = m.x - c.x1;
  284. }
  285. if (d->Drag & DragRight)
  286. {
  287. d->Ox = m.x - c.x2;
  288. }
  289. if (d->Drag & DragTop)
  290. {
  291. d->Oy = m.y - c.y1;
  292. }
  293. if (d->Drag & DragBottom)
  294. {
  295. d->Oy = m.y - c.y2;
  296. }
  297. }
  298. }
  299. else
  300. {
  301. if (IsCapturing())
  302. {
  303. Capture(false);
  304. }
  305. if (d->CloseOnUp)
  306. {
  307. d->Drag = DragNone;
  308. if (OnRequestClose(false))
  309. {
  310. Quit();
  311. return;
  312. }
  313. }
  314. else if (d->Drag == DragClose)
  315. {
  316. if (d->Close.Overlap(m.x, m.y))
  317. {
  318. d->Drag = DragNone;
  319. d->CloseDown = false;
  320. Invalidate(&d->Close);
  321. if (OnRequestClose(false))
  322. {
  323. Quit();
  324. return;
  325. }
  326. }
  327. else printf("%s:%i - Outside close btn.\n", _FL);
  328. }
  329. else
  330. {
  331. d->Drag = DragNone;
  332. }
  333. }
  334. }
  335. }
  336. void GMdiChild::OnMouseMove(GMouse &m)
  337. {
  338. if (IsCapturing())
  339. {
  340. GRect p = GetPos();
  341. GdcPt2 Min = GetMinimumSize();
  342. if (d->Drag == DragClose)
  343. {
  344. bool Over = d->Close.Overlap(m.x, m.y);
  345. if (Over ^ d->CloseDown)
  346. {
  347. d->CloseDown = Over;
  348. Invalidate(&d->Close);
  349. }
  350. }
  351. else
  352. {
  353. GetMouse(m, true);
  354. GdcPt2 n(m.x, m.y);
  355. GetParent()->PointToView(n);
  356. if (d->Drag == DragMove)
  357. {
  358. p.Offset(n.x - d->Ox - p.x1, n.y - d->Oy - p.y1);
  359. if (p.x1 < 0) p.Offset(-p.x1, 0);
  360. if (p.y1 < 0) p.Offset(0, -p.y1);
  361. }
  362. else
  363. {
  364. if (d->Drag & DragLeft)
  365. {
  366. p.x1 = min(p.x2 - Min.x, n.x - d->Ox);
  367. if (p.x1 < 0) p.x1 = 0;
  368. }
  369. if (d->Drag & DragRight)
  370. {
  371. p.x2 = max(p.x1 + Min.x, n.x - d->Ox);
  372. }
  373. if (d->Drag & DragTop)
  374. {
  375. p.y1 = min(p.y2 - Min.y, n.y - d->Oy);
  376. if (p.y1 < 0) p.y1 = 0;
  377. }
  378. if (d->Drag & DragBottom)
  379. {
  380. p.y2 = max(p.y1 + Min.y, n.y - d->Oy);
  381. }
  382. }
  383. }
  384. SetPos(p);
  385. }
  386. else
  387. {
  388. GMdiDrag Hit = d->HitTest(m);
  389. if (Hit & DragLeft)
  390. {
  391. if (Hit & DragTop)
  392. {
  393. SetCursor(LCUR_SizeFDiag);
  394. }
  395. else if (Hit & DragBottom)
  396. {
  397. SetCursor(LCUR_SizeBDiag);
  398. }
  399. else
  400. {
  401. SetCursor(LCUR_SizeHor);
  402. }
  403. }
  404. else if (Hit & DragRight)
  405. {
  406. if (Hit & DragTop)
  407. {
  408. SetCursor(LCUR_SizeBDiag);
  409. }
  410. else if (Hit & DragBottom)
  411. {
  412. SetCursor(LCUR_SizeFDiag);
  413. }
  414. else
  415. {
  416. SetCursor(LCUR_SizeHor);
  417. }
  418. }
  419. else if ((Hit & DragTop) OR (Hit & DragBottom))
  420. {
  421. SetCursor(LCUR_SizeVer);
  422. }
  423. else
  424. {
  425. SetCursor(LCUR_Normal);
  426. }
  427. }
  428. }
  429. void GMdiChild::Raise()
  430. {
  431. GViewI *p = GetParent();
  432. if (p)
  433. {
  434. #if defined LINUX
  435. // uint32_t v = XCB_STACK_MODE_ABOVE;
  436. // XcbCheck(xcb_configure_window_checked(XcbConn(), Handle(), XCB_CONFIG_WINDOW_STACK_MODE, &v));
  437. #elif defined WIN32
  438. SetWindowPos(Handle(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
  439. #else
  440. #error "Impl me."
  441. #endif
  442. p->DelView(this);
  443. p->AddView(this);
  444. p->OnChildrenChanged(this, true);
  445. }
  446. }
  447. void GMdiChild::Lower()
  448. {
  449. GViewI *p = GetParent();
  450. if (p)
  451. {
  452. #if defined LINUX
  453. // uint32_t v = XCB_STACK_MODE_BELOW;
  454. // XcbCheck(xcb_configure_window_checked(XcbConn(), Handle(), XCB_CONFIG_WINDOW_STACK_MODE, &v));
  455. #elif defined WIN32
  456. SetWindowPos(Handle(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
  457. #else
  458. #error "Impl me."
  459. #endif
  460. p->DelView(this);
  461. p->AddView(this, 0);
  462. p->OnChildrenChanged(this, true);
  463. }
  464. }
  465. GMessage::Result GMdiChild::OnEvent(GMessage *m)
  466. {
  467. return GLayout::OnEvent(m);
  468. }
  469. ///////////////////////////////////////////////////////////////////////////////////////////
  470. class GMdiParentPrivate
  471. {
  472. public:
  473. };
  474. GMdiParent::GMdiParent()
  475. {
  476. d = new GMdiParentPrivate;
  477. SetPourLargest(true);
  478. }
  479. GMdiParent::~GMdiParent()
  480. {
  481. if (GetWindow())
  482. {
  483. GetWindow()->UnregisterHook(this);
  484. }
  485. DeleteObj(d);
  486. }
  487. void GMdiParent::OnPaint(GSurface *pDC)
  488. {
  489. pDC->Colour(LC_LOW, 24);
  490. pDC->Rectangle();
  491. }
  492. bool GMdiParent::Attach(GViewI *p)
  493. {
  494. bool s = GLayout::Attach(p);
  495. if (s)
  496. {
  497. AttachChildren();
  498. GetWindow()->RegisterHook(this, GMouseEvents | GKeyEvents);
  499. }
  500. return s;
  501. }
  502. GMdiChild *GMdiParent::IsChild(GView *View)
  503. {
  504. for (GViewI *v=View; v; v=v->GetParent())
  505. {
  506. if (v->GetParent() == this)
  507. {
  508. GMdiChild *c = dynamic_cast<GMdiChild*>(v);
  509. if (c)
  510. {
  511. return c;
  512. }
  513. LgiAssert(0);
  514. break;
  515. }
  516. }
  517. return 0;
  518. }
  519. bool GMdiParent::OnViewMouse(GView *View, GMouse &m)
  520. {
  521. if (m.Down())
  522. {
  523. GMdiChild *c = IsChild(View);
  524. if (c)
  525. {
  526. c->Raise();
  527. }
  528. }
  529. return true;
  530. }
  531. bool GMdiParent::OnViewKey(GView *View, GKey &Key)
  532. {
  533. if (Key.Down() AND Key.Ctrl() AND Key.c16 == '\t')
  534. {
  535. bool Child = IsChild(View);
  536. if (Child)
  537. {
  538. GView *v;
  539. if (Key.Shift())
  540. {
  541. v = dynamic_cast<GView*>(Children.First());
  542. }
  543. else
  544. {
  545. v = dynamic_cast<GView*>(Children.Last());
  546. }
  547. GMdiChild *c = dynamic_cast<GMdiChild*>(v);
  548. if (c)
  549. {
  550. if (Key.Shift())
  551. {
  552. c->Raise();
  553. }
  554. else
  555. {
  556. c->Lower();
  557. }
  558. return true;
  559. }
  560. }
  561. }
  562. return false;
  563. }
  564. GRect GMdiParent::NewPos()
  565. {
  566. GRect Status(0, 0, X()*0.75, Y()*0.75);
  567. int Block = 5;
  568. for (int y=0; y<Y()>>Block; y++)
  569. {
  570. for (int x=0; x<X()>>Block; x++)
  571. {
  572. bool Has = false;
  573. for (GViewI *c = Children.First(); c; c = Children.Next())
  574. {
  575. GRect p = c->GetPos();
  576. if (p.x1 >> Block == x AND
  577. p.y1 >> Block == y)
  578. {
  579. Has = true;
  580. break;
  581. }
  582. }
  583. if (!Has)
  584. {
  585. Status.Offset(x << Block, y << Block);
  586. return Status;
  587. }
  588. }
  589. }
  590. return Status;
  591. }
  592. void GMdiParent::OnChildrenChanged(GViewI *Wnd, bool Attaching)
  593. {
  594. for (GViewI *v=Children.First(); v; )
  595. {
  596. GMdiChild *c = dynamic_cast<GMdiChild*>(v);
  597. v=Children.Next();
  598. if (c)
  599. {
  600. c->Invalidate(&c->d->Title);
  601. if (!v)
  602. {
  603. GViewI *n = c->Children.First();
  604. if (n)
  605. {
  606. n->Focus(true);
  607. }
  608. }
  609. }
  610. }
  611. }