diff options
Diffstat (limited to 'chrome/views/label.cc')
-rw-r--r-- | chrome/views/label.cc | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/chrome/views/label.cc b/chrome/views/label.cc new file mode 100644 index 0000000..590294b --- /dev/null +++ b/chrome/views/label.cc @@ -0,0 +1,406 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "chrome/views/label.h" + +#include <math.h> + +#include "base/string_util.h" +#include "chrome/common/gfx/chrome_canvas.h" +#include "chrome/common/gfx/chrome_font.h" +#include "chrome/common/gfx/url_elider.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/views/background.h" +#include "chrome/views/view_container.h" + +namespace ChromeViews { + +const char Label::kViewClassName[] = "chrome/views/Label"; + +static const SkColor kEnabledColor = SK_ColorBLACK; +static const SkColor kDisabledColor = SkColorSetRGB(161, 161, 146); + +Label::Label() { + Init(L"", GetDefaultFont()); +} + +Label::Label(const std::wstring& text) { + Init(text, GetDefaultFont()); +} + +Label::Label(const std::wstring& text, const ChromeFont& font) { + Init(text, font); +} + +void Label::Init(const std::wstring& text, const ChromeFont& font) { + contains_mouse_ = false; + font_ = font; + text_size_valid_ = false; + SetText(text); + url_set_ = false; + color_ = kEnabledColor; + horiz_alignment_ = ALIGN_CENTER; + is_multi_line_ = false; +} + +Label::~Label() { +} + +void Label::GetPreferredSize(CSize* out) { + DCHECK(out); + if (is_multi_line_) { + ChromeCanvas cc(0, 0, true); + int w = GetWidth(), h = 0; + cc.SizeStringInt(text_, font_, &w, &h, ComputeMultiLineFlags()); + out->cx = w; + out->cy = h; + } else { + GetTextSize(out); + } + + gfx::Insets insets = GetInsets(); + out->cx += insets.left() + insets.right(); + out->cy += insets.top() + insets.bottom(); +} + +int Label::ComputeMultiLineFlags() { + int flags = ChromeCanvas::MULTI_LINE; + switch (horiz_alignment_) { + case ALIGN_LEFT: + flags |= ChromeCanvas::TEXT_ALIGN_LEFT; + break; + case ALIGN_CENTER: + flags |= ChromeCanvas::TEXT_ALIGN_CENTER; + break; + case ALIGN_RIGHT: + flags |= ChromeCanvas::TEXT_ALIGN_RIGHT; + break; + } + return flags; +} + +void Label::Paint(ChromeCanvas* canvas) { + PaintBackground(canvas); + std::wstring paint_text; + + if (url_set_) { + // TODO(jungshik) : Figure out how to get 'intl.accept_languages' + // preference and use it when calling ElideUrl. + paint_text = gfx::ElideUrl(url_, font_, bounds_.right - bounds_.left, + std::wstring()); + + + // An URLs is always treated as an LTR text and therefore we should + // explicitly mark it as such if the locale is RTL so that URLs containing + // Hebrew or Arabic characters are displayed correctly. + // + // Note that we don't check the View's UI layout setting in order to + // determine whether or not to insert the special Unicode formatting + // characters. We use the locale settings because an URL is always treated + // as an LTR string, even if its containing view does not use an RTL UI + // layout. + if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) + l10n_util::WrapStringWithLTRFormatting(&paint_text); + } else { + paint_text = text_; + } + + if (is_multi_line_) { + canvas->DrawStringInt(paint_text, font_, color_, 0, 0, GetWidth(), + GetHeight(), ComputeMultiLineFlags()); + PaintFocusBorder(canvas); + } else { + gfx::Rect text_bounds = GetTextBounds(); + + canvas->DrawStringInt(paint_text, + font_, + color_, + text_bounds.x(), + text_bounds.y(), + text_bounds.width(), + text_bounds.height()); + // We'll draw the focus border ourselves so it is around the text. + if (HasFocus()) + canvas->DrawFocusRect(text_bounds.x(), + text_bounds.y(), + text_bounds.width(), + text_bounds.height()); + } +} + +void Label::PaintBackground(ChromeCanvas* canvas) { + const Background* bg = contains_mouse_ ? GetMouseOverBackground() : NULL; + if (!bg) + bg = GetBackground(); + if (bg) + bg->Paint(canvas, this); +} + +void Label::SetFont(const ChromeFont& font) { + font_ = font; + text_size_valid_ = false; + SchedulePaint(); +} + +ChromeFont Label::GetFont() const { + return font_; +} + +void Label::SetText(const std::wstring& text) { + text_ = text; + url_set_ = false; + text_size_valid_ = false; + SchedulePaint(); +} + +void Label::SetURL(const GURL& url) { + url_ = url; + text_ = UTF8ToWide(url_.spec()); + url_set_ = true; + text_size_valid_ = false; + SchedulePaint(); +} + +const std::wstring Label::GetText() const { + if (url_set_) + return UTF8ToWide(url_.spec()); + else + return text_; +} + +const GURL Label::GetURL() const { + if (url_set_) + return url_; + else + return GURL(text_); +} + +void Label::GetTextSize(CSize* out) { + if (!text_size_valid_) { + text_size_.cx = font_.GetStringWidth(text_); + text_size_.cy = font_.height(); + text_size_valid_ = true; + } + + if (text_size_valid_) { + *out = text_size_; + } else { + out->cx = out->cy = 0; + } +} + +int Label::GetHeightForWidth(int w) { + if (is_multi_line_) { + int h = 0; + ChromeCanvas cc(0, 0, true); + cc.SizeStringInt(text_, font_, &w, &h, ComputeMultiLineFlags()); + return h; + } + + return View::GetHeightForWidth(w); +} + +std::string Label::GetClassName() const { + return kViewClassName; +} + +void Label::SetColor(const SkColor& color) { + color_ = color; +} + +const SkColor Label::GetColor() const { + return color_; +} + +void Label::SetHorizontalAlignment(Alignment a) { + if (horiz_alignment_ != a) { + + // If the View's UI layout is right-to-left, we need to flip the alignment + // so that the alignment settings take into account the text + // directionality. + if (UILayoutIsRightToLeft()) { + if (a == ALIGN_LEFT) + a = ALIGN_RIGHT; + else if (a == ALIGN_RIGHT) + a = ALIGN_LEFT; + } + horiz_alignment_ = a; + SchedulePaint(); + } +} + +Label::Alignment Label::GetHorizontalAlignment() const { + return horiz_alignment_; +} + +void Label::SetMultiLine(bool f) { + if (f != is_multi_line_) { + is_multi_line_ = f; + SchedulePaint(); + } +} + +bool Label::IsMultiLine() { + return is_multi_line_; +} + +void Label::SetTooltipText(const std::wstring& tooltip_text) { + tooltip_text_ = tooltip_text; +} + +bool Label::GetTooltipText(int x, int y, std::wstring* tooltip) { + DCHECK(tooltip); + + // If a tooltip has been explicitly set, use it. + if (!tooltip_text_.empty()) { + tooltip->assign(tooltip_text_); + return true; + } + + // Show the full text if the text does not fit. + if (!is_multi_line_ && font_.GetStringWidth(text_) > GetWidth()) { + *tooltip = text_; + return true; + } + return false; +} + +void Label::OnMouseMoved(const MouseEvent& e) { + UpdateContainsMouse(e); +} + +void Label::OnMouseEntered(const MouseEvent& event) { + UpdateContainsMouse(event); +} + +void Label::OnMouseExited(const MouseEvent& event) { + SetContainsMouse(false); +} + +void Label::SetMouseOverBackground(Background* background) { + mouse_over_background_.reset(background); +} + +const Background* Label::GetMouseOverBackground() const { + return mouse_over_background_.get(); +} + +void Label::SetEnabled(bool enabled) { + if (enabled == enabled_) + return; + View::SetEnabled(enabled); + SetColor(enabled ? kEnabledColor : kDisabledColor); +} + +// static +ChromeFont Label::GetDefaultFont() { + return ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont); +} + +void Label::UpdateContainsMouse(const MouseEvent& event) { + SetContainsMouse(GetTextBounds().Contains(event.GetX(), event.GetY())); +} + +void Label::SetContainsMouse(bool contains_mouse) { + if (contains_mouse_ == contains_mouse) + return; + contains_mouse_ = contains_mouse; + if (GetMouseOverBackground()) + SchedulePaint(); +} + +gfx::Rect Label::GetTextBounds() { + CSize text_size; + GetTextSize(&text_size); + gfx::Insets insets = GetInsets(); + int avail_width = GetWidth() - insets.left() - insets.right(); + // Respect the size set by the owner view + text_size.cx = std::min(avail_width, static_cast<int>(text_size.cx)); + + int text_y = insets.top() + + (GetHeight() - text_size.cy - insets.top() - insets.bottom()) / 2; + int text_x; + switch (horiz_alignment_) { + case ALIGN_LEFT: + text_x = insets.left(); + break; + case ALIGN_CENTER: + // We put any extra margin pixel on the left rather than the right, since + // GetTextExtentPoint32() can report a value one too large on the right. + text_x = insets.left() + (avail_width + 1 - text_size.cx) / 2; + break; + case ALIGN_RIGHT: + text_x = GetWidth() - insets.right() - text_size.cx; + break; + } + return gfx::Rect(text_x, text_y, text_size.cx, text_size.cy); +} + +void Label::SizeToFit(int max_width) { + DCHECK(is_multi_line_); + + std::vector<std::wstring> lines; + SplitString(text_, L'\n', &lines); + + int width = 0; + for (std::vector<std::wstring>::const_iterator iter = lines.begin(); + iter != lines.end(); ++iter) { + width = std::max(width, font_.GetStringWidth(*iter)); + } + + if (max_width > 0) + width = std::min(width, max_width); + + CRect out; + GetBounds(&out); + SetBounds(out.left, out.top, width, 0); + SizeToPreferredSize(); +} + +bool Label::GetAccessibleRole(VARIANT* role) { + DCHECK(role); + + role->vt = VT_I4; + role->lVal = ROLE_SYSTEM_TEXT; + return true; +} + +bool Label::GetAccessibleName(std::wstring* name) { + *name = GetText(); + return true; +} + +bool Label::GetAccessibleState(VARIANT* state) { + DCHECK(state); + + state->lVal |= STATE_SYSTEM_READONLY; + return true; +} + +} |