// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2014 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Marco Trevisan */ #include #include "DecorationsMenuEntry.h" #include "DecorationStyle.h" #include "UnitySettings.h" namespace unity { namespace decoration { using namespace indicator; MenuEntry::MenuEntry(Entry::Ptr const& entry, CompWindow* win) : horizontal_padding(5) , vertical_padding(3) , active(entry->active()) , show_now(entry->show_now()) , in_dropdown(false) , entry_(entry) , grab_(win, true) , show_menu_enabled_(true) { entry_->updated.connect(sigc::mem_fun(this, &MenuEntry::EntryUpdated)); in_dropdown.changed.connect([this] (bool in) { visible = entry_->visible() && !in; }); auto render_texture_cb = sigc::hide(sigc::mem_fun(this, &MenuEntry::RenderTexture)); horizontal_padding.changed.connect(render_texture_cb); vertical_padding.changed.connect(render_texture_cb); scale.changed.connect(render_texture_cb); focused.changed.connect(render_texture_cb); Style::Get()->font.changed.connect(render_texture_cb); EntryUpdated(); } std::string const& MenuEntry::Id() const { return entry_->id(); } void MenuEntry::EntryUpdated() { sensitive = entry_->label_sensitive() || entry_->image_sensitive(); visible = entry_->visible() && !in_dropdown(); active = entry_->active(); show_now = entry_->show_now(); RenderTexture(); } void MenuEntry::RenderTexture() { WidgetState state = focused() ? WidgetState::NORMAL : WidgetState::BACKDROP; if (show_now()) state = WidgetState::PRESSED; if (active()) state = WidgetState::PRELIGHT; natural_ = Style::Get()->MenuItemNaturalSize(entry_->label()); cu::CairoContext text_ctx(GetNaturalWidth(), GetNaturalHeight(), scale()); if (state == WidgetState::PRELIGHT) Style::Get()->DrawMenuItem(state, text_ctx, text_ctx.width() / scale(), text_ctx.height() / scale()); nux::Rect bg_geo(-(horizontal_padding()*scale()), -(vertical_padding()*scale()), GetNaturalWidth(), GetNaturalHeight()); if (state != WidgetState::PRELIGHT) { if (BasicContainer::Ptr const& top = GetTopParent()) { auto const& top_geo = top->Geometry(); auto const& geo = Geometry(); bg_geo.Set(top_geo.x() - geo.x(), top_geo.y() - geo.y(), top_geo.width(), top_geo.height()); } } cairo_save(text_ctx); cairo_translate(text_ctx, horizontal_padding(), vertical_padding()); Style::Get()->DrawMenuItemEntry(entry_->label(), state, text_ctx, natural_.width, natural_.height, bg_geo * (1.0/scale)); cairo_restore(text_ctx); SetTexture(text_ctx); } void MenuEntry::ShowMenu(unsigned button) { if (active) return; active = true; auto const& geo = Geometry(); entry_->ShowMenu(grab_.Window()->id(), geo.x(), geo.y2(), button); } int MenuEntry::GetNaturalWidth() const { return (natural_.width + horizontal_padding() * 2) * scale(); } int MenuEntry::GetNaturalHeight() const { return (natural_.height + vertical_padding() * 2) * scale(); } void MenuEntry::ButtonDownEvent(CompPoint const& p, unsigned button, Time timestamp) { button_up_timer_.reset(); grab_.ButtonDownEvent(p, button, timestamp); show_menu_enabled_ = (focused() || Settings::Instance().lim_unfocused_popup()); } void MenuEntry::ButtonUpEvent(CompPoint const& p, unsigned button, Time timestamp) { if (!show_menu_enabled_) { grab_.ButtonUpEvent(p, button, timestamp); return; } if (button == 1 && !grab_.IsGrabbed()) { unsigned double_click_wait = Settings::Instance().lim_double_click_wait(); if (grab_.IsMaximizable() && double_click_wait > 0) { button_up_timer_.reset(new glib::Timeout(double_click_wait)); button_up_timer_->Run([this, button] { ShowMenu(button); return false; }); } else { ShowMenu(button); } } if (button == 2 || button == 3) { if (Style::Get()->WindowManagerAction(WMEvent(button)) == WMAction::NONE) ShowMenu(button); } grab_.ButtonUpEvent(p, button, timestamp); } void MenuEntry::MotionEvent(CompPoint const& p, Time timestamp) { bool ignore_movement = false; if (!grab_.IsGrabbed()) { if (Geometry().contains(p)) { int move_threshold = Settings::Instance().lim_movement_thresold(); auto const& clicked = grab_.ClickedPoint(); if (std::abs(p.x() - clicked.x()) < move_threshold && std::abs(p.y() - clicked.y()) < move_threshold) { ignore_movement = true; } } } if (!ignore_movement) grab_.MotionEvent(p, timestamp); } indicator::Entry::Ptr const& MenuEntry::GetEntry() const { return entry_; } void MenuEntry::AddProperties(debug::IntrospectionData& data) { TexturedItem::AddProperties(data); data.add("entry_id", Id()) .add("label", entry_->label()) .add("label_visible", entry_->label_visible()) .add("label_sensitive", entry_->label_sensitive()) .add("active", entry_->active()) .add("in_dropdown", in_dropdown()); } debug::Introspectable::IntrospectableList MenuEntry::GetIntrospectableChildren() { return IntrospectableList({&grab_}); } } // decoration namespace } // unity namespace