tb_popup_window.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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_widgets_listener.h"
  6. #include "tb_popup_window.h"
  7. namespace tb {
  8. // == TBPopupAlignment ======================================================================================
  9. TBRect TBPopupAlignment::GetAlignedRect(TBWidget *popup, TBWidget *target) const
  10. {
  11. TBWidget *root = target->GetParentRoot();
  12. SizeConstraints sc(root->GetRect().w, root->GetRect().h);
  13. PreferredSize ps = popup->GetPreferredSize(sc);
  14. // Amount of pixels that should be avoided if the target rect needs to be moved.
  15. int avoid_w = 0, avoid_h = 0;
  16. int x = 0, y = 0;
  17. int w = MIN(ps.pref_w, root->GetRect().w);
  18. int h = MIN(ps.pref_h, root->GetRect().h);
  19. if (pos_in_root.x != UNSPECIFIED &&
  20. pos_in_root.y != UNSPECIFIED)
  21. {
  22. x = pos_in_root.x;
  23. y = pos_in_root.y;
  24. avoid_w = pos_offset.x;
  25. avoid_h = pos_offset.y;
  26. // Make sure it's moved into view horizontally
  27. if (align == TB_ALIGN_TOP || align == TB_ALIGN_BOTTOM)
  28. x = Clamp(x, 0, root->GetRect().w - w);
  29. }
  30. else
  31. {
  32. target->ConvertToRoot(x, y);
  33. if (align == TB_ALIGN_TOP || align == TB_ALIGN_BOTTOM)
  34. {
  35. if (expand_to_target_width)
  36. w = MAX(w, target->GetRect().w);
  37. // If the menu is aligned top or bottom, limit its height to the worst case available height.
  38. // Being in the center of the root, that is half the root height minus the target rect.
  39. h = MIN(h, root->GetRect().h / 2 - target->GetRect().h);
  40. }
  41. avoid_w = target->GetRect().w;
  42. avoid_h = target->GetRect().h;
  43. }
  44. if (align == TB_ALIGN_BOTTOM)
  45. y = y + avoid_h + h > root->GetRect().h ? y - h : y + avoid_h;
  46. else if (align == TB_ALIGN_TOP)
  47. y = y - h < 0 ? y + avoid_h : y - h;
  48. else if (align == TB_ALIGN_RIGHT)
  49. {
  50. x = x + avoid_w + w > root->GetRect().w ? x - w : x + avoid_w;
  51. y = MIN(y, root->GetRect().h - h);
  52. }
  53. else // if (align == TB_ALIGN_LEFT)
  54. {
  55. x = x - w < 0 ? x + avoid_w : x - w;
  56. y = MIN(y, root->GetRect().h - h);
  57. }
  58. return TBRect(x, y, w, h);
  59. }
  60. // == TBPopupWindow =========================================================================================
  61. TBPopupWindow::TBPopupWindow(TBWidget *target)
  62. : m_target(target)
  63. {
  64. TBWidgetListener::AddGlobalListener(this);
  65. SetSkinBg(TBIDC("TBPopupWindow"), WIDGET_INVOKE_INFO_NO_CALLBACKS);
  66. SetSettings(WINDOW_SETTINGS_NONE);
  67. }
  68. TBPopupWindow::~TBPopupWindow()
  69. {
  70. TBWidgetListener::RemoveGlobalListener(this);
  71. }
  72. bool TBPopupWindow::Show(const TBPopupAlignment &alignment)
  73. {
  74. // Calculate and set a good size for the popup window
  75. SetRect(alignment.GetAlignedRect(this, m_target.Get()));
  76. TBWidget *root = m_target.Get()->GetParentRoot();
  77. root->AddChild(this);
  78. return true;
  79. }
  80. bool TBPopupWindow::OnEvent(const TBWidgetEvent &ev)
  81. {
  82. if (ev.type == EVENT_TYPE_KEY_DOWN && ev.special_key == TB_KEY_ESC)
  83. {
  84. Close();
  85. return true;
  86. }
  87. return TBWindow::OnEvent(ev);
  88. }
  89. void TBPopupWindow::OnWidgetFocusChanged(TBWidget *widget, bool focused)
  90. {
  91. if (focused && !IsEventDestinationFor(widget))
  92. Close();
  93. }
  94. bool TBPopupWindow::OnWidgetInvokeEvent(TBWidget *widget, const TBWidgetEvent &ev)
  95. {
  96. if (ev.type == EVENT_TYPE_RIGHT_POINTER_DOWN)
  97. Close();
  98. if ((ev.type == EVENT_TYPE_POINTER_DOWN || ev.type == EVENT_TYPE_CONTEXT_MENU) &&
  99. !IsEventDestinationFor(ev.target))
  100. Close();
  101. return false;
  102. }
  103. void TBPopupWindow::OnWidgetDelete(TBWidget *widget)
  104. {
  105. // If the target widget is deleted, close!
  106. if (!m_target.Get())
  107. Close();
  108. }
  109. bool TBPopupWindow::OnWidgetDying(TBWidget *widget)
  110. {
  111. // If the target widget or an ancestor of it is dying, close!
  112. if (widget == m_target.Get() || widget->IsAncestorOf(m_target.Get()))
  113. Close();
  114. return false;
  115. }
  116. }; // namespace tb