1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 #include "base/macros.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "mojo/examples/media_viewer/media_viewer.mojom.h"
12 #include "mojo/public/cpp/application/application_connection.h"
13 #include "mojo/public/cpp/application/application_delegate.h"
14 #include "mojo/public/cpp/application/application_impl.h"
15 #include "mojo/public/cpp/application/interface_factory_impl.h"
16 #include "mojo/public/cpp/bindings/interface_impl.h"
17 #include "mojo/services/public/cpp/view_manager/view.h"
18 #include "mojo/services/public/cpp/view_manager/view_manager.h"
19 #include "mojo/services/public/cpp/view_manager/view_manager_client_factory.h"
20 #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h"
21 #include "mojo/services/public/cpp/view_manager/view_observer.h"
22 #include "mojo/services/public/interfaces/navigation/navigation.mojom.h"
23 #include "mojo/views/native_widget_view_manager.h"
24 #include "mojo/views/views_init.h"
25 #include "skia/ext/platform_canvas.h"
26 #include "skia/ext/refptr.h"
27 #include "third_party/skia/include/core/SkBitmap.h"
28 #include "third_party/skia/include/core/SkCanvas.h"
29 #include "third_party/skia/include/core/SkColor.h"
30 #include "third_party/skia/include/core/SkPaint.h"
31 #include "third_party/skia/include/core/SkRect.h"
32 #include "ui/gfx/canvas.h"
33 #include "ui/gfx/geometry/insets.h"
34 #include "ui/gfx/geometry/rect.h"
35 #include "ui/views/background.h"
36 #include "ui/views/border.h"
37 #include "ui/views/controls/button/button.h"
38 #include "ui/views/controls/button/label_button.h"
39 #include "ui/views/layout/box_layout.h"
40 #include "ui/views/painter.h"
41 #include "ui/views/widget/widget.h"
42 #include "ui/views/widget/widget_delegate.h"
49 class CustomButtonBorder: public views::Border {
52 : normal_painter_(CreatePainter(SkColorSetRGB(0x80, 0x80, 0x80),
53 SkColorSetRGB(0xC0, 0xC0, 0xC0))),
54 hot_painter_(CreatePainter(SkColorSetRGB(0xA0, 0xA0, 0xA0),
55 SkColorSetRGB(0xD0, 0xD0, 0xD0))),
56 pushed_painter_(CreatePainter(SkColorSetRGB(0x80, 0x80, 0x80),
57 SkColorSetRGB(0x90, 0x90, 0x90))),
60 virtual ~CustomButtonBorder() {}
63 // Overridden from views::Border:
64 virtual void Paint(const views::View& view, gfx::Canvas* canvas) OVERRIDE {
65 const views::LabelButton* button =
66 static_cast<const views::LabelButton*>(&view);
67 views::Button::ButtonState state = button->state();
69 views::Painter* painter = normal_painter_.get();
70 if (state == views::Button::STATE_HOVERED) {
71 painter = hot_painter_.get();
72 } else if (state == views::Button::STATE_PRESSED) {
73 painter = pushed_painter_.get();
75 painter->Paint(canvas, view.size());
78 virtual gfx::Insets GetInsets() const OVERRIDE {
82 virtual gfx::Size GetMinimumSize() const OVERRIDE {
85 size.SetToMax(normal_painter_->GetMinimumSize());
87 size.SetToMax(hot_painter_->GetMinimumSize());
89 size.SetToMax(pushed_painter_->GetMinimumSize());
93 scoped_ptr<views::Painter> CreatePainter(SkColor border, SkColor background) {
94 skia::RefPtr<SkCanvas> canvas(skia::AdoptRef(skia::CreatePlatformCanvas(
97 paint.setColor(background);
98 canvas->drawRoundRect(SkRect::MakeWH(63, 63), 2, 2, paint);
99 paint.setStyle(SkPaint::kStroke_Style);
100 paint.setColor(border);
101 canvas->drawRoundRect(SkRect::MakeWH(63, 63), 2, 2, paint);
103 return scoped_ptr<views::Painter>(
104 views::Painter::CreateImagePainter(
105 gfx::ImageSkia::CreateFrom1xBitmap(
106 skia::GetTopDevice(*canvas)->accessBitmap(true)),
107 gfx::Insets(5, 5, 5, 5)));
110 scoped_ptr<views::Painter> normal_painter_;
111 scoped_ptr<views::Painter> hot_painter_;
112 scoped_ptr<views::Painter> pushed_painter_;
116 DISALLOW_COPY_AND_ASSIGN(CustomButtonBorder);
119 class ControlPanel : public views::ButtonListener {
130 virtual ~Delegate() {}
132 virtual void ButtonPressed(ControlType type) = 0;
135 ControlPanel(Delegate* delegate) : delegate_(delegate), buttons_() {}
137 virtual ~ControlPanel() {}
139 void Initialize(View* view) {
140 const char* kNames[] = { "Zoom In", "Actual Size", "Zoom Out" };
142 views::WidgetDelegateView* widget_delegate = new views::WidgetDelegateView;
144 widget_delegate->GetContentsView()->SetLayoutManager(
145 new views::BoxLayout(views::BoxLayout::kHorizontal, 5, 2, 5));
147 widget_delegate->GetContentsView()->set_background(
148 views::Background::CreateSolidBackground(SK_ColorLTGRAY));
150 for (int type = 0; type < CONTROL_COUNT; ++type) {
151 views::Button* button = new views::LabelButton(
152 this, base::ASCIIToUTF16(kNames[type]));
153 button->SetBorder(scoped_ptr<views::Border>(new CustomButtonBorder));
154 buttons_[type] = button;
155 widget_delegate->GetContentsView()->AddChildView(button);
158 views::Widget* widget = new views::Widget;
159 views::Widget::InitParams params(
160 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
161 params.native_widget = new NativeWidgetViewManager(widget, view);
162 params.delegate = widget_delegate;
163 params.bounds = gfx::Rect(view->bounds().width(), view->bounds().height());
164 params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
165 widget->Init(params);
170 // Overridden from views::ButtonListener:
171 virtual void ButtonPressed(views::Button* sender,
172 const ui::Event& event) OVERRIDE {
173 for (int i = 0; i < CONTROL_COUNT; ++i) {
174 if (sender == buttons_[i]) {
175 delegate_->ButtonPressed(static_cast<ControlType>(i));
182 views::Button* buttons_[CONTROL_COUNT];
184 DISALLOW_COPY_AND_ASSIGN(ControlPanel);
187 class NavigatorImpl : public InterfaceImpl<Navigator> {
189 explicit NavigatorImpl(MediaViewer* viewer) : viewer_(viewer) {}
190 virtual ~NavigatorImpl() {}
193 // Overridden from Navigator:
194 virtual void Navigate(
196 NavigationDetailsPtr navigation_details,
197 ResponseDetailsPtr response_details) OVERRIDE;
199 MediaViewer* viewer_;
201 DISALLOW_COPY_AND_ASSIGN(NavigatorImpl);
205 : public ApplicationDelegate,
206 public ViewManagerDelegate,
207 public ControlPanel::Delegate,
208 public ViewObserver {
211 : navigator_factory_(this),
212 view_manager_client_factory_(this),
218 control_panel_(this) {
219 handler_map_["image/png"] = "mojo:mojo_png_viewer";
222 virtual ~MediaViewer() {
224 root_view_->RemoveObserver(this);
229 NavigationDetailsPtr navigation_details,
230 ResponseDetailsPtr response_details) {
231 // TODO(yzshen): This shouldn't be needed once FIFO is ready.
232 if (!view_manager_) {
233 pending_navigate_request_.reset(new PendingNavigateRequest);
234 pending_navigate_request_->view_id = view_id;
235 pending_navigate_request_->navigation_details = navigation_details.Pass();
236 pending_navigate_request_->response_details = response_details.Pass();
241 std::string handler = GetHandlerForContentType(
242 response_details->response->mime_type);
246 content_view_->Embed(handler);
248 if (navigation_details) {
249 NavigatorPtr navigator;
250 app_->ConnectToService(handler, &navigator);
251 navigator->Navigate(content_view_->id(), navigation_details.Pass(),
252 response_details.Pass());
255 // TODO(yzshen): determine the set of controls to show based on what
256 // interfaces the embedded app provides.
257 app_->ConnectToService(handler, &zoomable_media_);
261 typedef std::map<std::string, std::string> HandlerMap;
263 struct PendingNavigateRequest {
265 NavigationDetailsPtr navigation_details;
266 ResponseDetailsPtr response_details;
270 // Overridden from ApplicationDelegate:
271 virtual void Initialize(ApplicationImpl* app) OVERRIDE {
273 views_init_.reset(new ViewsInit);
276 virtual bool ConfigureIncomingConnection(ApplicationConnection* connection)
278 connection->AddService(&navigator_factory_);
279 connection->AddService(&view_manager_client_factory_);
284 View* root = content_view_->parent();
285 gfx::Rect control_bounds(root->bounds().width(), 28);
286 control_view_->SetBounds(control_bounds);
287 gfx::Rect content_bounds(0, control_bounds.height(), root->bounds().width(),
288 root->bounds().height() - control_bounds.height());
289 content_view_->SetBounds(content_bounds);
292 // Overridden from ViewManagerDelegate:
293 virtual void OnEmbed(ViewManager* view_manager,
295 ServiceProviderImpl* exported_services,
296 scoped_ptr<ServiceProvider> imported_services) OVERRIDE {
298 view_manager_ = view_manager;
300 control_view_ = View::Create(view_manager_);
301 root_view_->AddChild(control_view_);
303 content_view_ = View::Create(view_manager_);
304 root_view_->AddChild(content_view_);
306 control_panel_.Initialize(control_view_);
309 root_view_->AddObserver(this);
311 if (pending_navigate_request_) {
312 scoped_ptr<PendingNavigateRequest> request(
313 pending_navigate_request_.release());
315 Navigate(request->view_id, request->navigation_details.Pass(),
316 request->response_details.Pass());
319 virtual void OnViewManagerDisconnected(
320 ViewManager* view_manager) OVERRIDE {
321 DCHECK_EQ(view_manager_, view_manager);
322 view_manager_ = NULL;
323 base::MessageLoop::current()->Quit();
326 // Overridden from ControlPanel::Delegate:
327 virtual void ButtonPressed(ControlPanel::ControlType type) OVERRIDE {
329 case ControlPanel::CONTROL_ZOOM_IN:
330 zoomable_media_->ZoomIn();
332 case ControlPanel::CONTROL_ACTUAL_SIZE:
333 zoomable_media_->ZoomToActualSize();
335 case ControlPanel::CONTROL_ZOOM_OUT:
336 zoomable_media_->ZoomOut();
344 virtual void OnViewBoundsChanged(View* view,
345 const gfx::Rect& old_bounds,
346 const gfx::Rect& new_bounds) OVERRIDE {
349 virtual void OnViewDestroyed(View* view) OVERRIDE {
350 DCHECK_EQ(view, root_view_);
351 view->RemoveObserver(this);
355 std::string GetHandlerForContentType(const std::string& content_type) {
356 HandlerMap::const_iterator it = handler_map_.find(content_type);
357 return it != handler_map_.end() ? it->second : std::string();
360 InterfaceFactoryImplWithContext<NavigatorImpl, MediaViewer>
362 ViewManagerClientFactory view_manager_client_factory_;
364 ApplicationImpl* app_;
365 scoped_ptr<ViewsInit> views_init_;
366 ViewManager* view_manager_;
370 ControlPanel control_panel_;
371 ZoomableMediaPtr zoomable_media_;
372 HandlerMap handler_map_;
373 scoped_ptr<PendingNavigateRequest> pending_navigate_request_;
375 DISALLOW_COPY_AND_ASSIGN(MediaViewer);
378 void NavigatorImpl::Navigate(
380 NavigationDetailsPtr navigation_details,
381 ResponseDetailsPtr response_details) {
382 viewer_->Navigate(view_id, navigation_details.Pass(),
383 response_details.Pass());
386 } // namespace examples
389 ApplicationDelegate* ApplicationDelegate::Create() {
390 return new examples::MediaViewer;