diff options
-rw-r--r-- | mojo/examples/media_viewer/DEPS | 2 | ||||
-rw-r--r-- | mojo/examples/media_viewer/media_viewer.cc | 210 | ||||
-rw-r--r-- | mojo/examples/media_viewer/media_viewer.mojom | 13 | ||||
-rw-r--r-- | mojo/examples/png_viewer/DEPS | 1 | ||||
-rw-r--r-- | mojo/examples/png_viewer/png_viewer.cc | 91 | ||||
-rw-r--r-- | mojo/mojo_examples.gypi | 21 |
6 files changed, 324 insertions, 14 deletions
diff --git a/mojo/examples/media_viewer/DEPS b/mojo/examples/media_viewer/DEPS index 2930a78..44ca77e 100644 --- a/mojo/examples/media_viewer/DEPS +++ b/mojo/examples/media_viewer/DEPS @@ -1,4 +1,6 @@ include_rules = [ + "+skia/ext", + "+third_party/skia/include", "+ui/events", "+ui/gfx", "+ui/views", diff --git a/mojo/examples/media_viewer/media_viewer.cc b/mojo/examples/media_viewer/media_viewer.cc index b727b59..e4ea4c6 100644 --- a/mojo/examples/media_viewer/media_viewer.cc +++ b/mojo/examples/media_viewer/media_viewer.cc @@ -7,6 +7,8 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" +#include "base/strings/utf_string_conversions.h" +#include "mojo/examples/media_viewer/media_viewer.mojom.h" #include "mojo/public/cpp/application/application_connection.h" #include "mojo/public/cpp/application/application_delegate.h" #include "mojo/public/cpp/application/application_impl.h" @@ -16,17 +18,170 @@ #include "mojo/services/public/cpp/view_manager/view_manager.h" #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h" #include "mojo/services/public/interfaces/navigation/navigation.mojom.h" +#include "mojo/views/native_widget_view_manager.h" +#include "mojo/views/views_init.h" +#include "skia/ext/platform_canvas.h" +#include "skia/ext/refptr.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkPaint.h" +#include "third_party/skia/include/core/SkRect.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/rect.h" +#include "ui/views/border.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/button/label_button.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/painter.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" namespace mojo { namespace examples { class MediaViewer; +class CustomButtonBorder: public views::Border { + public: + CustomButtonBorder() + : normal_painter_(CreatePainter(SkColorSetRGB(0x80, 0x80, 0x80), + SkColorSetRGB(0xC0, 0xC0, 0xC0))), + hot_painter_(CreatePainter(SkColorSetRGB(0xA0, 0xA0, 0xA0), + SkColorSetRGB(0xD0, 0xD0, 0xD0))), + pushed_painter_(CreatePainter(SkColorSetRGB(0x80, 0x80, 0x80), + SkColorSetRGB(0x90, 0x90, 0x90))), + insets_(2, 6, 2, 6) { + } + virtual ~CustomButtonBorder() {} + + private: + // Overridden from views::Border: + virtual void Paint(const views::View& view, gfx::Canvas* canvas) OVERRIDE { + const views::LabelButton* button = + static_cast<const views::LabelButton*>(&view); + views::Button::ButtonState state = button->state(); + + views::Painter* painter = normal_painter_.get(); + if (state == views::Button::STATE_HOVERED) { + painter = hot_painter_.get(); + } else if (state == views::Button::STATE_PRESSED) { + painter = pushed_painter_.get(); + } + painter->Paint(canvas, view.size()); + } + + virtual gfx::Insets GetInsets() const OVERRIDE { + return insets_; + } + + virtual gfx::Size GetMinimumSize() const OVERRIDE { + gfx::Size size; + if (normal_painter_) + size.SetToMax(normal_painter_->GetMinimumSize()); + if (hot_painter_) + size.SetToMax(hot_painter_->GetMinimumSize()); + if (pushed_painter_) + size.SetToMax(pushed_painter_->GetMinimumSize()); + return size; + } + + scoped_ptr<views::Painter> CreatePainter(SkColor border, SkColor background) { + skia::RefPtr<SkCanvas> canvas(skia::AdoptRef(skia::CreatePlatformCanvas( + 64, 64, false))); + SkPaint paint; + paint.setColor(background); + canvas->drawRoundRect(SkRect::MakeWH(63, 63), 2, 2, paint); + paint.setStyle(SkPaint::kStroke_Style); + paint.setColor(border); + canvas->drawRoundRect(SkRect::MakeWH(63, 63), 2, 2, paint); + + return scoped_ptr<views::Painter>( + views::Painter::CreateImagePainter( + gfx::ImageSkia::CreateFrom1xBitmap( + skia::GetTopDevice(*canvas)->accessBitmap(true)), + gfx::Insets(5, 5, 5, 5))); + } + + scoped_ptr<views::Painter> normal_painter_; + scoped_ptr<views::Painter> hot_painter_; + scoped_ptr<views::Painter> pushed_painter_; + + gfx::Insets insets_; + + DISALLOW_COPY_AND_ASSIGN(CustomButtonBorder); +}; + +class ControlPanel : public views::ButtonListener { + public: + enum ControlType { + CONTROL_ZOOM_IN, + CONTROL_ACTUAL_SIZE, + CONTROL_ZOOM_OUT, + CONTROL_COUNT, + }; + + class Delegate { + public: + virtual ~Delegate() {} + + virtual void ButtonPressed(ControlType type) = 0; + }; + + ControlPanel(Delegate* delegate) : delegate_(delegate), buttons_() {} + + virtual ~ControlPanel() {} + + void Initialize(view_manager::Node* node) { + const char* kNames[] = { "Zoom In", "Actual Size", "Zoom Out" }; + + views::WidgetDelegateView* widget_delegate = new views::WidgetDelegateView; + + widget_delegate->GetContentsView()->SetLayoutManager( + new views::BoxLayout(views::BoxLayout::kHorizontal, 5, 2, 5)); + + for (int type = 0; type < CONTROL_COUNT; ++type) { + views::Button* button = new views::LabelButton( + this, base::ASCIIToUTF16(kNames[type])); + button->SetBorder(scoped_ptr<views::Border>(new CustomButtonBorder)); + buttons_[type] = button; + widget_delegate->GetContentsView()->AddChildView(button); + } + + views::Widget* widget = new views::Widget; + views::Widget::InitParams params( + views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); + params.native_widget = new NativeWidgetViewManager(widget, node); + params.delegate = widget_delegate; + params.bounds = gfx::Rect(node->bounds().width(), node->bounds().height()); + params.opacity = views::Widget::InitParams::OPAQUE_WINDOW; + widget->Init(params); + widget->Show(); + } + + private: + // Overridden from views::ButtonListener: + virtual void ButtonPressed(views::Button* sender, + const ui::Event& event) OVERRIDE { + for (int i = 0; i < CONTROL_COUNT; ++i) { + if (sender == buttons_[i]) { + delegate_->ButtonPressed(static_cast<ControlType>(i)); + return; + } + } + } + + Delegate* delegate_; + views::Button* buttons_[CONTROL_COUNT]; + + DISALLOW_COPY_AND_ASSIGN(ControlPanel); +}; + class NavigatorImpl : public InterfaceImpl<navigation::Navigator> { public: - explicit NavigatorImpl(ApplicationConnection* connection, - MediaViewer* viewer) : viewer_(viewer) {} + NavigatorImpl(ApplicationConnection* connection, + MediaViewer* viewer) : viewer_(viewer) {} virtual ~NavigatorImpl() {} private: @@ -42,11 +197,14 @@ class NavigatorImpl : public InterfaceImpl<navigation::Navigator> { }; class MediaViewer : public ApplicationDelegate, - public view_manager::ViewManagerDelegate { + public view_manager::ViewManagerDelegate, + public ControlPanel::Delegate { public: MediaViewer() : app_(NULL), + view_manager_(NULL), + control_node_(NULL), content_node_(NULL), - view_manager_(NULL) { + control_panel_(this) { handler_map_["image/png"] = "mojo:mojo_png_viewer"; } @@ -66,7 +224,6 @@ class MediaViewer : public ApplicationDelegate, return; } - // TODO(yzshen): provide media control UI. std::string handler = GetHandlerForContentType( response_details->response->mime_type); if (handler.empty()) @@ -80,6 +237,10 @@ class MediaViewer : public ApplicationDelegate, navigator->Navigate(content_node_->id(), navigation_details.Pass(), response_details.Pass()); } + + // TODO(yzshen): determine the set of controls to show based on what + // interfaces the embedded app provides. + app_->ConnectToService(handler, &zoomable_media_); } private: @@ -95,6 +256,7 @@ class MediaViewer : public ApplicationDelegate, // Overridden from ApplicationDelegate: virtual void Initialize(ApplicationImpl* app) OVERRIDE { app_ = app; + views_init_.reset(new ViewsInit); } virtual bool ConfigureIncomingConnection(ApplicationConnection* connection) @@ -108,11 +270,20 @@ class MediaViewer : public ApplicationDelegate, virtual void OnRootAdded(view_manager::ViewManager* view_manager, view_manager::Node* root) OVERRIDE { view_manager_ = view_manager; + + control_node_ = view_manager::Node::Create(view_manager_); + root->AddChild(control_node_); + gfx::Rect control_bounds(root->bounds().width(), 28); + control_node_->SetBounds(control_bounds); + control_node_->SetActiveView(view_manager::View::Create(view_manager_)); + + control_panel_.Initialize(control_node_); + content_node_ = view_manager::Node::Create(view_manager_); root->AddChild(content_node_); - - gfx::Rect bounds(root->bounds().size()); - content_node_->SetBounds(bounds); + gfx::Rect content_bounds(0, control_bounds.height(), root->bounds().width(), + root->bounds().height() - control_bounds.height()); + content_node_->SetBounds(content_bounds); if (pending_navigate_request_) { scoped_ptr<PendingNavigateRequest> request( @@ -123,14 +294,35 @@ class MediaViewer : public ApplicationDelegate, } } + // Overridden from ControlPanel::Delegate: + virtual void ButtonPressed(ControlPanel::ControlType type) OVERRIDE { + switch (type) { + case ControlPanel::CONTROL_ZOOM_IN: + zoomable_media_->ZoomIn(); + break; + case ControlPanel::CONTROL_ACTUAL_SIZE: + zoomable_media_->ZoomToActualSize(); + break; + case ControlPanel::CONTROL_ZOOM_OUT: + zoomable_media_->ZoomOut(); + break; + default: + NOTIMPLEMENTED(); + } + } + std::string GetHandlerForContentType(const std::string& content_type) { HandlerMap::const_iterator it = handler_map_.find(content_type); return it != handler_map_.end() ? it->second : std::string(); } ApplicationImpl* app_; - view_manager::Node* content_node_; + scoped_ptr<ViewsInit> views_init_; view_manager::ViewManager* view_manager_; + view_manager::Node* control_node_; + view_manager::Node* content_node_; + ControlPanel control_panel_; + ZoomableMediaPtr zoomable_media_; HandlerMap handler_map_; scoped_ptr<PendingNavigateRequest> pending_navigate_request_; diff --git a/mojo/examples/media_viewer/media_viewer.mojom b/mojo/examples/media_viewer/media_viewer.mojom new file mode 100644 index 0000000..773d775 --- /dev/null +++ b/mojo/examples/media_viewer/media_viewer.mojom @@ -0,0 +1,13 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module mojo { + +interface ZoomableMedia { + ZoomIn(); + ZoomOut(); + ZoomToActualSize(); +}; + +} diff --git a/mojo/examples/png_viewer/DEPS b/mojo/examples/png_viewer/DEPS index 41134f5..23b2bf6 100644 --- a/mojo/examples/png_viewer/DEPS +++ b/mojo/examples/png_viewer/DEPS @@ -1,4 +1,5 @@ include_rules = [ + "+skia/ext", "+third_party/skia/include", "+ui/gfx", ] diff --git a/mojo/examples/png_viewer/png_viewer.cc b/mojo/examples/png_viewer/png_viewer.cc index 6a7218a..dfa8e7b 100644 --- a/mojo/examples/png_viewer/png_viewer.cc +++ b/mojo/examples/png_viewer/png_viewer.cc @@ -5,6 +5,7 @@ #include <algorithm> #include "base/strings/string_tokenizer.h" +#include "mojo/examples/media_viewer/media_viewer.mojom.h" #include "mojo/public/cpp/application/application_connection.h" #include "mojo/public/cpp/application/application_delegate.h" #include "mojo/services/public/cpp/view_manager/node.h" @@ -13,7 +14,12 @@ #include "mojo/services/public/cpp/view_manager/view_manager.h" #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h" #include "mojo/services/public/interfaces/navigation/navigation.mojom.h" +#include "skia/ext/platform_canvas.h" +#include "skia/ext/refptr.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkPaint.h" +#include "third_party/skia/include/core/SkScalar.h" #include "ui/gfx/codec/png_codec.h" namespace mojo { @@ -21,10 +27,27 @@ namespace examples { class PNGViewer; +class ZoomableMediaImpl : public InterfaceImpl<ZoomableMedia> { + public: + ZoomableMediaImpl(ApplicationConnection* connection, + PNGViewer* viewer) : viewer_(viewer) {} + virtual ~ZoomableMediaImpl() {} + + private: + // Overridden from ZoomableMedia: + virtual void ZoomIn() OVERRIDE; + virtual void ZoomOut() OVERRIDE; + virtual void ZoomToActualSize() OVERRIDE; + + PNGViewer* viewer_; + + DISALLOW_COPY_AND_ASSIGN(ZoomableMediaImpl); +}; + class NavigatorImpl : public InterfaceImpl<navigation::Navigator> { public: - explicit NavigatorImpl(ApplicationConnection* connection, - PNGViewer* viewer) : viewer_(viewer) {} + NavigatorImpl(ApplicationConnection* connection, + PNGViewer* viewer) : viewer_(viewer) {} virtual ~NavigatorImpl() {} private: @@ -89,19 +112,47 @@ class NavigatorImpl : public InterfaceImpl<navigation::Navigator> { class PNGViewer : public ApplicationDelegate, public view_manager::ViewManagerDelegate { public: - PNGViewer() : content_view_(NULL) {} + PNGViewer() : content_view_(NULL), zoom_percentage_(kDefaultZoomPercentage) {} virtual ~PNGViewer() {} void UpdateView(view_manager::Id node_id, const SkBitmap& bitmap) { bitmap_ = bitmap; + zoom_percentage_ = kDefaultZoomPercentage; + DrawBitmap(); + } + + void ZoomIn() { + if (zoom_percentage_ >= kMaxZoomPercentage) + return; + zoom_percentage_ += kZoomStep; + DrawBitmap(); + } + + void ZoomOut() { + if (zoom_percentage_ <= kMinZoomPercentage) + return; + zoom_percentage_ -= kZoomStep; + DrawBitmap(); + } + + void ZoomToActualSize() { + if (zoom_percentage_ == kDefaultZoomPercentage) + return; + zoom_percentage_ = kDefaultZoomPercentage; DrawBitmap(); } private: + static const uint16_t kMaxZoomPercentage = 400; + static const uint16_t kMinZoomPercentage = 20; + static const uint16_t kDefaultZoomPercentage = 100; + static const uint16_t kZoomStep = 20; + // Overridden from ApplicationDelegate: virtual bool ConfigureIncomingConnection(ApplicationConnection* connection) MOJO_OVERRIDE { connection->AddService<NavigatorImpl>(this); + connection->AddService<ZoomableMediaImpl>(this); view_manager::ViewManager::ConfigureIncomingConnection(connection, this); return true; } @@ -117,18 +168,48 @@ class PNGViewer : public ApplicationDelegate, } void DrawBitmap() { - if (content_view_) + if (!content_view_) + return; + + if (zoom_percentage_ == kDefaultZoomPercentage) { content_view_->SetContents(bitmap_); + return; + } + + skia::RefPtr<SkCanvas> canvas(skia::AdoptRef(skia::CreatePlatformCanvas( + content_view_->node()->bounds().width(), + content_view_->node()->bounds().height(), + true))); + canvas->drawColor(SK_ColorGRAY); + SkPaint paint; + SkScalar scale = + SkFloatToScalar(zoom_percentage_ * 1.0f / kDefaultZoomPercentage); + canvas->scale(scale, scale); + canvas->drawBitmap(bitmap_, 0, 0, &paint); + content_view_->SetContents(skia::GetTopDevice(*canvas)->accessBitmap(true)); } view_manager::View* content_view_; SkBitmap bitmap_; + uint16_t zoom_percentage_; DISALLOW_COPY_AND_ASSIGN(PNGViewer); }; +void ZoomableMediaImpl::ZoomIn() { + viewer_->ZoomIn(); +} + +void ZoomableMediaImpl::ZoomOut() { + viewer_->ZoomOut(); +} + +void ZoomableMediaImpl::ZoomToActualSize() { + viewer_->ZoomToActualSize(); +} + void NavigatorImpl::UpdateView(view_manager::Id node_id, - const SkBitmap& bitmap) { + const SkBitmap& bitmap) { viewer_->UpdateView(node_id, bitmap); } diff --git a/mojo/mojo_examples.gypi b/mojo/mojo_examples.gypi index e464e12..009fc9a 100644 --- a/mojo/mojo_examples.gypi +++ b/mojo/mojo_examples.gypi @@ -132,6 +132,20 @@ ], }, { + 'target_name': 'mojo_media_viewer_bindings', + 'type': 'static_library', + 'sources': [ + 'examples/media_viewer/media_viewer.mojom', + ], + 'includes': [ 'public/tools/bindings/mojom_bindings_generator.gypi' ], + 'export_dependent_settings': [ + 'mojo_cpp_bindings', + ], + 'dependencies': [ + 'mojo_cpp_bindings', + ], + }, + { 'target_name': 'mojo_png_viewer', 'type': 'shared_library', 'dependencies': [ @@ -140,6 +154,7 @@ 'mojo_application', 'mojo_cpp_bindings', 'mojo_environment_chromium', + 'mojo_media_viewer_bindings', 'mojo_navigation_bindings', 'mojo_network_bindings', 'mojo_launcher_bindings', @@ -518,10 +533,16 @@ 'type': 'shared_library', 'dependencies': [ '../base/base.gyp:base', + '../skia/skia.gyp:skia', + '../ui/gfx/gfx.gyp:gfx_geometry', + '../ui/views/views.gyp:views', 'mojo_application', 'mojo_environment_chromium', + 'mojo_input_events_lib', + 'mojo_media_viewer_bindings', 'mojo_navigation_bindings', 'mojo_system_impl', + 'mojo_views_support', 'mojo_view_manager_bindings', 'mojo_view_manager_lib', ], |