Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(458)

Unified Diff: ui/views/controls/styled_label.cc

Issue 12906002: Add ability to defined ranges with different styles in StyledLabel (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/views/controls/styled_label.h ('k') | ui/views/controls/styled_label_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/views/controls/styled_label.cc
diff --git a/ui/views/controls/styled_label.cc b/ui/views/controls/styled_label.cc
index d0fda3de315db4386b7c033f6a440112ae119226..b0e46a45ec3016f85b3f58f6f6358b8129c27027 100644
--- a/ui/views/controls/styled_label.cc
+++ b/ui/views/controls/styled_label.cc
@@ -23,33 +23,82 @@ int CalculateLineHeight() {
return label.GetPreferredSize().height();
}
+scoped_ptr<View> CreateLabelRange(const string16& text,
+ const StyledLabel::RangeStyleInfo& style_info,
+ views::LinkListener* link_listener) {
+ scoped_ptr<Label> result;
+
+ if (style_info.is_link) {
+ Link* link = new Link(text);
+ link->set_listener(link_listener);
+ link->SetUnderline((style_info.font_style & gfx::Font::UNDERLINE) != 0);
+ result.reset(link);
+ } else {
+ Label* label = new Label(text);
+ // Give the label a focus border so that its preferred size matches
+ // links' preferred sizes
+ label->SetHasFocusBorder(true);
+
+ result.reset(label);
+ }
+
+ if (!style_info.tooltip.empty())
+ result->SetTooltipText(style_info.tooltip);
+ if (style_info.font_style != gfx::Font::NORMAL)
+ result->SetFont(result->font().DeriveFont(0, style_info.font_style));
+
+ return scoped_ptr<View>(result.release());
+}
+
} // namespace
-bool StyledLabel::LinkRange::operator<(
- const StyledLabel::LinkRange& other) const {
+
+StyledLabel::RangeStyleInfo::RangeStyleInfo()
+ : font_style(gfx::Font::NORMAL),
+ disable_line_wrapping(false),
+ is_link(false) {
+}
+
+StyledLabel::RangeStyleInfo::~RangeStyleInfo() {}
+
+// static
+StyledLabel::RangeStyleInfo StyledLabel::RangeStyleInfo::CreateForLink() {
+ RangeStyleInfo result;
+ result.disable_line_wrapping = true;
+ result.is_link = true;
+ result.font_style = gfx::Font::UNDERLINE;
+ return result;
+}
+
+bool StyledLabel::StyleRange::operator<(
+ const StyledLabel::StyleRange& other) const {
// Intentionally reversed so the priority queue is sorted by smallest first.
return range.start() > other.range.start();
}
StyledLabel::StyledLabel(const string16& text, StyledLabelListener* listener)
- : text_(text),
- listener_(listener) {}
+ : listener_(listener) {
+ TrimWhitespace(text, TRIM_TRAILING, &text_);
+}
StyledLabel::~StyledLabel() {}
void StyledLabel::SetText(const string16& text) {
text_ = text;
calculated_size_ = gfx::Size();
- link_ranges_ = std::priority_queue<LinkRange>();
+ style_ranges_ = std::priority_queue<StyleRange>();
RemoveAllChildViews(true);
PreferredSizeChanged();
}
-void StyledLabel::AddLink(const ui::Range& range) {
+void StyledLabel::AddStyleRange(const ui::Range& range,
+ const RangeStyleInfo& style_info) {
DCHECK(!range.is_reversed());
DCHECK(!range.is_empty());
DCHECK(ui::Range(0, text_.size()).Contains(range));
- link_ranges_.push(LinkRange(range));
+
+ style_ranges_.push(StyleRange(range, style_info));
+
calculated_size_ = gfx::Size();
PreferredSizeChanged();
}
@@ -94,34 +143,53 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
int x = 0;
string16 remaining_string = text_;
- std::priority_queue<LinkRange> link_ranges = link_ranges_;
+ std::priority_queue<StyleRange> style_ranges = style_ranges_;
// Iterate over the text, creating a bunch of labels and links and laying them
// out in the appropriate positions.
while (!remaining_string.empty()) {
- // Don't put whitespace at beginning of a line.
- if (x == 0)
+ // Don't put whitespace at beginning of a line with an exception for the
+ // first line (so the text's leading whitespace is respected).
+ if (x == 0 && line > 0)
TrimWhitespace(remaining_string, TRIM_LEADING, &remaining_string);
ui::Range range(ui::Range::InvalidRange());
- if (!link_ranges.empty())
- range = link_ranges.top().range;
+ if (!style_ranges.empty())
+ range = style_ranges.top().range;
+
+ const size_t position = text_.size() - remaining_string.size();
const gfx::Rect chunk_bounds(x, 0, width - x, 2 * line_height);
std::vector<string16> substrings;
+ gfx::Font text_font;
+ // If the start of the remaining text is inside a styled range, the font
+ // style may differ from the base font. The font specified by the range
+ // should be used when eliding text.
+ if (position >= range.start()) {
+ text_font =
+ text_font.DeriveFont(0, style_ranges.top().style_info.font_style);
+ }
ui::ElideRectangleText(remaining_string,
- gfx::Font(),
+ text_font,
chunk_bounds.width(),
chunk_bounds.height(),
ui::IGNORE_LONG_WORDS,
&substrings);
+ DCHECK(!substrings.empty());
string16 chunk = substrings[0];
if (chunk.empty()) {
- // Nothing fit on this line. Start a new line. If x is 0, there's no room
- // for anything. Just abort.
- if (x == 0)
+ // Nothing fits on this line. Start a new line.
+ // If x is 0, first line may have leading whitespace that doesn't fit in a
+ // single line, so try trimming those. Otherwise there is no room for
+ // anything; abort.
+ if (x == 0) {
+ if (line == 0) {
+ TrimWhitespace(remaining_string, TRIM_LEADING, &remaining_string);
+ continue;
+ }
break;
+ }
x = 0;
line++;
@@ -129,33 +197,32 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
}
scoped_ptr<View> view;
- const size_t position = text_.size() - remaining_string.size();
if (position >= range.start()) {
- // This chunk is a link.
- if (chunk.size() < range.length() && x != 0) {
- // Don't wrap links. Try to fit them entirely on one line.
+ const RangeStyleInfo& style_info = style_ranges.top().style_info;
+
+ if (style_info.disable_line_wrapping && chunk.size() < range.length() &&
+ position == range.start() && x != 0) {
+ // If the chunk should not be wrapped, try to fit it entirely on the
+ // next line.
x = 0;
line++;
continue;
}
- chunk = chunk.substr(0, range.length());
- Link* link = new Link(chunk);
- link->set_listener(this);
- if (!dry_run)
- link_targets_[link] = range;
- view.reset(link);
- link_ranges.pop();
+ chunk = chunk.substr(0, std::min(chunk.size(), range.end() - position));
+
+ view = CreateLabelRange(chunk, style_info, this);
+
+ if (style_info.is_link && !dry_run)
+ link_targets_[view.get()] = range;
+
+ if (position + chunk.size() >= range.end())
+ style_ranges.pop();
} else {
// This chunk is normal text.
if (position + chunk.size() > range.start())
chunk = chunk.substr(0, range.start() - position);
-
- Label* label = new Label(chunk);
- // Give the label a focus border so that its preferred size matches
- // links' preferred sizes.
- label->SetHasFocusBorder(true);
- view.reset(label);
+ view = CreateLabelRange(chunk, RangeStyleInfo(), this);
}
// Lay out the views to overlap by 1 pixel to compensate for their border
« no previous file with comments | « ui/views/controls/styled_label.h ('k') | ui/views/controls/styled_label_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698