普通文本  |  322行  |  10.2 KB

// 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.

#include <map>
#include <string>

#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "mojo/application/application_runner_chromium.h"
#include "mojo/examples/media_viewer/media_viewer.mojom.h"
#include "mojo/public/c/system/main.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"
#include "mojo/public/cpp/application/interface_factory_impl.h"
#include "mojo/public/cpp/bindings/interface_impl.h"
#include "mojo/services/public/cpp/view_manager/view.h"
#include "mojo/services/public/cpp/view_manager/view_manager.h"
#include "mojo/services/public/cpp/view_manager/view_manager_client_factory.h"
#include "mojo/services/public/cpp/view_manager/view_manager_delegate.h"
#include "mojo/services/public/cpp/view_manager/view_observer.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/background.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* view) {
    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));

    widget_delegate->GetContentsView()->set_background(
        views::Background::CreateSolidBackground(SK_ColorLTGRAY));

    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, view);
    params.delegate = widget_delegate;
    params.bounds = gfx::Rect(view->bounds().width(), view->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 MediaViewer
    : public ApplicationDelegate,
      public ViewManagerDelegate,
      public ControlPanel::Delegate,
      public ViewObserver {
 public:
  MediaViewer()
      : app_(NULL),
        view_manager_(NULL),
        root_view_(NULL),
        control_view_(NULL),
        content_view_(NULL),
        control_panel_(this) {
    handler_map_["image/png"] = "mojo:mojo_png_viewer";
  }

  virtual ~MediaViewer() {
    if (root_view_)
      root_view_->RemoveObserver(this);
  }

 private:
  typedef std::map<std::string, std::string> HandlerMap;


  // Overridden from ApplicationDelegate:
  virtual void Initialize(ApplicationImpl* app) OVERRIDE {
    view_manager_client_factory_.reset(
        new ViewManagerClientFactory(app->shell(), this));
    app_ = app;
    views_init_.reset(new ViewsInit);
  }

  virtual bool ConfigureIncomingConnection(ApplicationConnection* connection)
      OVERRIDE {
    connection->AddService(view_manager_client_factory_.get());
    return true;
  }

  void LayoutViews() {
    View* root = content_view_->parent();
    gfx::Rect control_bounds(root->bounds().width(), 28);
    control_view_->SetBounds(control_bounds);
    gfx::Rect content_bounds(0, control_bounds.height(), root->bounds().width(),
                             root->bounds().height() - control_bounds.height());
    content_view_->SetBounds(content_bounds);
  }

  // Overridden from ViewManagerDelegate:
  virtual void OnEmbed(ViewManager* view_manager,
                       View* root,
                       ServiceProviderImpl* exported_services,
                       scoped_ptr<ServiceProvider> imported_services) OVERRIDE {
    root_view_ = root;
    view_manager_ = view_manager;

    control_view_ = View::Create(view_manager_);
    root_view_->AddChild(control_view_);

    content_view_ = View::Create(view_manager_);
    root_view_->AddChild(content_view_);

    control_panel_.Initialize(control_view_);

    LayoutViews();
    root_view_->AddObserver(this);

    content_view_->Embed("TODO");
  }

  virtual void OnViewManagerDisconnected(
      ViewManager* view_manager) OVERRIDE {
    DCHECK_EQ(view_manager_, view_manager);
    view_manager_ = NULL;
    base::MessageLoop::current()->Quit();
  }

  // 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();
    }
  }

  // ViewObserver:
  virtual void OnViewBoundsChanged(View* view,
                                   const gfx::Rect& old_bounds,
                                   const gfx::Rect& new_bounds) OVERRIDE {
    LayoutViews();
  }
  virtual void OnViewDestroyed(View* view) OVERRIDE {
    DCHECK_EQ(view, root_view_);
    view->RemoveObserver(this);
    root_view_ = NULL;
  }

  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();
  }

  scoped_ptr<ViewManagerClientFactory> view_manager_client_factory_;

  ApplicationImpl* app_;
  scoped_ptr<ViewsInit> views_init_;
  ViewManager* view_manager_;
  View* root_view_;
  View* control_view_;
  View* content_view_;
  ControlPanel control_panel_;
  ZoomableMediaPtr zoomable_media_;
  HandlerMap handler_map_;

  DISALLOW_COPY_AND_ASSIGN(MediaViewer);
};

}  // namespace examples
}  // namespace mojo

MojoResult MojoMain(MojoHandle shell_handle) {
  mojo::ApplicationRunnerChromium runner(new mojo::examples::MediaViewer);
  return runner.Run(shell_handle);
}