summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--views/controls/button/checkbox.cc100
-rw-r--r--views/controls/button/checkbox.h55
-rw-r--r--views/controls/button/radio_button.cc90
-rw-r--r--views/controls/button/radio_button.h31
-rw-r--r--views/controls/button/text_button.cc505
-rw-r--r--views/controls/button/text_button.h191
-rw-r--r--views/examples/button_example.cc62
-rw-r--r--views/examples/button_example.h5
-rw-r--r--views/examples/examples_main.cc5
-rw-r--r--views/examples/native_theme_button_example.cc6
-rw-r--r--views/examples/native_theme_button_example.h6
-rw-r--r--views/examples/native_theme_checkbox_example.cc39
-rw-r--r--views/examples/native_theme_checkbox_example.h46
-rw-r--r--views/examples/radio_button_example.cc33
-rw-r--r--views/examples/radio_button_example.h6
-rw-r--r--views/native_theme_delegate.h52
-rw-r--r--views/native_theme_painter.cc3
-rw-r--r--views/native_theme_painter.h38
-rw-r--r--views/views.gyp4
19 files changed, 1033 insertions, 244 deletions
diff --git a/views/controls/button/checkbox.cc b/views/controls/button/checkbox.cc
index 3425c98..45d0501 100644
--- a/views/controls/button/checkbox.cc
+++ b/views/controls/button/checkbox.cc
@@ -14,6 +14,9 @@ namespace views {
// static
const char Checkbox::kViewClassName[] = "views/Checkbox";
+// static
+const char CheckboxNt::kViewClassName[] = "views/CheckboxNt";
+
static const int kCheckboxLabelSpacing = 4;
static const int kLabelFocusPaddingHorizontal = 2;
static const int kLabelFocusPaddingVertical = 1;
@@ -218,4 +221,101 @@ void Checkbox::Init(const std::wstring& label_text) {
AddChildView(label_);
}
+////////////////////////////////////////////////////////////////////////////////
+// CheckboxNt, public:
+
+CheckboxNt::CheckboxNt(const std::wstring& label)
+ : TextButtonBase(NULL, label),
+ checked_(false) {
+ set_border(new TextButtonNativeThemeBorder(this));
+}
+
+CheckboxNt::~CheckboxNt() {
+}
+
+void CheckboxNt::SetChecked(bool checked) {
+ checked_ = checked;
+ SchedulePaint();
+}
+
+void CheckboxNt::SetMultiLine(bool multiline) {
+ NOTREACHED() << "Not yet implemented";
+}
+
+gfx::Size CheckboxNt::GetPreferredSize() {
+ gfx::Size prefsize(TextButtonBase::GetPreferredSize());
+ gfx::NativeTheme::ExtraParams extra;
+ gfx::NativeTheme::State state = GetThemeState(&extra);
+ gfx::Size size = gfx::NativeTheme::instance()->GetPartSize(GetThemePart(),
+ state,
+ extra);
+ prefsize.Enlarge(size.width(), 0);
+ prefsize.set_height(std::max(prefsize.height(), size.height()));
+
+ if (max_width_ > 0)
+ prefsize.set_width(std::min(max_width_, prefsize.width()));
+
+ return prefsize;
+}
+
+std::string CheckboxNt::GetClassName() const {
+ return kViewClassName;
+}
+
+void CheckboxNt::GetAccessibleState(ui::AccessibleViewState* state) {
+ TextButtonBase::GetAccessibleState(state);
+ state->role = ui::AccessibilityTypes::ROLE_CHECKBUTTON;
+ state->state = checked() ? ui::AccessibilityTypes::STATE_CHECKED : 0;
+}
+
+void CheckboxNt::OnPaintFocusBorder(gfx::Canvas* canvas) {
+ if (HasFocus() && (IsFocusable() || IsAccessibilityFocusableInRootView())) {
+ gfx::Rect bounds(GetTextBounds());
+ // Increate the bounding box by one on each side so that that focus border
+ // does not draw on top of the letters.
+ bounds.Inset(-1, -1, -1, -1);
+ canvas->DrawFocusRect(bounds.x(), bounds.y(), bounds.width(),
+ bounds.height());
+ }
+}
+
+void CheckboxNt::NotifyClick(const views::Event& event) {
+ SetChecked(!checked());
+ RequestFocus();
+ TextButtonBase::NotifyClick(event);
+}
+
+gfx::NativeTheme::Part CheckboxNt::GetThemePart() const {
+ return gfx::NativeTheme::kCheckbox;
+}
+
+gfx::Rect CheckboxNt::GetThemePaintRect() const {
+ gfx::NativeTheme::ExtraParams extra;
+ gfx::NativeTheme::State state = GetThemeState(&extra);
+ gfx::Size size(gfx::NativeTheme::instance()->GetPartSize(GetThemePart(),
+ state,
+ extra));
+ gfx::Insets insets = GetInsets();
+ gfx::Rect rect(insets.left(), 0, size.width(), height());
+ rect.set_x(GetMirroredXForRect(rect));
+ return rect;
+}
+
+void CheckboxNt::GetExtraParams(gfx::NativeTheme::ExtraParams* params) const {
+ TextButtonBase::GetExtraParams(params);
+ params->button.is_default = false;
+ params->button.checked = checked_;
+}
+
+gfx::Rect CheckboxNt::GetTextBounds() const {
+ gfx::Rect bounds(TextButtonBase::GetTextBounds());
+ gfx::NativeTheme::ExtraParams extra;
+ gfx::NativeTheme::State state = GetThemeState(&extra);
+ gfx::Size size(gfx::NativeTheme::instance()->GetPartSize(GetThemePart(),
+ state,
+ extra));
+ bounds.Offset(size.width() + kCheckboxLabelSpacing, 0);
+ return bounds;
+}
+
} // namespace views
diff --git a/views/controls/button/checkbox.h b/views/controls/button/checkbox.h
index e251406..8d30a33 100644
--- a/views/controls/button/checkbox.h
+++ b/views/controls/button/checkbox.h
@@ -9,6 +9,7 @@
#include <string>
#include "views/controls/button/native_button.h"
+#include "views/controls/button/text_button.h"
namespace views {
@@ -87,6 +88,60 @@ class Checkbox : public NativeButtonBase {
DISALLOW_COPY_AND_ASSIGN(Checkbox);
};
+// A native themed class representing a checkbox. This class does not use
+// platform specific objects to replicate the native platforms looks and feel.
+//
+// This class will eventually be renamed to Checkbox to replace the class
+// above.
+//
+// TODO: A Checkbox feature not support by CheckboxNt is multi-line.
+class CheckboxNt : public TextButtonBase {
+ public:
+ explicit CheckboxNt(const std::wstring& label);
+ virtual ~CheckboxNt();
+
+ // Sets a listener for this checkbox. Checkboxes aren't required to have them
+ // since their state can be read independently of them being toggled.
+ void set_listener(ButtonListener* listener) { listener_ = listener; }
+
+ // Sets/Gets whether or not the checkbox is checked.
+ virtual void SetChecked(bool checked);
+ bool checked() const { return checked_; }
+
+ // Sets whether or not the checkbox label should wrap multiple lines of text.
+ // If true, long lines are wrapped, and this is reflected in the preferred
+ // size returned by GetPreferredSize. If false, text that will not fit within
+ // the available bounds for the label will be cropped.
+ // TODO: not yet implemented.
+ void SetMultiLine(bool multiline);
+
+ protected:
+ // Overridden from View:
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual std::string GetClassName() const OVERRIDE;
+ virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ void OnPaintFocusBorder(gfx::Canvas* canvas) OVERRIDE;
+
+ private:
+ // Overridden from Button:
+ virtual void NotifyClick(const views::Event& event) OVERRIDE;
+
+ // Overridden from TextButtonBase:
+ virtual gfx::NativeTheme::Part GetThemePart() const OVERRIDE;
+ virtual gfx::Rect GetThemePaintRect() const OVERRIDE;
+ virtual void GetExtraParams(
+ gfx::NativeTheme::ExtraParams* params) const OVERRIDE;
+ virtual gfx::Rect GetTextBounds() const OVERRIDE;
+
+ // True if the checkbox is checked.
+ bool checked_;
+
+ // The button's class name.
+ static const char kViewClassName[];
+
+ DISALLOW_COPY_AND_ASSIGN(CheckboxNt);
+};
+
} // namespace views
#endif // VIEWS_CONTROLS_BUTTON_CHECKBOX_H_
diff --git a/views/controls/button/radio_button.cc b/views/controls/button/radio_button.cc
index a6e3f19..a5292eb 100644
--- a/views/controls/button/radio_button.cc
+++ b/views/controls/button/radio_button.cc
@@ -13,6 +13,9 @@ namespace views {
// static
const char RadioButton::kViewClassName[] = "views/RadioButton";
+// static
+const char RadioButtonNt::kViewClassName[] = "views/RadioButtonNt";
+
////////////////////////////////////////////////////////////////////////////////
// RadioButton, public:
@@ -112,4 +115,91 @@ NativeButtonWrapper* RadioButton::CreateWrapper() {
return NativeButtonWrapper::CreateRadioButtonWrapper(this);
}
+////////////////////////////////////////////////////////////////////////////////
+//
+// RadioButtonNt
+//
+////////////////////////////////////////////////////////////////////////////////
+
+RadioButtonNt::RadioButtonNt(const std::wstring& label, int group_id)
+ : CheckboxNt(label) {
+ SetGroup(group_id);
+}
+
+RadioButtonNt::~RadioButtonNt() {
+}
+
+void RadioButtonNt::SetChecked(bool checked) {
+ if (checked == RadioButtonNt::checked())
+ return;
+ if (checked) {
+ // We can't just get the root view here because sometimes the radio
+ // button isn't attached to a root view (e.g., if it's part of a tab page
+ // that is currently not active).
+ View* container = parent();
+ while (container && container->parent())
+ container = container->parent();
+ if (container) {
+ std::vector<View*> other;
+ container->GetViewsWithGroup(GetGroup(), &other);
+ std::vector<View*>::iterator i;
+ for (i = other.begin(); i != other.end(); ++i) {
+ if (*i != this) {
+ if ((*i)->GetClassName() != kViewClassName) {
+ NOTREACHED() << "radio-button-nt has same group as other non "
+ "radio-button-nt views.";
+ continue;
+ }
+ RadioButtonNt* peer = static_cast<RadioButtonNt*>(*i);
+ peer->SetChecked(false);
+ }
+ }
+ }
+ }
+ CheckboxNt::SetChecked(checked);
+}
+
+std::string RadioButtonNt::GetClassName() const {
+ return kViewClassName;
+}
+
+void RadioButtonNt::GetAccessibleState(ui::AccessibleViewState* state) {
+ CheckboxNt::GetAccessibleState(state);
+ state->role = ui::AccessibilityTypes::ROLE_RADIOBUTTON;
+}
+
+View* RadioButtonNt::GetSelectedViewForGroup(int group_id) {
+ std::vector<View*> views;
+ GetRootView()->GetViewsWithGroup(group_id, &views);
+ if (views.empty())
+ return NULL;
+
+ for (std::vector<View*>::const_iterator iter = views.begin();
+ iter != views.end(); ++iter) {
+ // REVIEW: why don't we check the runtime type like is done above?
+ RadioButtonNt* radio_button = static_cast<RadioButtonNt*>(*iter);
+ if (radio_button->checked())
+ return radio_button;
+ }
+ return NULL;
+}
+
+bool RadioButtonNt::IsGroupFocusTraversable() const {
+ // When focusing a radio button with tab/shift+tab, only the selected button
+ // from the group should be focused.
+ return false;
+}
+
+void RadioButtonNt::NotifyClick(const views::Event& event) {
+ // Set the checked state to true only if we are unchecked, since we can't
+ // be toggled on and off like a checkbox.
+ if (!checked())
+ SetChecked(true);
+ RequestFocus();
+}
+
+gfx::NativeTheme::Part RadioButtonNt::GetThemePart() const {
+ return gfx::NativeTheme::kRadio;
+}
+
} // namespace views
diff --git a/views/controls/button/radio_button.h b/views/controls/button/radio_button.h
index 7df8387..c922558 100644
--- a/views/controls/button/radio_button.h
+++ b/views/controls/button/radio_button.h
@@ -46,6 +46,37 @@ class RadioButton : public Checkbox {
DISALLOW_COPY_AND_ASSIGN(RadioButton);
};
+// A native themed class representing a radio button. This class does not use
+// platform specific objects to replicate the native platforms looks and feel.
+//
+// This class will eventually be renamed to RadioButton to replace the class
+// above.
+class RadioButtonNt : public CheckboxNt {
+ public:
+ // The button's class name.
+ static const char kViewClassName[];
+
+ RadioButtonNt(const std::wstring& label, int group_id);
+ virtual ~RadioButtonNt();
+
+ // Overridden from View:
+ virtual std::string GetClassName() const OVERRIDE;
+ virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual View* GetSelectedViewForGroup(int group_id) OVERRIDE;
+ virtual bool IsGroupFocusTraversable() const OVERRIDE;
+
+ // Overridden from Button:
+ virtual void NotifyClick(const views::Event& event) OVERRIDE;
+
+ // Overridden from TextButtonBase:
+ virtual gfx::NativeTheme::Part GetThemePart() const OVERRIDE;
+
+ // Overridden from CheckboxNt:
+ virtual void SetChecked(bool checked) OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(RadioButtonNt);
+};
+
} // namespace views
#endif // VIEWS_CONTROLS_BUTTON_RADIO_BUTTON_H_
diff --git a/views/controls/button/text_button.cc b/views/controls/button/text_button.cc
index b8e8d72..c5fbdcb 100644
--- a/views/controls/button/text_button.cc
+++ b/views/controls/button/text_button.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -8,13 +8,13 @@
#include "base/logging.h"
#include "base/utf_string_conversions.h"
+#include "grit/app_resources.h"
#include "ui/base/animation/throb_animation.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas_skia.h"
#include "views/controls/button/button.h"
#include "views/events/event.h"
#include "views/widget/widget.h"
-#include "grit/app_resources.h"
namespace views {
@@ -26,18 +26,21 @@ static const int kPreferredPaddingHorizontal = 6;
static const int kPreferredPaddingVertical = 5;
// static
-const SkColor TextButton::kEnabledColor = SkColorSetRGB(6, 45, 117);
+const SkColor TextButtonBase::kEnabledColor = SkColorSetRGB(6, 45, 117);
// static
-const SkColor TextButton::kHighlightColor = SkColorSetARGB(200, 255, 255, 255);
+const SkColor TextButtonBase::kHighlightColor =
+ SkColorSetARGB(200, 255, 255, 255);
// static
-const SkColor TextButton::kDisabledColor = SkColorSetRGB(161, 161, 146);
+const SkColor TextButtonBase::kDisabledColor = SkColorSetRGB(161, 161, 146);
// static
-const SkColor TextButton::kHoverColor = TextButton::kEnabledColor;
+const SkColor TextButtonBase::kHoverColor = TextButton::kEnabledColor;
// How long the hover fade animation should last.
static const int kHoverAnimationDurationMs = 170;
// static
+const char TextButtonBase::kViewClassName[] = "views/TextButtonBase";
+// static
const char TextButton::kViewClassName[] = "views/TextButton";
static int PrefixTypeToCanvasType(TextButton::PrefixType type) {
@@ -93,9 +96,8 @@ TextButtonBorder::~TextButtonBorder() {
// TextButtonBorder - painting
//
////////////////////////////////////////////////////////////////////////////////
-
void TextButtonBorder::Paint(const View& view, gfx::Canvas* canvas) const {
- const TextButton* mb = static_cast<const TextButton*>(&view);
+ const TextButtonBase* mb = static_cast<const TextButton*>(&view);
int state = mb->state();
// TextButton takes care of deciding when to call Paint.
@@ -103,10 +105,24 @@ void TextButtonBorder::Paint(const View& view, gfx::Canvas* canvas) const {
if (state == TextButton::BS_PUSHED)
set = &pushed_set_;
- if (set) {
+ bool is_animating = mb->GetAnimation()->is_animating();
+ bool show_mult_icons = mb->show_multiple_icon_states();
+ bool do_paint = (show_mult_icons && is_animating) ||
+ (show_mult_icons && (state == TextButton::BS_HOT ||
+ state == TextButton::BS_PUSHED)) ||
+ (state == TextButton::BS_NORMAL && mb->normal_has_border());
+ if (set && do_paint) {
+ if (is_animating) {
+ canvas->SaveLayerAlpha(
+ static_cast<uint8>(mb->GetAnimation()->CurrentValueBetween(0, 255)));
+ canvas->AsCanvasSkia()->drawARGB(0, 255, 255, 255,
+ SkXfermode::kClear_Mode);
+ }
+
Paint(view, canvas, *set);
- } else {
- // Do nothing
+
+ if (is_animating)
+ canvas->Restore();
}
}
@@ -180,12 +196,63 @@ void TextButtonBorder::GetInsets(gfx::Insets* insets) const {
}
////////////////////////////////////////////////////////////////////////////////
-// TextButton, public:
+//
+// TextButtonNativeThemeBorder
+//
+////////////////////////////////////////////////////////////////////////////////
+
+TextButtonNativeThemeBorder::TextButtonNativeThemeBorder(
+ NativeThemeDelegate* delegate)
+ : delegate_(delegate) {
+}
+
+TextButtonNativeThemeBorder::~TextButtonNativeThemeBorder() {
+}
+
+void TextButtonNativeThemeBorder::Paint(const View& view,
+ gfx::Canvas* canvas) const {
+ const TextButtonBase* tb = static_cast<const TextButton*>(&view);
+ const gfx::NativeTheme* native_theme = gfx::NativeTheme::instance();
+ gfx::NativeTheme::Part part = delegate_->GetThemePart();
+ gfx::CanvasSkia* skia_canvas = canvas->AsCanvasSkia();
+ gfx::Rect rect(delegate_->GetThemePaintRect());
+
+ if (tb->show_multiple_icon_states() &&
+ 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);
+ }
+}
+
+void TextButtonNativeThemeBorder::GetInsets(gfx::Insets* insets) const {
+ insets->Set(kPreferredPaddingVertical, kPreferredPaddingHorizontal,
+ kPreferredPaddingVertical, kPreferredPaddingHorizontal);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// TextButtonBase, public:
-TextButton::TextButton(ButtonListener* listener, const std::wstring& text)
+TextButtonBase::TextButtonBase(ButtonListener* listener,
+ const std::wstring& text)
: CustomButton(listener),
alignment_(ALIGN_LEFT),
- icon_placement_(ICON_ON_LEFT),
font_(ResourceBundle::GetSharedInstance().GetFont(
ResourceBundle::BaseFont)),
color_(kEnabledColor),
@@ -198,153 +265,171 @@ TextButton::TextButton(ButtonListener* listener, const std::wstring& text)
active_text_shadow_color_(0),
inactive_text_shadow_color_(0),
has_shadow_(false),
- has_hover_icon_(false),
- has_pushed_icon_(false),
max_width_(0),
normal_has_border_(false),
show_multiple_icon_states_(true),
- prefix_type_(PREFIX_NONE),
- icon_text_spacing_(kDefaultIconTextSpacing) {
+ is_default_(false),
+ prefix_type_(PREFIX_NONE) {
SetText(text);
- set_border(new TextButtonBorder);
SetAnimationDuration(kHoverAnimationDurationMs);
}
-TextButton::~TextButton() {
+TextButtonBase::~TextButtonBase() {
}
-void TextButton::SetText(const std::wstring& text) {
+void TextButtonBase::SetIsDefault(bool is_default) {
+ if (is_default == is_default_)
+ return;
+ is_default_ = is_default;
+ if (is_default_)
+ AddAccelerator(Accelerator(ui::VKEY_RETURN, false, false, false));
+ else
+ RemoveAccelerator(Accelerator(ui::VKEY_RETURN, false, false, false));
+ SchedulePaint();
+}
+
+void TextButtonBase::SetText(const std::wstring& text) {
text_ = WideToUTF16Hack(text);
SetAccessibleName(WideToUTF16Hack(text));
UpdateTextSize();
}
-void TextButton::SetIcon(const SkBitmap& icon) {
- icon_ = icon;
-}
-
-void TextButton::SetHoverIcon(const SkBitmap& icon) {
- icon_hover_ = icon;
- has_hover_icon_ = true;
-}
-
-void TextButton::SetPushedIcon(const SkBitmap& icon) {
- icon_pushed_ = icon;
- has_pushed_icon_ = true;
-}
-
-void TextButton::SetFont(const gfx::Font& font) {
+void TextButtonBase::SetFont(const gfx::Font& font) {
font_ = font;
UpdateTextSize();
}
-void TextButton::SetEnabledColor(SkColor color) {
+void TextButtonBase::SetEnabledColor(SkColor color) {
color_enabled_ = color;
UpdateColor();
}
-void TextButton::SetDisabledColor(SkColor color) {
+void TextButtonBase::SetDisabledColor(SkColor color) {
color_disabled_ = color;
UpdateColor();
}
-void TextButton::SetHighlightColor(SkColor color) {
+void TextButtonBase::SetHighlightColor(SkColor color) {
color_highlight_ = color;
}
-void TextButton::SetHoverColor(SkColor color) {
+void TextButtonBase::SetHoverColor(SkColor color) {
color_hover_ = color;
}
-void TextButton::SetTextHaloColor(SkColor color) {
+void TextButtonBase::SetTextHaloColor(SkColor color) {
text_halo_color_ = color;
has_text_halo_ = true;
}
-void TextButton::SetTextShadowColors(SkColor active_color,
- SkColor inactive_color) {
+void TextButtonBase::SetTextShadowColors(SkColor active_color,
+ SkColor inactive_color) {
active_text_shadow_color_ = active_color;
inactive_text_shadow_color_ = inactive_color;
has_shadow_ = true;
}
-void TextButton::ClearMaxTextSize() {
+void TextButtonBase::ClearMaxTextSize() {
max_text_size_ = text_size_;
}
-void TextButton::SetNormalHasBorder(bool normal_has_border) {
+void TextButtonBase::SetNormalHasBorder(bool normal_has_border) {
normal_has_border_ = normal_has_border;
}
-void TextButton::SetShowMultipleIconStates(bool show_multiple_icon_states) {
+void TextButtonBase::SetShowMultipleIconStates(bool show_multiple_icon_states) {
show_multiple_icon_states_ = show_multiple_icon_states;
}
-void TextButton::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
- if (mode == PB_NORMAL) {
- OnPaintBackground(canvas);
+gfx::Size TextButtonBase::GetPreferredSize() {
+ gfx::Insets insets = GetInsets();
- if (show_multiple_icon_states_ && hover_animation_->is_animating()) {
- // Draw the hover bitmap into an offscreen buffer, then blend it
- // back into the current canvas.
- canvas->SaveLayerAlpha(
- static_cast<int>(hover_animation_->GetCurrentValue() * 255));
- canvas->AsCanvasSkia()->drawARGB(0, 255, 255, 255,
- SkXfermode::kClear_Mode);
- OnPaintBorder(canvas);
- canvas->Restore();
- } else if ((show_multiple_icon_states_ &&
- (state_ == BS_HOT || state_ == BS_PUSHED)) ||
- (state_ == BS_NORMAL && normal_has_border_)) {
- OnPaintBorder(canvas);
- }
+ // Use the max size to set the button boundaries.
+ gfx::Size prefsize(max_text_size_.width() + insets.width(),
+ max_text_size_.height() + insets.height());
- OnPaintFocusBorder(canvas);
- }
+ if (max_width_ > 0)
+ prefsize.set_width(std::min(max_width_, prefsize.width()));
- SkBitmap icon = icon_;
- if (show_multiple_icon_states_) {
- if (has_hover_icon_ && (state() == BS_HOT))
- icon = icon_hover_;
- else if (has_pushed_icon_ && (state() == BS_PUSHED))
- icon = icon_pushed_;
+ return prefsize;
+}
+
+void TextButtonBase::OnPaint(gfx::Canvas* canvas) {
+ PaintButton(canvas, PB_NORMAL);
+}
+
+const ui::Animation* TextButtonBase::GetAnimation() const {
+ return hover_animation_.get();
+}
+
+void TextButtonBase::UpdateColor() {
+ color_ = IsEnabled() ? color_enabled_ : color_disabled_;
+}
+
+void TextButtonBase::UpdateTextSize() {
+ int width = 0, height = 0;
+ gfx::CanvasSkia::SizeStringInt(
+ text_, font_, &width, &height,
+ gfx::Canvas::NO_ELLIPSIS | PrefixTypeToCanvasType(prefix_type_));
+
+ // Add 2 extra pixels to width and height when text halo is used.
+ if (has_text_halo_) {
+ width += 2;
+ height += 2;
}
+ text_size_.SetSize(width, font_.GetHeight());
+ max_text_size_.SetSize(std::max(max_text_size_.width(), text_size_.width()),
+ std::max(max_text_size_.height(),
+ text_size_.height()));
+ PreferredSizeChanged();
+}
+
+void TextButtonBase::GetExtraParams(
+ gfx::NativeTheme::ExtraParams* params) const {
+ params->button.checked = false;
+ params->button.indeterminate = false;
+ params->button.is_default = false;
+ params->button.has_border = false;
+ params->button.classic_state = 0;
+ params->button.background_color = kEnabledColor;
+}
+
+gfx::Rect TextButtonBase::GetTextBounds() const {
gfx::Insets insets = GetInsets();
int available_width = width() - insets.width();
- int available_height = height() - insets.height();
- // Use the actual text (not max) size to properly center the text.
int content_width = text_size_.width();
- if (icon.width() > 0) {
- content_width += icon.width();
- if (!text_.empty())
- content_width += icon_text_spacing_;
+ int text_x = 0;
+ switch(alignment_) {
+ case ALIGN_LEFT:
+ text_x = insets.left();
+ break;
+ case ALIGN_RIGHT:
+ text_x = width() - insets.right() - content_width;
+ break;
+ case ALIGN_CENTER:
+ text_x = insets.left() + std::max(0,
+ (available_width - content_width) / 2);
+ break;
}
- // Place the icon along the left edge.
- int icon_x;
- if (alignment_ == ALIGN_LEFT) {
- icon_x = insets.left();
- } else if (alignment_ == ALIGN_RIGHT) {
- icon_x = available_width - content_width;
- } else {
- icon_x =
- std::max(0, (available_width - content_width) / 2) + insets.left();
- }
- int text_x = icon_x;
- if (icon.width() > 0)
- text_x += icon.width() + icon_text_spacing_;
const int text_width = std::min(text_size_.width(),
width() - insets.right() - text_x);
+ int available_height = height() - insets.height();
int text_y = (available_height - text_size_.height()) / 2 + insets.top();
- // If the icon should go on the other side, swap the elements.
- if (icon_placement_ == ICON_ON_RIGHT) {
- int new_text_x = icon_x;
- icon_x = new_text_x + text_width + icon_text_spacing_;
- text_x = new_text_x;
+ gfx::Rect bounds(text_x, text_y, text_width, text_size_.height());
+ return bounds;
+}
+
+void TextButtonBase::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
+ if (mode == PB_NORMAL) {
+ OnPaintBackground(canvas);
+ OnPaintBorder(canvas);
+ OnPaintFocusBorder(canvas);
}
- if (text_width > 0) {
+ gfx::Rect text_bounds(GetTextBounds());
+ if (text_bounds.width() > 0) {
// Because the text button can (at times) draw multiple elements on the
// canvas, we can not mirror the button by simply flipping the canvas as
// doing this will mirror the text itself. Flipping the canvas will also
@@ -353,7 +438,6 @@ void TextButton::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
// horizontally.
//
// Due to the above, we must perform the flipping manually for RTL UIs.
- gfx::Rect text_bounds(text_x, text_y, text_width, text_size_.height());
text_bounds.set_x(GetMirroredXForRect(text_bounds));
SkColor text_color = (show_multiple_icon_states_ &&
@@ -416,51 +500,109 @@ void TextButton::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
draw_string_flags);
}
}
+}
- if (icon.width() > 0) {
- int icon_y = (available_height - icon.height()) / 2 + insets.top();
+////////////////////////////////////////////////////////////////////////////////
+// TextButtonBase, View overrides:
- // Mirroring the icon position if necessary.
- gfx::Rect icon_bounds(icon_x, icon_y, icon.width(), icon.height());
- icon_bounds.set_x(GetMirroredXForRect(icon_bounds));
- canvas->DrawBitmapInt(icon, icon_bounds.x(), icon_bounds.y());
+gfx::Size TextButtonBase::GetMinimumSize() {
+ return max_text_size_;
+}
+
+void TextButtonBase::SetEnabled(bool enabled) {
+ if (enabled != IsEnabled()) {
+ CustomButton::SetEnabled(enabled);
}
+ // We should always call UpdateColor() since the state of the button might be
+ // changed by other functions like CustomButton::SetState().
+ UpdateColor();
+ SchedulePaint();
}
-void TextButton::UpdateColor() {
- color_ = IsEnabled() ? color_enabled_ : color_disabled_;
+std::string TextButtonBase::GetClassName() const {
+ return kViewClassName;
}
-void TextButton::UpdateTextSize() {
- int width = 0, height = 0;
- gfx::CanvasSkia::SizeStringInt(
- text_, font_, &width, &height,
- gfx::Canvas::NO_ELLIPSIS | PrefixTypeToCanvasType(prefix_type_));
+////////////////////////////////////////////////////////////////////////////////
+// TextButtonBase, NativeThemeDelegate overrides:
- // Add 2 extra pixels to width and height when text halo is used.
- if (has_text_halo_) {
- width += 2;
- height += 2;
+gfx::Rect TextButtonBase::GetThemePaintRect() const {
+ return bounds();
+}
+
+gfx::NativeTheme::State TextButtonBase::GetThemeState(
+ gfx::NativeTheme::ExtraParams* params) const {
+ GetExtraParams(params);
+ 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:
+ NOTREACHED() << "Unknown state: " << state();
+ return gfx::NativeTheme::kNormal;
}
+}
- text_size_.SetSize(width, font_.GetHeight());
- max_text_size_.SetSize(std::max(max_text_size_.width(), text_size_.width()),
- std::max(max_text_size_.height(),
- text_size_.height()));
- PreferredSizeChanged();
+const ui::Animation* TextButtonBase::GetThemeAnimation() const {
+ return hover_animation_.get();
+}
+
+gfx::NativeTheme::State TextButtonBase::GetBackgroundThemeState(
+ gfx::NativeTheme::ExtraParams* params) const {
+ GetExtraParams(params);
+ return gfx::NativeTheme::kNormal;
}
+gfx::NativeTheme::State TextButtonBase::GetForegroundThemeState(
+ gfx::NativeTheme::ExtraParams* params) const {
+ GetExtraParams(params);
+ return gfx::NativeTheme::kHovered;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TextButton
+//
////////////////////////////////////////////////////////////////////////////////
-// TextButton, View overrides:
+
+TextButton::TextButton(ButtonListener* listener,
+ const std::wstring& text)
+ : TextButtonBase(listener, text),
+ icon_placement_(ICON_ON_LEFT),
+ has_hover_icon_(false),
+ has_pushed_icon_(false),
+ icon_text_spacing_(kDefaultIconTextSpacing) {
+ set_border(new TextButtonBorder);
+}
+
+TextButton::~TextButton() {
+}
+
+void TextButton::SetIcon(const SkBitmap& icon) {
+ icon_ = icon;
+}
+
+void TextButton::SetHoverIcon(const SkBitmap& icon) {
+ icon_hover_ = icon;
+ has_hover_icon_ = true;
+}
+
+void TextButton::SetPushedIcon(const SkBitmap& icon) {
+ icon_pushed_ = icon;
+ has_pushed_icon_ = true;
+}
gfx::Size TextButton::GetPreferredSize() {
- gfx::Insets insets = GetInsets();
+ gfx::Size prefsize(TextButtonBase::GetPreferredSize());
+ prefsize.Enlarge(icon_.width(), 0);
+ prefsize.set_height(std::max(prefsize.height(), icon_.height()));
// Use the max size to set the button boundaries.
- gfx::Size prefsize(max_text_size_.width() + icon_.width() + insets.width(),
- std::max(max_text_size_.height(), icon_.height()) +
- insets.height());
-
if (icon_.width() > 0 && !text_.empty())
prefsize.Enlarge(icon_text_spacing_, 0);
@@ -470,26 +612,115 @@ gfx::Size TextButton::GetPreferredSize() {
return prefsize;
}
-gfx::Size TextButton::GetMinimumSize() {
- return max_text_size_;
-}
+void TextButton::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
+ TextButtonBase::PaintButton(canvas, mode);
-void TextButton::SetEnabled(bool enabled) {
- if (enabled != IsEnabled()) {
- CustomButton::SetEnabled(enabled);
+ SkBitmap icon = icon_;
+ if (show_multiple_icon_states_) {
+ if (has_hover_icon_ && (state() == BS_HOT))
+ icon = icon_hover_;
+ else if (has_pushed_icon_ && (state() == BS_PUSHED))
+ icon = icon_pushed_;
+ }
+
+ if (icon.width() > 0) {
+ gfx::Rect text_bounds = GetTextBounds();
+ int icon_x;
+ int spacing = text_.empty() ? 0 : icon_text_spacing_;
+ if (icon_placement_ == ICON_ON_LEFT) {
+ icon_x = text_bounds.x() - icon.width() - spacing;
+ } else {
+ icon_x = text_bounds.right() + spacing;
+ }
+
+ gfx::Insets insets = GetInsets();
+ int available_height = height() - insets.height();
+ int icon_y = (available_height - icon.height()) / 2 + insets.top();
+
+ // Mirroring the icon position if necessary.
+ gfx::Rect icon_bounds(icon_x, icon_y, icon.width(), icon.height());
+ icon_bounds.set_x(GetMirroredXForRect(icon_bounds));
+ canvas->DrawBitmapInt(icon, icon_bounds.x(), icon_bounds.y());
}
- // We should always call UpdateColor() since the state of the button might be
- // changed by other functions like CustomButton::SetState().
- UpdateColor();
- SchedulePaint();
}
std::string TextButton::GetClassName() const {
return kViewClassName;
}
-void TextButton::OnPaint(gfx::Canvas* canvas) {
- PaintButton(canvas, PB_NORMAL);
+gfx::NativeTheme::Part TextButton::GetThemePart() const {
+ return gfx::NativeTheme::kPushButton;
+}
+
+void TextButton::GetExtraParams(gfx::NativeTheme::ExtraParams* params) const {
+ params->button.checked = false;
+ params->button.indeterminate = false;
+ params->button.is_default = is_default_;
+ params->button.has_border = false;
+ params->button.classic_state = 0;
+ params->button.background_color = kEnabledColor;
+}
+
+gfx::Rect TextButton::GetTextBounds() const {
+ gfx::Rect bounds(TextButtonBase::GetTextBounds());
+
+ SkBitmap icon = icon_;
+ if (show_multiple_icon_states_) {
+ if (has_hover_icon_ && (state() == BS_HOT))
+ icon = icon_hover_;
+ else if (has_pushed_icon_ && (state() == BS_PUSHED))
+ icon = icon_pushed_;
+ }
+
+ if (icon.width() > 0) {
+ gfx::Insets insets = GetInsets();
+ int available_width = width() - insets.width();
+ int icon_width = icon.width() + (text_.empty() ? 0 : icon_text_spacing_);
+ int new_content_width = bounds.width() + icon_width;
+
+ if (new_content_width < available_width) {
+ switch(alignment_) {
+ case ALIGN_LEFT:
+ if (icon_placement_ == ICON_ON_LEFT)
+ bounds.Offset(icon_width, 0);
+ break;
+ case ALIGN_RIGHT:
+ if (icon_placement_ == ICON_ON_RIGHT)
+ bounds.Offset(-icon_width, 0);
+ break;
+ case ALIGN_CENTER:
+ if (icon_placement_ == ICON_ON_LEFT) {
+ bounds.Offset(icon_width / 2, 0);
+ } else {
+ bounds.Offset(-icon_width / 2, 0);
+ }
+ break;
+ }
+ } else {
+ // Make sure the icon is always fully visible.
+ switch(alignment_) {
+ case ALIGN_LEFT:
+ case ALIGN_CENTER:
+ if (icon_placement_ == ICON_ON_LEFT) {
+ bounds.Offset(icon_width, 0);
+ } else {
+ bounds.set_width(available_width - icon_width);
+ }
+ break;
+ case ALIGN_RIGHT:
+ if (icon_placement_ == ICON_ON_RIGHT) {
+ bounds.Offset(-icon_width, 0);
+ } else {
+ bounds.set_x(icon_width + insets.left());
+ }
+ break;
+ }
+ }
+ }
+
+ return bounds;
}
} // namespace views
+
+
diff --git a/views/controls/button/text_button.h b/views/controls/button/text_button.h
index f8ab377..8b1c502 100644
--- a/views/controls/button/text_button.h
+++ b/views/controls/button/text_button.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -15,6 +15,7 @@
#include "ui/gfx/font.h"
#include "views/border.h"
#include "views/controls/button/custom_button.h"
+#include "views/native_theme_delegate.h"
namespace views {
@@ -35,10 +36,8 @@ class TextButtonBorder : public Border {
TextButtonBorder();
virtual ~TextButtonBorder();
- // Render the background for the provided view
+ // Implementation of Border:
virtual void Paint(const View& view, gfx::Canvas* canvas) const;
-
- // Returns the insets for the border.
virtual void GetInsets(gfx::Insets* insets) const;
protected:
@@ -67,14 +66,41 @@ class TextButtonBorder : public Border {
////////////////////////////////////////////////////////////////////////////////
//
-// TextButton
+// TextButtonNativeThemeBorder
//
-// A button which displays text and/or and icon that can be changed in
-// response to actions. TextButton reserves space for the largest string
+// A Border subclass that paints a TextButton's background layer using the
+// platform's native theme look. This handles normal/disabled/hot/pressed
+// states, with possible animation between states.
+//
+////////////////////////////////////////////////////////////////////////////////
+class TextButtonNativeThemeBorder : public Border {
+ public:
+ TextButtonNativeThemeBorder(NativeThemeDelegate* delegate);
+ virtual ~TextButtonNativeThemeBorder();
+
+ // Implementation of Border:
+ virtual void Paint(const View& view, gfx::Canvas* canvas) const;
+ virtual void GetInsets(gfx::Insets* insets) const;
+
+ private:
+ // The delegate the controls the appearance of this border.
+ NativeThemeDelegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextButtonNativeThemeBorder);
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TextButtonBase
+//
+// A base ckass for different types of buttons, like push buttons, radio
+// buttons, and checkboxes, that do not depende on native components for
+// look and feel. TextButton reserves space for the largest string
// passed to SetText. To reset the cached max size invoke ClearMaxTextSize.
//
////////////////////////////////////////////////////////////////////////////////
-class TextButton : public CustomButton {
+class TextButtonBase : public CustomButton, public NativeThemeDelegate {
public:
// The menu button's class name.
static const char kViewClassName[];
@@ -92,8 +118,7 @@ class TextButton : public CustomButton {
PREFIX_SHOW
};
- TextButton(ButtonListener* listener, const std::wstring& text);
- virtual ~TextButton();
+ virtual ~TextButtonBase();
// Call SetText once per string in your set of possible values at button
// creation time, so that it can contain the largest of them and avoid
@@ -111,27 +136,10 @@ class TextButton : public CustomButton {
void set_prefix_type(PrefixType type) { prefix_type_ = type; }
- void set_icon_text_spacing(int icon_text_spacing) {
- icon_text_spacing_ = icon_text_spacing;
- }
-
- // Sets the icon.
- void SetIcon(const SkBitmap& icon);
- void SetHoverIcon(const SkBitmap& icon);
- void SetPushedIcon(const SkBitmap& icon);
-
- bool HasIcon() const { return !icon_.empty(); }
-
- // Meanings are reversed for right-to-left layouts.
- enum IconPlacement {
- ICON_ON_LEFT,
- ICON_ON_RIGHT
- };
+ const ui::Animation* GetAnimation() const;
- IconPlacement icon_placement() { return icon_placement_; }
- void set_icon_placement(IconPlacement icon_placement) {
- icon_placement_ = icon_placement;
- }
+ void SetIsDefault(bool is_default);
+ bool is_default() const { return is_default_; }
// TextButton remembers the maximum display size of the text passed to
// SetText. This method resets the cached maximum display size to the
@@ -152,9 +160,13 @@ class TextButton : public CustomButton {
// inactive. Both possible colors are set in this method, and the
// appropriate one is chosen during Paint.
void SetTextShadowColors(SkColor active_color, SkColor inactive_color);
+
+ bool normal_has_border() const { return normal_has_border_; }
void SetNormalHasBorder(bool normal_has_border);
+
// Sets whether or not to show the hot and pushed states for the button icon
// (if present) in addition to the normal state. Defaults to true.
+ bool show_multiple_icon_states() const { return show_multiple_icon_states_; }
void SetShowMultipleIconStates(bool show_multiple_icon_states);
// Paint the button into the specified canvas. If |mode| is |PB_FOR_DRAG|, the
@@ -163,9 +175,10 @@ class TextButton : public CustomButton {
virtual void PaintButton(gfx::Canvas* canvas, PaintButtonMode mode);
// Overridden from View:
- virtual gfx::Size GetPreferredSize();
- virtual gfx::Size GetMinimumSize();
- virtual void SetEnabled(bool enabled);
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetMinimumSize() OVERRIDE;
+ virtual void SetEnabled(bool enabled) OVERRIDE;
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
// Text colors.
static const SkColor kEnabledColor;
@@ -177,9 +190,7 @@ class TextButton : public CustomButton {
virtual std::string GetClassName() const;
protected:
- SkBitmap icon() const { return icon_; }
-
- virtual void OnPaint(gfx::Canvas* canvas);
+ TextButtonBase(ButtonListener* listener, const std::wstring& text);
// Called when enabled or disabled state changes, or the colors for those
// states change.
@@ -189,10 +200,23 @@ class TextButton : public CustomButton {
// invoked when the font or text changes.
void UpdateTextSize();
+ // Overridden from NativeThemeDelegate:
+ virtual gfx::Rect GetThemePaintRect() const OVERRIDE;
+ virtual gfx::NativeTheme::State GetThemeState(
+ gfx::NativeTheme::ExtraParams* params) const OVERRIDE;
+ virtual const 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;
+
+ virtual void GetExtraParams(gfx::NativeTheme::ExtraParams* params) const;
+
+ virtual gfx::Rect GetTextBounds() const;
+
// The text string that is displayed in the button.
string16 text_;
- private:
// The size of the text string.
gfx::Size text_size_;
@@ -203,9 +227,6 @@ class TextButton : public CustomButton {
// The alignment of the text string within the button.
TextAlignment alignment_;
- // The position of the icon.
- IconPlacement icon_placement_;
-
// The font used to paint the text.
gfx::Font font_;
@@ -227,17 +248,6 @@ class TextButton : public CustomButton {
SkColor inactive_text_shadow_color_;
bool has_shadow_;
- // An icon displayed with the text.
- SkBitmap icon_;
-
- // An optional different version of the icon for hover state.
- SkBitmap icon_hover_;
- bool has_hover_icon_;
-
- // An optional different version of the icon for pushed state.
- SkBitmap icon_pushed_;
- bool has_pushed_icon_;
-
// The width of the button will never be larger than this value. A value <= 0
// indicates the width is not constrained.
int max_width_;
@@ -248,8 +258,87 @@ class TextButton : public CustomButton {
// Whether or not to show the hot and pushed icon states.
bool show_multiple_icon_states_;
+ // Whether or not the button appears and behaves as the default button in its
+ // current context.
+ bool is_default_;
+
PrefixType prefix_type_;
+ DISALLOW_COPY_AND_ASSIGN(TextButtonBase);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TextButton
+//
+// A button which displays text and/or and icon that can be changed in
+// response to actions. TextButton reserves space for the largest string
+// passed to SetText. To reset the cached max size invoke ClearMaxTextSize.
+//
+////////////////////////////////////////////////////////////////////////////////
+class TextButton : public TextButtonBase {
+ public:
+ // The button's class name.
+ static const char kViewClassName[];
+
+ TextButton(ButtonListener* listener, const std::wstring& text);
+ virtual ~TextButton();
+
+ void set_icon_text_spacing(int icon_text_spacing) {
+ icon_text_spacing_ = icon_text_spacing;
+ }
+
+ // Sets the icon.
+ void SetIcon(const SkBitmap& icon);
+ void SetHoverIcon(const SkBitmap& icon);
+ void SetPushedIcon(const SkBitmap& icon);
+
+ bool HasIcon() const { return !icon_.empty(); }
+
+ // Meanings are reversed for right-to-left layouts.
+ enum IconPlacement {
+ ICON_ON_LEFT,
+ ICON_ON_RIGHT
+ };
+
+ IconPlacement icon_placement() { return icon_placement_; }
+ void set_icon_placement(IconPlacement icon_placement) {
+ icon_placement_ = icon_placement;
+ }
+
+ // Overridden from View:
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual std::string GetClassName() const;
+
+ // Overridden from TextButtonBase:
+ virtual void PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) OVERRIDE;
+
+ protected:
+ SkBitmap icon() const { return icon_; }
+
+ // Overridden from NativeThemeDelegate:
+ virtual gfx::NativeTheme::Part GetThemePart() const OVERRIDE;
+
+ // Overridden from TextButtonBase:
+ virtual void GetExtraParams(
+ gfx::NativeTheme::ExtraParams* params) const OVERRIDE;
+ virtual gfx::Rect GetTextBounds() const OVERRIDE;
+
+ private:
+ // The position of the icon.
+ IconPlacement icon_placement_;
+
+ // An icon displayed with the text.
+ SkBitmap icon_;
+
+ // An optional different version of the icon for hover state.
+ SkBitmap icon_hover_;
+ bool has_hover_icon_;
+
+ // An optional different version of the icon for pushed state.
+ SkBitmap icon_pushed_;
+ bool has_pushed_icon_;
+
// Space between icon and text.
int icon_text_spacing_;
diff --git a/views/examples/button_example.cc b/views/examples/button_example.cc
index d27a5d2..4ab7f80 100644
--- a/views/examples/button_example.cc
+++ b/views/examples/button_example.cc
@@ -4,6 +4,9 @@
#include "views/examples/button_example.h"
+#include "grit/app_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "views/controls/button/checkbox.h"
#include "views/layout/fill_layout.h"
#include "views/view.h"
@@ -11,7 +14,12 @@ namespace examples {
ButtonExample::ButtonExample(ExamplesMain* main)
: ExampleBase(main),
+ alignment_(views::TextButton::ALIGN_LEFT),
+ use_native_theme_border_(false),
+ icon_(NULL),
count_(0) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ icon_ = rb.GetBitmapNamed(IDR_CLOSE_SA_H);
}
ButtonExample::~ButtonExample() {
@@ -22,7 +30,8 @@ std::wstring ButtonExample::GetExampleTitle() {
}
void ButtonExample::CreateExampleView(views::View* container) {
- button_ = new views::TextButton(this, L"Button");
+ views::TextButton* tb = new views::TextButton(this, L"Button");
+ button_ = tb;
container->SetLayoutManager(new views::FillLayout);
container->AddChildView(button_);
}
@@ -30,6 +39,57 @@ void ButtonExample::CreateExampleView(views::View* container) {
void ButtonExample::ButtonPressed(views::Button* sender,
const views::Event& event) {
PrintStatus(L"Pressed! count:%d", ++count_);
+
+ if (event.IsControlDown()) {
+ if (event.IsShiftDown()) {
+ switch(button_->icon_placement()) {
+ case views::TextButton::ICON_ON_LEFT:
+ button_->set_icon_placement(views::TextButton::ICON_ON_RIGHT);
+ break;
+ case views::TextButton::ICON_ON_RIGHT:
+ button_->set_icon_placement(views::TextButton::ICON_ON_LEFT);
+ break;
+ }
+ } else if (event.IsAltDown()) {
+ if (button_->HasIcon())
+ button_->SetIcon(SkBitmap());
+ else
+ button_->SetIcon(*icon_);
+ } else {
+ switch(alignment_) {
+ case views::TextButton::ALIGN_LEFT:
+ alignment_ = views::TextButton::ALIGN_CENTER;
+ break;
+ case views::TextButton::ALIGN_CENTER:
+ alignment_ = views::TextButton::ALIGN_RIGHT;
+ break;
+ case views::TextButton::ALIGN_RIGHT:
+ alignment_ = views::TextButton::ALIGN_LEFT;
+ break;
+ }
+ button_->set_alignment(alignment_);
+ }
+ } else if (event.IsShiftDown()) {
+ if (event.IsAltDown()) {
+ if (button_->text().length() < 10) {
+ button_->SetText(L"Startof"
+ L"ReallyReallyReallyReallyReallyReallyReally"
+ L"ReallyReallyReallyReallyReallyReallyReally"
+ L"ReallyReallyReallyReallyReallyReallyReally"
+ L"LongButtonText");
+ } else {
+ button_->SetText(L"Button");
+ }
+ } else {
+ use_native_theme_border_ = !use_native_theme_border_;
+ if (use_native_theme_border_)
+ button_->set_border(new views::TextButtonNativeThemeBorder(button_));
+ else
+ button_->set_border(new views::TextButtonBorder());
+ }
+ } else if (event.IsAltDown()) {
+ button_->SetIsDefault(!button_->is_default());
+ }
}
} // namespace examples
diff --git a/views/examples/button_example.h b/views/examples/button_example.h
index fe8567b..aad1ff9 100644
--- a/views/examples/button_example.h
+++ b/views/examples/button_example.h
@@ -35,6 +35,11 @@ class ButtonExample : public ExampleBase, public views::ButtonListener {
// The only control in this test.
views::TextButton* button_;
+ // Values used to modify the look and feel of the button.
+ views::TextButton::TextAlignment alignment_;
+ bool use_native_theme_border_;
+ SkBitmap* icon_;
+
// The number of times the button is pressed.
int count_;
diff --git a/views/examples/examples_main.cc b/views/examples/examples_main.cc
index 7f12733..8b2b647 100644
--- a/views/examples/examples_main.cc
+++ b/views/examples/examples_main.cc
@@ -20,6 +20,7 @@
#include "views/examples/menu_example.h"
#include "views/examples/message_box_example.h"
#include "views/examples/native_theme_button_example.h"
+#include "views/examples/native_theme_checkbox_example.h"
#include "views/examples/radio_button_example.h"
#include "views/examples/scroll_view_example.h"
#include "views/examples/single_split_view_example.h"
@@ -99,6 +100,10 @@ void ExamplesMain::Run() {
views::Window* window =
views::Window::CreateChromeWindow(NULL, gfx::Rect(0, 0, 850, 300), this);
+ examples::NativeThemeCheckboxExample native_theme_checkbox_example(this);
+ tabbed_pane->AddTab(native_theme_checkbox_example.GetExampleTitle(),
+ native_theme_checkbox_example.GetExampleView());
+
examples::NativeThemeButtonExample native_theme_button_example(this);
tabbed_pane->AddTab(native_theme_button_example.GetExampleTitle(),
native_theme_button_example.GetExampleView());
diff --git a/views/examples/native_theme_button_example.cc b/views/examples/native_theme_button_example.cc
index 7398a270..e7630e3 100644
--- a/views/examples/native_theme_button_example.cc
+++ b/views/examples/native_theme_button_example.cc
@@ -136,6 +136,10 @@ gfx::NativeTheme::Part ExampleNativeThemeButton::GetThemePart() const {
return gfx::NativeTheme::kPushButton;
}
+gfx::Rect ExampleNativeThemeButton::GetThemePaintRect() const {
+ return bounds();
+}
+
gfx::NativeTheme::State ExampleNativeThemeButton::GetThemeState(
gfx::NativeTheme::ExtraParams* params) const {
GetExtraParams(params);
@@ -182,7 +186,7 @@ void ExampleNativeThemeButton::GetExtraParams(
params->button.background_color = SkColorSetARGB(0, 0, 0, 0);
}
-ui::Animation* ExampleNativeThemeButton::GetThemeAnimation() const {
+const ui::Animation* ExampleNativeThemeButton::GetThemeAnimation() const {
int selected = cb_state_->selected_item();
return selected <= 3 ? NULL : hover_animation_.get();
}
diff --git a/views/examples/native_theme_button_example.h b/views/examples/native_theme_button_example.h
index 9ca7c33..91f02a6 100644
--- a/views/examples/native_theme_button_example.h
+++ b/views/examples/native_theme_button_example.h
@@ -11,6 +11,7 @@
#include "views/controls/button/custom_button.h"
#include "views/controls/combobox/combobox.h"
#include "views/examples/example_base.h"
+#include "views/native_theme_delegate.h"
#include "views/native_theme_painter.h"
namespace views {
@@ -22,7 +23,7 @@ namespace examples {
// A subclass of button to test native theme rendering.
class ExampleNativeThemeButton : public views::CustomButton,
- public views::NativeThemePainter::Delegate,
+ public views::NativeThemeDelegate,
public views::Combobox::Listener {
public:
ExampleNativeThemeButton(views::ButtonListener* listener,
@@ -44,9 +45,10 @@ class ExampleNativeThemeButton : public views::CustomButton,
// Overridden from views::NativeThemePainter::Delegate:
virtual gfx::NativeTheme::Part GetThemePart() const OVERRIDE;
+ virtual gfx::Rect GetThemePaintRect() const OVERRIDE;
virtual gfx::NativeTheme::State GetThemeState(
gfx::NativeTheme::ExtraParams* params) const OVERRIDE;
- virtual ui::Animation* GetThemeAnimation() const OVERRIDE;
+ virtual const ui::Animation* GetThemeAnimation() const OVERRIDE;
virtual gfx::NativeTheme::State GetBackgroundThemeState(
gfx::NativeTheme::ExtraParams* params) const OVERRIDE;
virtual gfx::NativeTheme::State GetForegroundThemeState(
diff --git a/views/examples/native_theme_checkbox_example.cc b/views/examples/native_theme_checkbox_example.cc
new file mode 100644
index 0000000..f7c6626
--- /dev/null
+++ b/views/examples/native_theme_checkbox_example.cc
@@ -0,0 +1,39 @@
+// 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_checkbox_example.h"
+
+#include "base/stringprintf.h"
+#include "views/controls/button/checkbox.h"
+#include "views/controls/button/radio_button.h"
+#include "views/layout/fill_layout.h"
+
+namespace examples {
+
+NativeThemeCheckboxExample::NativeThemeCheckboxExample(ExamplesMain* main)
+ : ExampleBase(main),
+ count_(0) {
+}
+
+NativeThemeCheckboxExample::~NativeThemeCheckboxExample() {
+}
+
+std::wstring NativeThemeCheckboxExample::GetExampleTitle() {
+ return L"CheckboxNt";
+}
+
+void NativeThemeCheckboxExample::CreateExampleView(views::View* container) {
+ //button_ = new views::RadioButtonNt(L"RadioButtonNt", 3);
+ button_ = new views::CheckboxNt(L"CheckboxNt");
+ button_->set_listener(this);
+ container->SetLayoutManager(new views::FillLayout);
+ container->AddChildView(button_);
+}
+
+void NativeThemeCheckboxExample::ButtonPressed(views::Button* sender,
+ const views::Event& event) {
+ PrintStatus(base::StringPrintf(L"Pressed! count:%d", ++count_).c_str());
+}
+
+} // namespace examples
diff --git a/views/examples/native_theme_checkbox_example.h b/views/examples/native_theme_checkbox_example.h
new file mode 100644
index 0000000..4bd83c7
--- /dev/null
+++ b/views/examples/native_theme_checkbox_example.h
@@ -0,0 +1,46 @@
+// 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_CHECKBOX_EXAMPLE_H_
+#define VIEWS_EXAMPLES_NATIVE_THEME_CHECKBOX_EXAMPLE_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "ui/gfx/native_theme.h"
+#include "views/controls/button/button.h"
+#include "views/examples/example_base.h"
+
+namespace views {
+class CheckboxNt;
+}
+
+namespace examples {
+
+// NativeThemeCheckboxExample exercises a CheckboxNt control.
+class NativeThemeCheckboxExample : public ExampleBase,
+ public views::ButtonListener {
+ public:
+ explicit NativeThemeCheckboxExample(ExamplesMain* main);
+ virtual ~NativeThemeCheckboxExample();
+
+ // 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.
+ views::CheckboxNt* button_;
+
+ int count_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeThemeCheckboxExample);
+};
+
+} // namespace examples
+
+#endif // VIEWS_EXAMPLES_NATIVE_THEME_CHECKBOX_EXAMPLE_H_
diff --git a/views/examples/radio_button_example.cc b/views/examples/radio_button_example.cc
index 27d8fa1..546a0ee 100644
--- a/views/examples/radio_button_example.cc
+++ b/views/examples/radio_button_example.cc
@@ -25,16 +25,17 @@ void RadioButtonExample::CreateExampleView(views::View* container) {
select_ = new views::TextButton(this, L"Select");
status_ = new views::TextButton(this, L"Show Status");
- int all = arraysize(radio_buttons_);
-
- // divide buttons into 2 groups
- int group_count = all / 2;
- for (int i = 0; i < all; i++) {
- int group = i / group_count;
+ int group = 1;
+ for (int i = 0; i < arraysize(radio_buttons_); ++i) {
radio_buttons_[i] = new views::RadioButton(
- base::StringPrintf(
- L"Radio %d in group %d", (i % group_count + 1), group),
- group);
+ base::StringPrintf( L"Radio %d in group %d", i + 1, group), group);
+ }
+
+ ++group;
+ for (int i = 0; i < arraysize(radio_buttons_nt_); ++i) {
+ radio_buttons_nt_[i] = new views::RadioButtonNt(
+ base::StringPrintf( L"Radio %d in group %d", i + 1, group), group);
+ radio_buttons_nt_[i]->SetFocusable(true);
}
views::GridLayout* layout = new views::GridLayout(container);
@@ -43,10 +44,14 @@ void RadioButtonExample::CreateExampleView(views::View* container) {
views::ColumnSet* column_set = layout->AddColumnSet(0);
column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
1.0f, views::GridLayout::USE_PREF, 0, 0);
- for (int i = 0; i < all; i++) {
+ for (int i = 0; i < arraysize(radio_buttons_); i++) {
layout->StartRow(0, 0);
layout->AddView(radio_buttons_[i]);
}
+ for (int i = 0; i < arraysize(radio_buttons_nt_); i++) {
+ layout->StartRow(0, 0);
+ layout->AddView(radio_buttons_nt_[i]);
+ }
layout->StartRow(0, 0);
layout->AddView(select_);
layout->StartRow(0, 0);
@@ -57,16 +62,16 @@ void RadioButtonExample::ButtonPressed(views::Button* sender,
const views::Event& event) {
if (sender == select_) {
radio_buttons_[0]->SetChecked(true);
- radio_buttons_[5]->SetChecked(true);
+ radio_buttons_nt_[2]->SetChecked(true);
} else if (sender == status_) {
// Show the state of radio buttons.
PrintStatus(L"Group1: 1:%ls, 2:%ls, 3:%ls Group2: 1:%ls, 2:%ls, 3:%ls",
IntToOnOff(radio_buttons_[0]->checked()),
IntToOnOff(radio_buttons_[1]->checked()),
IntToOnOff(radio_buttons_[2]->checked()),
- IntToOnOff(radio_buttons_[3]->checked()),
- IntToOnOff(radio_buttons_[4]->checked()),
- IntToOnOff(radio_buttons_[5]->checked()));
+ IntToOnOff(radio_buttons_nt_[0]->checked()),
+ IntToOnOff(radio_buttons_nt_[1]->checked()),
+ IntToOnOff(radio_buttons_nt_[2]->checked()));
}
}
diff --git a/views/examples/radio_button_example.h b/views/examples/radio_button_example.h
index 92cf431..72217e2 100644
--- a/views/examples/radio_button_example.h
+++ b/views/examples/radio_button_example.h
@@ -31,9 +31,9 @@ class RadioButtonExample : public ExampleBase,
virtual void ButtonPressed(views::Button* sender,
const views::Event& event) OVERRIDE;
- // 6 radio buttons, 0-2 consists 1st group, and 3-5 consists
- // 2nd group.
- views::RadioButton* radio_buttons_[6];
+ // Two groups of 3 radio buttons.
+ views::RadioButton* radio_buttons_[3];
+ views::RadioButtonNt* radio_buttons_nt_[3];
// Control button to select radio buttons, and show the status of buttons.
views::TextButton* select_;
diff --git a/views/native_theme_delegate.h b/views/native_theme_delegate.h
new file mode 100644
index 0000000..d94a514
--- /dev/null
+++ b/views/native_theme_delegate.h
@@ -0,0 +1,52 @@
+// 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_DELEGATE_H_
+#define VIEWS_NATIVE_THEME_DELEGATE_H_
+#pragma once
+
+#include "ui/gfx/native_theme.h"
+#include "ui/gfx/rect.h"
+
+namespace views {
+
+// A delagate that supports animating transtions between different native
+// theme states. This delegate can be used to control a native theme Border
+// or Painter object.
+//
+// If animation is onging, the native theme border or 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 NativeThemeDelegate {
+ public:
+ virtual ~NativeThemeDelegate() {}
+
+ // Get the native theme part that should be drawn.
+ virtual gfx::NativeTheme::Part GetThemePart() const = 0;
+
+ // Get the rectangle that should be painted.
+ virtual gfx::Rect GetThemePaintRect() const = 0;
+
+ // Get the state of the part, along with any extra data needed for drawing.
+ virtual gfx::NativeTheme::State GetThemeState(
+ gfx::NativeTheme::ExtraParams* params) const = 0;
+
+ // If the native theme drawign should be animated, return the Animation object
+ // that controlls it. If no animation is ongoing, NULL may be returned.
+ virtual const 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;
+};
+
+} // namespace views
+
+#endif // VIEWS_NATIVE_THEME_DELEGATE_H_
diff --git a/views/native_theme_painter.cc b/views/native_theme_painter.cc
index a99edea..71bb71b 100644
--- a/views/native_theme_painter.cc
+++ b/views/native_theme_painter.cc
@@ -9,10 +9,11 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/canvas_skia.h"
#include "ui/gfx/rect.h"
+#include "views/native_theme_delegate.h"
namespace views {
-NativeThemePainter::NativeThemePainter(Delegate* delegate)
+NativeThemePainter::NativeThemePainter(NativeThemeDelegate* delegate)
: delegate_(delegate) {
DCHECK(delegate_);
}
diff --git a/views/native_theme_painter.h b/views/native_theme_painter.h
index 55dad89..a2c45bc 100644
--- a/views/native_theme_painter.h
+++ b/views/native_theme_painter.h
@@ -7,7 +7,6 @@
#pragma once
#include "base/compiler_specific.h"
-#include "ui/gfx/native_theme.h"
#include "views/painter.h"
namespace gfx {
@@ -21,43 +20,14 @@ class Animation;
namespace views {
+class NativeThemeDelegate;
+
// 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);
+ explicit NativeThemePainter(NativeThemeDelegate* delegate);
virtual ~NativeThemePainter() {}
@@ -66,7 +36,7 @@ class NativeThemePainter : public Painter {
private:
// The delegate the controls the appearance of this painter.
- Delegate* delegate_;
+ NativeThemeDelegate* delegate_;
// Overridden from Painter:
virtual void Paint(int w, int h, gfx::Canvas* canvas) OVERRIDE;
diff --git a/views/views.gyp b/views/views.gyp
index 0eb07f1..dfa848d 100644
--- a/views/views.gyp
+++ b/views/views.gyp
@@ -303,6 +303,7 @@
'metrics_win.cc',
'mouse_watcher.cc',
'mouse_watcher.h',
+ 'native_theme_delegate.h',
'native_theme_painter.cc',
'native_theme_painter.h',
'painter.cc',
@@ -550,6 +551,7 @@
'target_name': 'views_examples',
'type': 'executable',
'dependencies': [
+ '../app/app.gyp:app_resources',
'../base/base.gyp:base',
'../skia/skia.gyp:skia',
'../third_party/icu/icu.gyp:icui18n',
@@ -576,6 +578,8 @@
'examples/menu_example.h',
'examples/native_theme_button_example.cc',
'examples/native_theme_button_example.h',
+ 'examples/native_theme_checkbox_example.cc',
+ 'examples/native_theme_checkbox_example.h',
'examples/radio_button_example.cc',
'examples/radio_button_example.h',
'examples/scroll_view_example.cc',