summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--views/examples/examples_main.cc5
-rw-r--r--views/examples/native_theme_button_example.cc274
-rw-r--r--views/examples/native_theme_button_example.h92
-rw-r--r--views/native_theme_painter.cc53
-rw-r--r--views/native_theme_painter.h79
-rw-r--r--views/views.gyp4
6 files changed, 507 insertions, 0 deletions
diff --git a/views/examples/examples_main.cc b/views/examples/examples_main.cc
index 0ab98f6..1326672 100644
--- a/views/examples/examples_main.cc
+++ b/views/examples/examples_main.cc
@@ -18,6 +18,7 @@
#include "views/examples/combobox_example.h"
#include "views/examples/menu_example.h"
#include "views/examples/message_box_example.h"
+#include "views/examples/native_theme_button_example.h"
#include "views/examples/radio_button_example.h"
#include "views/examples/scroll_view_example.h"
#include "views/examples/single_split_view_example.h"
@@ -101,6 +102,10 @@ void ExamplesMain::Run() {
views::Window* window =
views::Window::CreateChromeWindow(NULL, gfx::Rect(0, 0, 850, 300), this);
+ examples::NativeThemeButtonExample native_theme_button_example(this);
+ tabbed_pane->AddTab(native_theme_button_example.GetExampleTitle(),
+ native_theme_button_example.GetExampleView());
+
examples::TextfieldExample textfield_example(this);
tabbed_pane->AddTab(textfield_example.GetExampleTitle(),
textfield_example.GetExampleView());
diff --git a/views/examples/native_theme_button_example.cc b/views/examples/native_theme_button_example.cc
new file mode 100644
index 0000000..23e4ad8
--- /dev/null
+++ b/views/examples/native_theme_button_example.cc
@@ -0,0 +1,274 @@
+// Copyright (c) 2011 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 "views/examples/native_theme_button_example.h"
+
+#include "base/logging.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
+#include "ui/base/animation/throb_animation.h"
+#include "ui/base/models/combobox_model.h"
+#include "ui/gfx/canvas.h"
+#include "views/controls/label.h"
+#include "views/native_theme_painter.h"
+#include "views/layout/grid_layout.h"
+
+namespace {
+
+class ExampleComboboxModel : public ui::ComboboxModel {
+ public:
+ ExampleComboboxModel(const wchar_t** strings, int count)
+ : strings_(strings), count_(count) {
+ }
+
+ ~ExampleComboboxModel() {
+ }
+
+ void set_data(const wchar_t** strings, int count) {
+ strings_ = strings;
+ count_ = count;
+ }
+
+ // Overridden from ui::ComboboxModel:
+ virtual int GetItemCount() OVERRIDE {
+ return count_;
+ }
+ virtual string16 GetItemAt(int index) OVERRIDE {
+ return WideToUTF16Hack(strings_[index]);
+ }
+
+ private:
+ const wchar_t** strings_;
+ int count_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExampleComboboxModel);
+};
+
+const wchar_t* kParts[] = {
+ L"PushButton",
+ L"RadioButton",
+ L"Checkbox",
+};
+
+const wchar_t* kStates[] = {
+ L"Disabled",
+ L"Normal",
+ L"Hot",
+ L"Pressed",
+ L"<Dynamic>",
+};
+
+} // anonymous namespace
+
+namespace examples {
+
+ExampleNativeThemeButton::ExampleNativeThemeButton(
+ views::ButtonListener* listener,
+ views::Combobox* cb_part,
+ views::Combobox* cb_state)
+ : CustomButton(listener),
+ cb_part_(cb_part),
+ cb_state_(cb_state),
+ count_(0),
+ is_checked_(false),
+ is_indeterminate_(false) {
+ cb_part_->set_listener(this);
+ cb_state_->set_listener(this);
+
+ painter_.reset(new views::NativeThemePainter(this));
+ set_background(views::Background::CreateBackgroundPainter(
+ false, painter_.get()));
+}
+
+ExampleNativeThemeButton::~ExampleNativeThemeButton() {
+}
+
+std::wstring ExampleNativeThemeButton::MessWithState() {
+ const wchar_t* message;
+ switch(GetThemePart()) {
+ case gfx::NativeTheme::kPushButton:
+ message = L"Pressed! count:%d";
+ break;
+ case gfx::NativeTheme::kRadio:
+ is_checked_ = !is_checked_;
+ message = is_checked_ ? L"Checked! count:%d" : L"Unchecked! count:%d";
+ break;
+ case gfx::NativeTheme::kCheckbox:
+ if (is_indeterminate_) {
+ is_checked_ = false;
+ is_indeterminate_ = false;
+ } else if (!is_checked_) {
+ is_checked_ = true;
+ } else {
+ is_checked_ = false;
+ is_indeterminate_ = true;
+ }
+
+ message = is_checked_ ? L"Checked! count:%d" :
+ is_indeterminate_ ? L"Indeterminate! count:%d" : L"Unchecked! count:%d";
+ break;
+ default:
+ DCHECK(false);
+ }
+
+ return base::StringPrintf(message, ++count_);
+}
+
+void ExampleNativeThemeButton::ItemChanged(views::Combobox* combo_box,
+ int prev_index,
+ int new_index) {
+ SchedulePaint();
+}
+
+gfx::NativeTheme::Part ExampleNativeThemeButton::GetThemePart() const {
+ int selected = cb_part_->selected_item();
+ switch(selected) {
+ case 0:
+ return gfx::NativeTheme::kPushButton;
+ case 1:
+ return gfx::NativeTheme::kRadio;
+ case 2:
+ return gfx::NativeTheme::kCheckbox;
+ default:
+ DCHECK(false);
+ }
+ return gfx::NativeTheme::kPushButton;
+}
+
+gfx::NativeTheme::State ExampleNativeThemeButton::GetThemeState(
+ gfx::NativeTheme::ExtraParams* params) const {
+ GetExtraParams(params);
+
+ int selected = cb_state_->selected_item();
+ if (selected > 3) {
+ switch(state()) {
+ case BS_DISABLED:
+ return gfx::NativeTheme::kDisabled;
+ case BS_NORMAL:
+ return gfx::NativeTheme::kNormal;
+ case BS_HOT:
+ return gfx::NativeTheme::kHovered;
+ case BS_PUSHED:
+ return gfx::NativeTheme::kPressed;
+ default:
+ DCHECK(false);
+ }
+ }
+
+ switch(selected) {
+ case 0:
+ return gfx::NativeTheme::kDisabled;
+ case 1:
+ return gfx::NativeTheme::kNormal;
+ case 2:
+ return gfx::NativeTheme::kHovered;
+ case 3:
+ return gfx::NativeTheme::kPressed;
+ default:
+ DCHECK(false);
+ }
+ return gfx::NativeTheme::kNormal;
+}
+
+void ExampleNativeThemeButton::GetExtraParams(
+ gfx::NativeTheme::ExtraParams* params) const {
+
+ params->button.checked = is_checked_;
+ params->button.indeterminate = is_indeterminate_;
+ params->button.is_default = false;
+ params->button.has_border = false;
+ params->button.classic_state = 0;
+ params->button.background_color = SkColorSetARGB(0, 0, 0, 0);
+}
+
+ui::Animation* ExampleNativeThemeButton::GetThemeAnimation() const {
+ int selected = cb_state_->selected_item();
+ return selected <= 3 ? NULL : hover_animation_.get();
+}
+
+gfx::NativeTheme::State ExampleNativeThemeButton::GetBackgroundThemeState(
+ gfx::NativeTheme::ExtraParams* params) const {
+ GetExtraParams(params);
+ return gfx::NativeTheme::kNormal;
+}
+
+gfx::NativeTheme::State ExampleNativeThemeButton::GetForegroundThemeState(
+ gfx::NativeTheme::ExtraParams* params) const {
+ GetExtraParams(params);
+ return gfx::NativeTheme::kHovered;
+}
+
+gfx::Size ExampleNativeThemeButton::GetPreferredSize() {
+ return painter_.get() == NULL ? gfx::Size() : painter_->GetPreferredSize();
+}
+
+void ExampleNativeThemeButton::OnPaintBackground(gfx::Canvas* canvas) {
+ // Fill the background with a known colour so that we know where the bounds
+ // of the View are.
+ canvas->FillRectInt(SkColorSetRGB(255, 128, 128), 0, 0, width(), height());
+ CustomButton::OnPaintBackground(canvas);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+NativeThemeButtonExample::NativeThemeButtonExample(ExamplesMain* main)
+ : ExampleBase(main) {
+}
+
+NativeThemeButtonExample::~NativeThemeButtonExample() {
+}
+
+std::wstring NativeThemeButtonExample::GetExampleTitle() {
+ return L"Native Theme Button";
+}
+
+void NativeThemeButtonExample::CreateExampleView(views::View* container) {
+ views::GridLayout* layout = new views::GridLayout(container);
+ container->SetLayoutManager(layout);
+
+ layout->AddPaddingRow(0, 8);
+
+ views::ColumnSet* column_set = layout->AddColumnSet(0);
+ column_set->AddPaddingColumn(0, 8);
+ column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL,
+ 0.1f, views::GridLayout::USE_PREF, 0, 0);
+ column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
+ 0.9f, views::GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(0, 8);
+
+ layout->StartRow(0, 0);
+ layout->AddView(new views::Label(L"Part:"));
+ views::Combobox* cb_part = new views::Combobox(
+ new ExampleComboboxModel(kParts, arraysize(kParts)));
+ cb_part->SetSelectedItem(0);
+ layout->AddView(cb_part);
+
+ layout->StartRow(0, 0);
+ layout->AddView(new views::Label(L"State:"));
+ views::Combobox* cb_state = new views::Combobox(
+ new ExampleComboboxModel(kStates, arraysize(kStates)));
+ cb_state->SetSelectedItem(0);
+ layout->AddView(cb_state);
+
+ layout->AddPaddingRow(0, 32);
+
+ button_ = new ExampleNativeThemeButton(this, cb_part, cb_state);
+
+ column_set = layout->AddColumnSet(1);
+ column_set->AddPaddingColumn(0, 16);
+ column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
+ 1, views::GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(0, 16);
+ layout->StartRow(1, 1);
+ layout->AddView(button_);
+
+ layout->AddPaddingRow(0, 8);
+}
+
+void NativeThemeButtonExample::ButtonPressed(views::Button* sender,
+ const views::Event& event) {
+ PrintStatus(button_->MessWithState().c_str());
+}
+
+} // namespace examples
diff --git a/views/examples/native_theme_button_example.h b/views/examples/native_theme_button_example.h
new file mode 100644
index 0000000..9ca7c33
--- /dev/null
+++ b/views/examples/native_theme_button_example.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2011 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.
+
+#ifndef VIEWS_EXAMPLES_NATIVE_THEME_BUTTON_EXAMPLE_H_
+#define VIEWS_EXAMPLES_NATIVE_THEME_BUTTON_EXAMPLE_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "ui/gfx/native_theme.h"
+#include "views/controls/button/custom_button.h"
+#include "views/controls/combobox/combobox.h"
+#include "views/examples/example_base.h"
+#include "views/native_theme_painter.h"
+
+namespace views {
+class Combobox;
+class NativeThemePainter;
+}
+
+namespace examples {
+
+// A subclass of button to test native theme rendering.
+class ExampleNativeThemeButton : public views::CustomButton,
+ public views::NativeThemePainter::Delegate,
+ public views::Combobox::Listener {
+ public:
+ ExampleNativeThemeButton(views::ButtonListener* listener,
+ views::Combobox* cb_part,
+ views::Combobox* cb_state);
+ ~ExampleNativeThemeButton();
+
+ std::wstring MessWithState();
+
+ private:
+ // Overridden from View:
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE;
+
+ // Overridden from views::Combobox::Listener:
+ virtual void ItemChanged(views::Combobox* combo_box,
+ int prev_index,
+ int new_index) OVERRIDE;
+
+ // Overridden from views::NativeThemePainter::Delegate:
+ virtual gfx::NativeTheme::Part GetThemePart() const OVERRIDE;
+ virtual gfx::NativeTheme::State GetThemeState(
+ gfx::NativeTheme::ExtraParams* params) const OVERRIDE;
+ virtual ui::Animation* GetThemeAnimation() const OVERRIDE;
+ virtual gfx::NativeTheme::State GetBackgroundThemeState(
+ gfx::NativeTheme::ExtraParams* params) const OVERRIDE;
+ virtual gfx::NativeTheme::State GetForegroundThemeState(
+ gfx::NativeTheme::ExtraParams* params) const OVERRIDE;
+
+ void GetExtraParams(gfx::NativeTheme::ExtraParams* params) const;
+
+ scoped_ptr<views::NativeThemePainter> painter_;
+ views::Combobox* cb_part_;
+ views::Combobox* cb_state_;
+ int count_;
+ bool is_checked_;
+ bool is_indeterminate_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExampleNativeThemeButton);
+};
+
+// NativeThemeButtonExample shows how a View can use the NativeThemePainter
+// to paints its background and get a native look.
+class NativeThemeButtonExample : public ExampleBase,
+ public views::ButtonListener {
+ public:
+ explicit NativeThemeButtonExample(ExamplesMain* main);
+ virtual ~NativeThemeButtonExample();
+
+ // Overridden from ExampleBase:
+ virtual std::wstring GetExampleTitle() OVERRIDE;
+ virtual void CreateExampleView(views::View* container) OVERRIDE;
+
+ private:
+ // Overridden from views::ButtonListener:
+ virtual void ButtonPressed(views::Button* sender,
+ const views::Event& event) OVERRIDE;
+
+ // The only control in this test.
+ ExampleNativeThemeButton* button_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeThemeButtonExample);
+};
+
+} // namespace examples
+
+#endif // VIEWS_EXAMPLES_NATIVE_THEME_BUTTON_EXAMPLE_H_
diff --git a/views/native_theme_painter.cc b/views/native_theme_painter.cc
new file mode 100644
index 0000000..7806f33
--- /dev/null
+++ b/views/native_theme_painter.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 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 "views/native_theme_painter.h"
+
+#include "base/logging.h"
+#include "ui/base/animation/animation.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/canvas_skia.h"
+#include "ui/gfx/rect.h"
+
+namespace views {
+
+NativeThemePainter::NativeThemePainter(Delegate* delegate)
+ : delegate_(delegate) {
+ DCHECK(delegate_);
+}
+
+gfx::Size NativeThemePainter::GetPreferredSize() {
+ const gfx::NativeTheme* theme = gfx::NativeTheme::instance();
+ return theme->GetPartSize(delegate_->GetThemePart());
+}
+
+void NativeThemePainter::Paint(int w, int h, gfx::Canvas* canvas) {
+ const gfx::NativeTheme* native_theme = gfx::NativeTheme::instance();
+ gfx::NativeTheme::Part part = delegate_->GetThemePart();
+ gfx::CanvasSkia* skia_canvas = canvas->AsCanvasSkia();
+ gfx::Rect rect(0, 0, w, h);
+
+ if (delegate_->GetThemeAnimation() != NULL &&
+ delegate_->GetThemeAnimation()->is_animating()) {
+ // Paint background state.
+ gfx::NativeTheme::ExtraParams prev_extra;
+ gfx::NativeTheme::State prev_state =
+ delegate_->GetBackgroundThemeState(&prev_extra);
+ native_theme->Paint(skia_canvas, part, prev_state, rect, prev_extra);
+
+ // Composite foreground state above it.
+ gfx::NativeTheme::ExtraParams extra;
+ gfx::NativeTheme::State state = delegate_->GetForegroundThemeState(&extra);
+ int alpha = delegate_->GetThemeAnimation()->CurrentValueBetween(0, 255);
+ skia_canvas->SaveLayerAlpha(static_cast<uint8>(alpha));
+ native_theme->Paint(skia_canvas, part, state, rect, extra);
+ skia_canvas->Restore();
+ } else {
+ gfx::NativeTheme::ExtraParams extra;
+ gfx::NativeTheme::State state = delegate_->GetThemeState(&extra);
+ native_theme->Paint(skia_canvas, part, state, rect, extra);
+ }
+}
+
+} // namespace views
diff --git a/views/native_theme_painter.h b/views/native_theme_painter.h
new file mode 100644
index 0000000..55dad89
--- /dev/null
+++ b/views/native_theme_painter.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2011 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.
+
+#ifndef VIEWS_NATIVE_THEME_PAINTER_H_
+#define VIEWS_NATIVE_THEME_PAINTER_H_
+#pragma once
+
+#include "base/compiler_specific.h"
+#include "ui/gfx/native_theme.h"
+#include "views/painter.h"
+
+namespace gfx {
+class Canvas;
+class Size;
+}
+
+namespace ui {
+class Animation;
+}
+
+namespace views {
+
+// A Painter that uses NativeTheme to implement painting and sizing. A
+// theme delegate must be given at construction time so that the appropriate
+// painting and sizing can be done.
+class NativeThemePainter : public Painter {
+ public:
+ // A delagate that supports animating transtions between different native
+ // theme states. If animation is onging, the native theme painter will
+ // composite the foreground state over the backgroud state using an alpha
+ // between 0 and 255 based on the current value of the animation.
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+
+ // Get the part that this native theme painter should draw.
+ virtual gfx::NativeTheme::Part GetThemePart() const = 0;
+
+ // Get the state of the part, along with any extra data needed for painting.
+ virtual gfx::NativeTheme::State GetThemeState(
+ gfx::NativeTheme::ExtraParams* params) const = 0;
+
+ // If the native theme painter is animated, return the Animation object
+ // that is controlling it. If no animation is ongoing, NULL may be
+ // returned.
+ virtual ui::Animation* GetThemeAnimation() const = 0;
+
+ // If animation is onging, this returns the background native theme state.
+ virtual gfx::NativeTheme::State GetBackgroundThemeState(
+ gfx::NativeTheme::ExtraParams* params) const = 0;
+
+ // If animation is onging, this returns the foreground native theme state.
+ // This state will be composited over the background using an alpha value
+ // based on the current value of the animation.
+ virtual gfx::NativeTheme::State GetForegroundThemeState(
+ gfx::NativeTheme::ExtraParams* params) const = 0;
+ };
+
+ explicit NativeThemePainter(Delegate* delegate);
+
+ virtual ~NativeThemePainter() {}
+
+ // Returns the preferred size of the native part being painted.
+ gfx::Size GetPreferredSize();
+
+ private:
+ // The delegate the controls the appearance of this painter.
+ Delegate* delegate_;
+
+ // Overridden from Painter:
+ virtual void Paint(int w, int h, gfx::Canvas* canvas) OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeThemePainter);
+};
+
+} // namespace views
+
+#endif // VIEWS_NATIVE_THEME_PAINTER_H_
diff --git a/views/views.gyp b/views/views.gyp
index c7fac12..deca1c4 100644
--- a/views/views.gyp
+++ b/views/views.gyp
@@ -311,6 +311,8 @@
'metrics_win.cc',
'mouse_watcher.cc',
'mouse_watcher.h',
+ 'native_theme_painter.cc',
+ 'native_theme_painter.h',
'painter.cc',
'painter.h',
'repeat_controller.cc',
@@ -587,6 +589,8 @@
'examples/message_box_example.h',
'examples/menu_example.cc',
'examples/menu_example.h',
+ 'examples/native_theme_button_example.cc',
+ 'examples/native_theme_button_example.h',
'examples/radio_button_example.cc',
'examples/radio_button_example.h',
'examples/scroll_view_example.cc',