Index: ash/wm/panel_layout_manager.cc |
diff --git a/ash/wm/panel_layout_manager.cc b/ash/wm/panel_layout_manager.cc |
index 997271d5bc686c06c6caf471a47cc493721f82f9..a1d1154126dd2b45adedd9fe08ebd27589614af8 100644 |
--- a/ash/wm/panel_layout_manager.cc |
+++ b/ash/wm/panel_layout_manager.cc |
@@ -8,16 +8,26 @@ |
#include "ash/launcher/launcher.h" |
#include "ash/shell.h" |
+#include "ash/wm/frame_painter.h" |
#include "ash/wm/property_util.h" |
#include "base/auto_reset.h" |
+#include "base/bind.h" |
+#include "base/bind_helpers.h" |
+#include "third_party/skia/include/core/SkColor.h" |
+#include "third_party/skia/include/core/SkPaint.h" |
+#include "third_party/skia/include/core/SkPath.h" |
#include "ui/aura/client/activation_client.h" |
#include "ui/aura/client/aura_constants.h" |
#include "ui/aura/root_window.h" |
#include "ui/aura/window.h" |
+#include "ui/gfx/canvas.h" |
#include "ui/gfx/rect.h" |
-#include "ui/gfx/size.h" |
+#include "ui/views/background.h" |
#include "ui/views/widget/widget.h" |
+namespace ash { |
+namespace internal { |
+ |
namespace { |
const int kPanelMarginEdge = 4; |
const int kPanelMarginMiddle = 8; |
@@ -26,10 +36,34 @@ const int kMinimizedHeight = 24; |
const float kMaxHeightFactor = .80f; |
const float kMaxWidthFactor = .50f; |
-} |
-namespace ash { |
-namespace internal { |
+// Callout arrow dimensions. |
+const int kArrowWidth = 20; |
+const int kArrowHeight = 10; |
+ |
+class CalloutWidgetBackground : public views::Background { |
+ public: |
+ CalloutWidgetBackground() {} |
+ virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE { |
+ SkPath path; |
+ // TODO(dcheng): Verify if this results in off by one errors. |
+ path.moveTo(SkIntToScalar(0), SkIntToScalar(0)); |
+ path.lineTo(SkIntToScalar(kArrowWidth / 2), SkIntToScalar(kArrowHeight)); |
+ path.lineTo(SkIntToScalar(kArrowWidth), SkIntToScalar(0)); |
+ |
+ // Use the same opacity and colors as the header for now. |
+ SkPaint paint; |
+ paint.setStyle(SkPaint::kFill_Style); |
+ paint.setColor( |
+ SkColorSetARGB(FramePainter::kActiveWindowOpacity, 189, 189, 189)); |
+ canvas->DrawPath(path, paint); |
+ } |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(CalloutWidgetBackground); |
+}; |
+ |
+} // namespace |
//////////////////////////////////////////////////////////////////////////////// |
// PanelLayoutManager public implementation: |
@@ -38,8 +72,25 @@ PanelLayoutManager::PanelLayoutManager(aura::Window* panel_container) |
in_layout_(false), |
dragged_panel_(NULL), |
launcher_(NULL), |
- last_active_panel_(NULL) { |
+ last_active_panel_(NULL), |
+ callout_widget_(new views::Widget), |
+ weak_factory_(this) { |
DCHECK(panel_container); |
+ views::Widget::InitParams params; |
+ params.type = views::Widget::InitParams::TYPE_POPUP; |
+ params.transparent = true; |
+ params.can_activate = false; |
+ params.keep_on_top = true; |
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
+ params.parent = panel_container_; |
+ params.bounds.set_width(kArrowWidth); |
+ params.bounds.set_height(kArrowHeight); |
+ // Why do we need this and can_activate = false? |
+ callout_widget_->set_focus_on_creation(false); |
+ callout_widget_->Init(params); |
+ views::View* content_view = new views::View; |
+ content_view->set_background(new CalloutWidgetBackground); |
+ callout_widget_->SetContentsView(content_view); |
Shell::GetRootWindow()->AddObserver(this); |
} |
@@ -101,6 +152,8 @@ void PanelLayoutManager::OnWindowResized() { |
} |
void PanelLayoutManager::OnWindowAddedToLayout(aura::Window* child) { |
+ if (child == callout_widget_->GetNativeWindow()) |
+ return; |
panel_windows_.push_back(child); |
Relayout(); |
} |
@@ -175,8 +228,12 @@ void PanelLayoutManager::OnWindowPropertyChanged(aura::Window* window, |
if (key == aura::client::kRootWindowActiveWindowKey) { |
aura::Window* active = window->GetProperty( |
aura::client::kRootWindowActiveWindowKey); |
- if (active && active->type() == aura::client::WINDOW_TYPE_PANEL) |
+ if (active && active->type() == aura::client::WINDOW_TYPE_PANEL) { |
UpdateStacking(active); |
+ UpdateCallout(active); |
+ } else { |
+ UpdateCallout(NULL); |
+ } |
} |
} |
@@ -188,6 +245,7 @@ void PanelLayoutManager::Relayout() { |
return; |
AutoReset<bool> auto_reset_in_layout(&in_layout_, true); |
+ int launcher_top = launcher_->widget()->GetWindowScreenBounds().y(); |
aura::Window* active_panel = NULL; |
for (PanelList::iterator iter = panel_windows_.begin(); |
iter != panel_windows_.end(); ++iter) { |
@@ -218,11 +276,12 @@ void PanelLayoutManager::Relayout() { |
gfx::Rect bounds = panel->bounds(); |
bounds.set_x( |
icon_origin.x() + icon_bounds.width() / 2 - bounds.width() / 2); |
- bounds.set_y(icon_origin.y() - bounds.height()); |
+ bounds.set_y(launcher_top - bounds.height()); |
SetChildBoundsDirect(panel, bounds); |
} |
UpdateStacking(active_panel); |
+ UpdateCallout(active_panel); |
} |
void PanelLayoutManager::UpdateStacking(aura::Window* active_panel) { |
@@ -271,5 +330,33 @@ void PanelLayoutManager::UpdateStacking(aura::Window* active_panel) { |
last_active_panel_ = active_panel; |
} |
+void PanelLayoutManager::UpdateCallout(aura::Window* active_panel) { |
+ weak_factory_.InvalidateWeakPtrs(); |
+ // TODO(dcheng): This doesn't account for panels in overflow. They should have |
+ // a callout as well. |
+ if (!active_panel || |
+ launcher_->GetScreenBoundsOfItemIconForWindow(active_panel).IsEmpty()) { |
+ callout_widget_->Hide(); |
+ return; |
+ } |
+ MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&PanelLayoutManager::ShowCalloutHelper, |
+ weak_factory_.GetWeakPtr(), |
+ active_panel)); |
+} |
+ |
+void PanelLayoutManager::ShowCalloutHelper(aura::Window* active_panel) { |
+ DCHECK(active_panel); |
+ gfx::Rect bounds = active_panel->GetBoundsInRootWindow(); |
+ gfx::Rect callout_bounds = callout_widget_->GetWindowScreenBounds(); |
+ callout_bounds.set_x( |
+ bounds.x() + (bounds.width() - callout_bounds.width()) / 2); |
+ callout_bounds.set_y(bounds.bottom()); |
+ SetChildBoundsDirect(callout_widget_->GetNativeWindow(), callout_bounds); |
+ panel_container_->StackChildAtTop(callout_widget_->GetNativeWindow()); |
+ callout_widget_->Show(); |
+} |
+ |
} // namespace internal |
} // namespace ash |