tb_window.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. // ================================================================================
  2. // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
  3. // == See tb_core.h for more information. ==
  4. // ================================================================================
  5. #include "tb_window.h"
  6. #include <assert.h>
  7. namespace tb {
  8. // == TBWindow ==========================================================================
  9. TBWindow::TBWindow()
  10. : m_settings(WINDOW_SETTINGS_DEFAULT)
  11. {
  12. // ATOMIC BEGIN
  13. m_axis = AXIS_Y;
  14. // ATOMIC END
  15. SetSkinBg(TBIDC("TBWindow"), WIDGET_INVOKE_INFO_NO_CALLBACKS);
  16. AddChild(&m_mover);
  17. AddChild(&m_resizer);
  18. m_mover.SetSkinBg(TBIDC("TBWindow.mover"));
  19. m_mover.AddChild(&m_textfield);
  20. m_textfield.SetIgnoreInput(true);
  21. // ATOMIC BEGIN
  22. m_textfield.SetSqueezable(true);
  23. // ATOMIC END
  24. m_mover.AddChild(&m_close_button);
  25. m_close_button.SetSkinBg(TBIDC("TBWindow.close"));
  26. m_close_button.SetIsFocusable(false);
  27. m_close_button.SetID(TBIDC("TBWindow.close"));
  28. SetIsGroupRoot(true);
  29. }
  30. TBWindow::~TBWindow()
  31. {
  32. if (m_resizer.GetParent()) RemoveChild(&m_resizer);
  33. if (m_mover.GetParent()) RemoveChild(&m_mover);
  34. if (m_close_button.GetParent()) m_mover.RemoveChild(&m_close_button);
  35. m_mover.RemoveChild(&m_textfield);
  36. }
  37. TBRect TBWindow::GetResizeToFitContentRect(RESIZE_FIT fit)
  38. {
  39. PreferredSize ps = GetPreferredSize();
  40. int new_w = ps.pref_w;
  41. int new_h = ps.pref_h;
  42. if (fit == RESIZE_FIT_MINIMAL)
  43. {
  44. new_w = ps.min_w;
  45. new_h = ps.min_h;
  46. }
  47. else if (fit == RESIZE_FIT_CURRENT_OR_NEEDED)
  48. {
  49. new_w = CLAMP(GetRect().w, ps.min_w, ps.max_w);
  50. new_h = CLAMP(GetRect().h, ps.min_h, ps.max_h);
  51. }
  52. if (GetParent())
  53. {
  54. new_w = MIN(new_w, GetParent()->GetRect().w);
  55. new_h = MIN(new_h, GetParent()->GetRect().h);
  56. }
  57. return TBRect(GetRect().x, GetRect().y, new_w, new_h);
  58. }
  59. void TBWindow::ResizeToFitContent(RESIZE_FIT fit)
  60. {
  61. SetRect(GetResizeToFitContentRect(fit));
  62. }
  63. void TBWindow::Close()
  64. {
  65. // ATOMIC BEGIN
  66. TBWidgetListener::InvokeWindowClose(this);
  67. // ATOMIC END
  68. Die();
  69. }
  70. bool TBWindow::IsActive() const
  71. {
  72. return GetState(WIDGET_STATE_SELECTED);
  73. }
  74. TBWindow *TBWindow::GetTopMostOtherWindow(bool only_activable_windows)
  75. {
  76. TBWindow *other_window = nullptr;
  77. TBWidget *sibling = GetParent()->GetLastChild();
  78. while (sibling && !other_window)
  79. {
  80. if (sibling != this)
  81. other_window = TBSafeCast<TBWindow>(sibling);
  82. if (only_activable_windows && other_window && !(other_window->m_settings & WINDOW_SETTINGS_CAN_ACTIVATE))
  83. other_window = nullptr;
  84. sibling = sibling->GetPrev();
  85. }
  86. return other_window;
  87. }
  88. void TBWindow::Activate()
  89. {
  90. if (!GetParent() || !(m_settings & WINDOW_SETTINGS_CAN_ACTIVATE))
  91. return;
  92. if (IsActive())
  93. {
  94. // Already active, but we may still have lost focus,
  95. // so ensure it comes back to us.
  96. EnsureFocus();
  97. return;
  98. }
  99. // Deactivate currently active window
  100. TBWindow *active_window = GetTopMostOtherWindow(true);
  101. if (active_window)
  102. active_window->DeActivate();
  103. // Activate this window
  104. SetZ(WIDGET_Z_TOP);
  105. SetWindowActiveState(true);
  106. EnsureFocus();
  107. }
  108. bool TBWindow::EnsureFocus()
  109. {
  110. // If we already have focus, we're done.
  111. if (focused_widget && IsAncestorOf(focused_widget))
  112. return true;
  113. // Focus last focused widget (if we have one)
  114. bool success = false;
  115. if (m_last_focus.Get())
  116. success = m_last_focus.Get()->SetFocus(WIDGET_FOCUS_REASON_UNKNOWN);
  117. // We didn't have one or failed, so try focus any child.
  118. if (!success)
  119. success = SetFocusRecursive(WIDGET_FOCUS_REASON_UNKNOWN);
  120. return success;
  121. }
  122. void TBWindow::DeActivate()
  123. {
  124. if (!IsActive())
  125. return;
  126. SetWindowActiveState(false);
  127. }
  128. void TBWindow::SetWindowActiveState(bool active)
  129. {
  130. SetState(WIDGET_STATE_SELECTED, active);
  131. m_mover.SetState(WIDGET_STATE_SELECTED, active);
  132. }
  133. void TBWindow::SetSettings(WINDOW_SETTINGS settings)
  134. {
  135. if (settings == m_settings)
  136. return;
  137. m_settings = settings;
  138. if (settings & WINDOW_SETTINGS_TITLEBAR)
  139. {
  140. if (!m_mover.GetParent())
  141. AddChild(&m_mover);
  142. }
  143. else if (!(settings & WINDOW_SETTINGS_TITLEBAR))
  144. {
  145. if (m_mover.GetParent())
  146. RemoveChild(&m_mover);
  147. }
  148. if (settings & WINDOW_SETTINGS_RESIZABLE)
  149. {
  150. if (!m_resizer.GetParent())
  151. AddChild(&m_resizer);
  152. }
  153. else if (!(settings & WINDOW_SETTINGS_RESIZABLE))
  154. {
  155. if (m_resizer.GetParent())
  156. RemoveChild(&m_resizer);
  157. }
  158. if (settings & WINDOW_SETTINGS_CLOSE_BUTTON)
  159. {
  160. if (!m_close_button.GetParent())
  161. m_mover.AddChild(&m_close_button);
  162. }
  163. else if (!(settings & WINDOW_SETTINGS_CLOSE_BUTTON))
  164. {
  165. if (m_close_button.GetParent())
  166. m_mover.RemoveChild(&m_close_button);
  167. }
  168. // FIX: invalidate layout / resize window!
  169. Invalidate();
  170. }
  171. int TBWindow::GetTitleHeight()
  172. {
  173. if (m_settings & WINDOW_SETTINGS_TITLEBAR)
  174. return m_mover.GetPreferredSize().pref_h;
  175. return 0;
  176. }
  177. TBRect TBWindow::GetPaddingRect()
  178. {
  179. TBRect padding_rect = TBWidget::GetPaddingRect();
  180. int title_height = GetTitleHeight();
  181. // ATOMIC BEGIN
  182. if ( m_axis == AXIS_Y ) // default axis
  183. {
  184. // ATOMIC END
  185. padding_rect.y += title_height;
  186. padding_rect.h -= title_height;
  187. // ATOMIC BEGIN
  188. }
  189. else if ( m_axis == AXIS_X ) // rotated sideways
  190. {
  191. padding_rect.x += title_height;
  192. padding_rect.w -= title_height;
  193. }
  194. // ATOMIC END
  195. return padding_rect;
  196. }
  197. PreferredSize TBWindow::OnCalculatePreferredSize(const SizeConstraints &constraints)
  198. {
  199. PreferredSize ps = OnCalculatePreferredContentSize(constraints);
  200. // Add window skin padding
  201. if (TBSkinElement *e = GetSkinBgElement())
  202. {
  203. ps.min_w += e->padding_left + e->padding_right;
  204. ps.pref_w += e->padding_left + e->padding_right;
  205. ps.min_h += e->padding_top + e->padding_bottom;
  206. ps.pref_h += e->padding_top + e->padding_bottom;
  207. }
  208. // Add window title bar height
  209. int title_height = GetTitleHeight();
  210. // ATOMIC BEGIN
  211. if ( m_axis == AXIS_Y ) // default axis
  212. {
  213. // ATOMIC END
  214. ps.min_h += title_height;
  215. ps.pref_h += title_height;
  216. // ATOMIC BEGIN
  217. }
  218. else if ( m_axis == AXIS_X ) // rotated sideways
  219. {
  220. ps.min_w += title_height;
  221. ps.pref_w += title_height;
  222. }
  223. // ATOMIC END
  224. return ps;
  225. }
  226. bool TBWindow::OnEvent(const TBWidgetEvent &ev)
  227. {
  228. if (ev.target == &m_close_button)
  229. {
  230. if (ev.type == EVENT_TYPE_CLICK)
  231. Close();
  232. return true;
  233. }
  234. return TBWidget::OnEvent(ev);
  235. }
  236. void TBWindow::OnAdded()
  237. {
  238. // If we was added last, call Activate to update status etc.
  239. if (GetParent()->GetLastChild() == this)
  240. Activate();
  241. }
  242. void TBWindow::OnRemove()
  243. {
  244. DeActivate();
  245. // Active the top most other window
  246. if (TBWindow *active_window = GetTopMostOtherWindow(true))
  247. active_window->Activate();
  248. }
  249. void TBWindow::OnChildAdded(TBWidget *child)
  250. {
  251. m_resizer.SetZ(WIDGET_Z_TOP);
  252. }
  253. void TBWindow::OnResized(int old_w, int old_h)
  254. {
  255. // Apply gravity on children
  256. TBWidget::OnResized(old_w, old_h);
  257. // Manually move our own decoration children
  258. // FIX: Put a layout in the TBMover so we can add things there nicely.
  259. int title_height = GetTitleHeight();
  260. // ATOMIC BEGIN
  261. if ( m_axis == AXIS_Y ) // default axis
  262. {
  263. // ATOMIC END
  264. m_mover.SetRect(TBRect(0, 0, GetRect().w, title_height));
  265. PreferredSize ps = m_resizer.GetPreferredSize();
  266. m_resizer.SetRect(TBRect(GetRect().w - ps.pref_w, GetRect().h - ps.pref_h, ps.pref_w, ps.pref_h));
  267. TBRect mover_rect = m_mover.GetPaddingRect();
  268. int button_size = mover_rect.h;
  269. m_close_button.SetRect(TBRect(mover_rect.x + mover_rect.w - button_size, mover_rect.y, button_size, button_size));
  270. if (m_settings & WINDOW_SETTINGS_CLOSE_BUTTON)
  271. mover_rect.w -= button_size;
  272. m_textfield.SetRect(mover_rect);
  273. // ATOMIC BEGIN
  274. }
  275. else if ( m_axis == AXIS_X ) // rotated sideways
  276. {
  277. m_mover.SetRect(TBRect(0, 0, title_height, GetRect().h ));
  278. PreferredSize ps = m_resizer.GetPreferredSize();
  279. m_resizer.SetRect(TBRect(GetRect().w - ps.pref_w, GetRect().h - ps.pref_h, ps.pref_w, ps.pref_h));
  280. TBRect mover_rect = m_mover.GetPaddingRect();
  281. int button_size = mover_rect.w;
  282. m_close_button.SetRect(TBRect(mover_rect.x + 1, mover_rect.y + 1, button_size, button_size));
  283. if (m_settings & WINDOW_SETTINGS_CLOSE_BUTTON)
  284. mover_rect.w -= button_size;
  285. m_textfield.SetRect(TBRect(mover_rect.x + 5, mover_rect.y + mover_rect.h - button_size, button_size - 1, button_size));
  286. }
  287. // ATOMIC END
  288. }
  289. // ATOMIC BEGIN
  290. void TBWindow::SetAxis(AXIS axis)
  291. {
  292. m_axis = axis;
  293. Invalidate();
  294. }
  295. // ATOMIC END
  296. }; // namespace tb