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. 4 5 #include <map> 6 #include <string> 7 8 #include "base/macros.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "mojo/application/application_runner_chromium.h" 12 #include "mojo/examples/media_viewer/media_viewer.mojom.h" 13 #include "mojo/public/c/system/main.h" 14 #include "mojo/public/cpp/application/application_connection.h" 15 #include "mojo/public/cpp/application/application_delegate.h" 16 #include "mojo/public/cpp/application/application_impl.h" 17 #include "mojo/public/cpp/application/interface_factory_impl.h" 18 #include "mojo/public/cpp/bindings/interface_impl.h" 19 #include "mojo/services/public/cpp/view_manager/view.h" 20 #include "mojo/services/public/cpp/view_manager/view_manager.h" 21 #include "mojo/services/public/cpp/view_manager/view_manager_client_factory.h" 22 #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h" 23 #include "mojo/services/public/cpp/view_manager/view_observer.h" 24 #include "mojo/services/public/interfaces/navigation/navigation.mojom.h" 25 #include "mojo/views/native_widget_view_manager.h" 26 #include "mojo/views/views_init.h" 27 #include "skia/ext/platform_canvas.h" 28 #include "skia/ext/refptr.h" 29 #include "third_party/skia/include/core/SkBitmap.h" 30 #include "third_party/skia/include/core/SkCanvas.h" 31 #include "third_party/skia/include/core/SkColor.h" 32 #include "third_party/skia/include/core/SkPaint.h" 33 #include "third_party/skia/include/core/SkRect.h" 34 #include "ui/gfx/canvas.h" 35 #include "ui/gfx/geometry/insets.h" 36 #include "ui/gfx/geometry/rect.h" 37 #include "ui/views/background.h" 38 #include "ui/views/border.h" 39 #include "ui/views/controls/button/button.h" 40 #include "ui/views/controls/button/label_button.h" 41 #include "ui/views/layout/box_layout.h" 42 #include "ui/views/painter.h" 43 #include "ui/views/widget/widget.h" 44 #include "ui/views/widget/widget_delegate.h" 45 46 namespace mojo { 47 namespace examples { 48 49 class MediaViewer; 50 51 class CustomButtonBorder: public views::Border { 52 public: 53 CustomButtonBorder() 54 : normal_painter_(CreatePainter(SkColorSetRGB(0x80, 0x80, 0x80), 55 SkColorSetRGB(0xC0, 0xC0, 0xC0))), 56 hot_painter_(CreatePainter(SkColorSetRGB(0xA0, 0xA0, 0xA0), 57 SkColorSetRGB(0xD0, 0xD0, 0xD0))), 58 pushed_painter_(CreatePainter(SkColorSetRGB(0x80, 0x80, 0x80), 59 SkColorSetRGB(0x90, 0x90, 0x90))), 60 insets_(2, 6, 2, 6) { 61 } 62 virtual ~CustomButtonBorder() {} 63 64 private: 65 // Overridden from views::Border: 66 virtual void Paint(const views::View& view, gfx::Canvas* canvas) OVERRIDE { 67 const views::LabelButton* button = 68 static_cast<const views::LabelButton*>(&view); 69 views::Button::ButtonState state = button->state(); 70 71 views::Painter* painter = normal_painter_.get(); 72 if (state == views::Button::STATE_HOVERED) { 73 painter = hot_painter_.get(); 74 } else if (state == views::Button::STATE_PRESSED) { 75 painter = pushed_painter_.get(); 76 } 77 painter->Paint(canvas, view.size()); 78 } 79 80 virtual gfx::Insets GetInsets() const OVERRIDE { 81 return insets_; 82 } 83 84 virtual gfx::Size GetMinimumSize() const OVERRIDE { 85 gfx::Size size; 86 if (normal_painter_) 87 size.SetToMax(normal_painter_->GetMinimumSize()); 88 if (hot_painter_) 89 size.SetToMax(hot_painter_->GetMinimumSize()); 90 if (pushed_painter_) 91 size.SetToMax(pushed_painter_->GetMinimumSize()); 92 return size; 93 } 94 95 scoped_ptr<views::Painter> CreatePainter(SkColor border, SkColor background) { 96 skia::RefPtr<SkCanvas> canvas(skia::AdoptRef(skia::CreatePlatformCanvas( 97 64, 64, false))); 98 SkPaint paint; 99 paint.setColor(background); 100 canvas->drawRoundRect(SkRect::MakeWH(63, 63), 2, 2, paint); 101 paint.setStyle(SkPaint::kStroke_Style); 102 paint.setColor(border); 103 canvas->drawRoundRect(SkRect::MakeWH(63, 63), 2, 2, paint); 104 105 return scoped_ptr<views::Painter>( 106 views::Painter::CreateImagePainter( 107 gfx::ImageSkia::CreateFrom1xBitmap( 108 skia::GetTopDevice(*canvas)->accessBitmap(true)), 109 gfx::Insets(5, 5, 5, 5))); 110 } 111 112 scoped_ptr<views::Painter> normal_painter_; 113 scoped_ptr<views::Painter> hot_painter_; 114 scoped_ptr<views::Painter> pushed_painter_; 115 116 gfx::Insets insets_; 117 118 DISALLOW_COPY_AND_ASSIGN(CustomButtonBorder); 119 }; 120 121 class ControlPanel : public views::ButtonListener { 122 public: 123 enum ControlType { 124 CONTROL_ZOOM_IN, 125 CONTROL_ACTUAL_SIZE, 126 CONTROL_ZOOM_OUT, 127 CONTROL_COUNT, 128 }; 129 130 class Delegate { 131 public: 132 virtual ~Delegate() {} 133 134 virtual void ButtonPressed(ControlType type) = 0; 135 }; 136 137 ControlPanel(Delegate* delegate) : delegate_(delegate), buttons_() {} 138 139 virtual ~ControlPanel() {} 140 141 void Initialize(View* view) { 142 const char* kNames[] = { "Zoom In", "Actual Size", "Zoom Out" }; 143 144 views::WidgetDelegateView* widget_delegate = new views::WidgetDelegateView; 145 146 widget_delegate->GetContentsView()->SetLayoutManager( 147 new views::BoxLayout(views::BoxLayout::kHorizontal, 5, 2, 5)); 148 149 widget_delegate->GetContentsView()->set_background( 150 views::Background::CreateSolidBackground(SK_ColorLTGRAY)); 151 152 for (int type = 0; type < CONTROL_COUNT; ++type) { 153 views::Button* button = new views::LabelButton( 154 this, base::ASCIIToUTF16(kNames[type])); 155 button->SetBorder(scoped_ptr<views::Border>(new CustomButtonBorder)); 156 buttons_[type] = button; 157 widget_delegate->GetContentsView()->AddChildView(button); 158 } 159 160 views::Widget* widget = new views::Widget; 161 views::Widget::InitParams params( 162 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); 163 params.native_widget = new NativeWidgetViewManager(widget, view); 164 params.delegate = widget_delegate; 165 params.bounds = gfx::Rect(view->bounds().width(), view->bounds().height()); 166 params.opacity = views::Widget::InitParams::OPAQUE_WINDOW; 167 widget->Init(params); 168 widget->Show(); 169 } 170 171 private: 172 // Overridden from views::ButtonListener: 173 virtual void ButtonPressed(views::Button* sender, 174 const ui::Event& event) OVERRIDE { 175 for (int i = 0; i < CONTROL_COUNT; ++i) { 176 if (sender == buttons_[i]) { 177 delegate_->ButtonPressed(static_cast<ControlType>(i)); 178 return; 179 } 180 } 181 } 182 183 Delegate* delegate_; 184 views::Button* buttons_[CONTROL_COUNT]; 185 186 DISALLOW_COPY_AND_ASSIGN(ControlPanel); 187 }; 188 189 class MediaViewer 190 : public ApplicationDelegate, 191 public ViewManagerDelegate, 192 public ControlPanel::Delegate, 193 public ViewObserver { 194 public: 195 MediaViewer() 196 : app_(NULL), 197 view_manager_(NULL), 198 root_view_(NULL), 199 control_view_(NULL), 200 content_view_(NULL), 201 control_panel_(this) { 202 handler_map_["image/png"] = "mojo:mojo_png_viewer"; 203 } 204 205 virtual ~MediaViewer() { 206 if (root_view_) 207 root_view_->RemoveObserver(this); 208 } 209 210 private: 211 typedef std::map<std::string, std::string> HandlerMap; 212 213 214 // Overridden from ApplicationDelegate: 215 virtual void Initialize(ApplicationImpl* app) OVERRIDE { 216 view_manager_client_factory_.reset( 217 new ViewManagerClientFactory(app->shell(), this)); 218 app_ = app; 219 views_init_.reset(new ViewsInit); 220 } 221 222 virtual bool ConfigureIncomingConnection(ApplicationConnection* connection) 223 OVERRIDE { 224 connection->AddService(view_manager_client_factory_.get()); 225 return true; 226 } 227 228 void LayoutViews() { 229 View* root = content_view_->parent(); 230 gfx::Rect control_bounds(root->bounds().width(), 28); 231 control_view_->SetBounds(control_bounds); 232 gfx::Rect content_bounds(0, control_bounds.height(), root->bounds().width(), 233 root->bounds().height() - control_bounds.height()); 234 content_view_->SetBounds(content_bounds); 235 } 236 237 // Overridden from ViewManagerDelegate: 238 virtual void OnEmbed(ViewManager* view_manager, 239 View* root, 240 ServiceProviderImpl* exported_services, 241 scoped_ptr<ServiceProvider> imported_services) OVERRIDE { 242 root_view_ = root; 243 view_manager_ = view_manager; 244 245 control_view_ = View::Create(view_manager_); 246 root_view_->AddChild(control_view_); 247 248 content_view_ = View::Create(view_manager_); 249 root_view_->AddChild(content_view_); 250 251 control_panel_.Initialize(control_view_); 252 253 LayoutViews(); 254 root_view_->AddObserver(this); 255 256 content_view_->Embed("TODO"); 257 } 258 259 virtual void OnViewManagerDisconnected( 260 ViewManager* view_manager) OVERRIDE { 261 DCHECK_EQ(view_manager_, view_manager); 262 view_manager_ = NULL; 263 base::MessageLoop::current()->Quit(); 264 } 265 266 // Overridden from ControlPanel::Delegate: 267 virtual void ButtonPressed(ControlPanel::ControlType type) OVERRIDE { 268 switch (type) { 269 case ControlPanel::CONTROL_ZOOM_IN: 270 zoomable_media_->ZoomIn(); 271 break; 272 case ControlPanel::CONTROL_ACTUAL_SIZE: 273 zoomable_media_->ZoomToActualSize(); 274 break; 275 case ControlPanel::CONTROL_ZOOM_OUT: 276 zoomable_media_->ZoomOut(); 277 break; 278 default: 279 NOTIMPLEMENTED(); 280 } 281 } 282 283 // ViewObserver: 284 virtual void OnViewBoundsChanged(View* view, 285 const gfx::Rect& old_bounds, 286 const gfx::Rect& new_bounds) OVERRIDE { 287 LayoutViews(); 288 } 289 virtual void OnViewDestroyed(View* view) OVERRIDE { 290 DCHECK_EQ(view, root_view_); 291 view->RemoveObserver(this); 292 root_view_ = NULL; 293 } 294 295 std::string GetHandlerForContentType(const std::string& content_type) { 296 HandlerMap::const_iterator it = handler_map_.find(content_type); 297 return it != handler_map_.end() ? it->second : std::string(); 298 } 299 300 scoped_ptr<ViewManagerClientFactory> view_manager_client_factory_; 301 302 ApplicationImpl* app_; 303 scoped_ptr<ViewsInit> views_init_; 304 ViewManager* view_manager_; 305 View* root_view_; 306 View* control_view_; 307 View* content_view_; 308 ControlPanel control_panel_; 309 ZoomableMediaPtr zoomable_media_; 310 HandlerMap handler_map_; 311 312 DISALLOW_COPY_AND_ASSIGN(MediaViewer); 313 }; 314 315 } // namespace examples 316 } // namespace mojo 317 318 MojoResult MojoMain(MojoHandle shell_handle) { 319 mojo::ApplicationRunnerChromium runner(new mojo::examples::MediaViewer); 320 return runner.Run(shell_handle); 321 } 322