// ================================================================================ // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås == // == See tb_core.h for more information. == // ================================================================================ #include "tb_widgets_listener.h" #include "tb_popup_window.h" namespace tb { // == TBPopupAlignment ====================================================================================== TBRect TBPopupAlignment::GetAlignedRect(TBWidget *popup, TBWidget *target) const { TBWidget *root = target->GetParentRoot(); SizeConstraints sc(root->GetRect().w, root->GetRect().h); PreferredSize ps = popup->GetPreferredSize(sc); // Amount of pixels that should be avoided if the target rect needs to be moved. int avoid_w = 0, avoid_h = 0; int x = 0, y = 0; int w = MIN(ps.pref_w, root->GetRect().w); int h = MIN(ps.pref_h, root->GetRect().h); if (pos_in_root.x != UNSPECIFIED && pos_in_root.y != UNSPECIFIED) { x = pos_in_root.x; y = pos_in_root.y; avoid_w = pos_offset.x; avoid_h = pos_offset.y; // Make sure it's moved into view horizontally if (align == TB_ALIGN_TOP || align == TB_ALIGN_BOTTOM) x = Clamp(x, 0, root->GetRect().w - w); } else { target->ConvertToRoot(x, y); if (align == TB_ALIGN_TOP || align == TB_ALIGN_BOTTOM) { if (expand_to_target_width) w = MAX(w, target->GetRect().w); // If the menu is aligned top or bottom, limit its height to the worst case available height. // Being in the center of the root, that is half the root height minus the target rect. h = MIN(h, root->GetRect().h / 2 - target->GetRect().h); } avoid_w = target->GetRect().w; avoid_h = target->GetRect().h; } if (align == TB_ALIGN_BOTTOM) y = y + avoid_h + h > root->GetRect().h ? y - h : y + avoid_h; else if (align == TB_ALIGN_TOP) y = y - h < 0 ? y + avoid_h : y - h; else if (align == TB_ALIGN_RIGHT) { x = x + avoid_w + w > root->GetRect().w ? x - w : x + avoid_w; y = MIN(y, root->GetRect().h - h); } else // if (align == TB_ALIGN_LEFT) { x = x - w < 0 ? x + avoid_w : x - w; y = MIN(y, root->GetRect().h - h); } return TBRect(x, y, w, h); } // == TBPopupWindow ========================================================================================= TBPopupWindow::TBPopupWindow(TBWidget *target) : m_target(target) { TBWidgetListener::AddGlobalListener(this); SetSkinBg(TBIDC("TBPopupWindow"), WIDGET_INVOKE_INFO_NO_CALLBACKS); SetSettings(WINDOW_SETTINGS_NONE); } TBPopupWindow::~TBPopupWindow() { TBWidgetListener::RemoveGlobalListener(this); } bool TBPopupWindow::Show(const TBPopupAlignment &alignment) { // Calculate and set a good size for the popup window SetRect(alignment.GetAlignedRect(this, m_target.Get())); TBWidget *root = m_target.Get()->GetParentRoot(); root->AddChild(this); return true; } bool TBPopupWindow::OnEvent(const TBWidgetEvent &ev) { if (ev.type == EVENT_TYPE_KEY_DOWN && ev.special_key == TB_KEY_ESC) { Close(); return true; } return TBWindow::OnEvent(ev); } void TBPopupWindow::OnWidgetFocusChanged(TBWidget *widget, bool focused) { if (focused && !IsEventDestinationFor(widget)) Close(); } bool TBPopupWindow::OnWidgetInvokeEvent(TBWidget *widget, const TBWidgetEvent &ev) { if (ev.type == EVENT_TYPE_RIGHT_POINTER_DOWN) Close(); if ((ev.type == EVENT_TYPE_POINTER_DOWN || ev.type == EVENT_TYPE_CONTEXT_MENU) && !IsEventDestinationFor(ev.target)) Close(); return false; } void TBPopupWindow::OnWidgetDelete(TBWidget *widget) { // If the target widget is deleted, close! if (!m_target.Get()) Close(); } bool TBPopupWindow::OnWidgetDying(TBWidget *widget) { // If the target widget or an ancestor of it is dying, close! if (widget == m_target.Get() || widget->IsAncestorOf(m_target.Get())) Close(); return false; } }; // namespace tb