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

Side by Side Diff: ui/views/controls/styled_label.cc

Issue 12543032: Add views::RichLabel, a class which creates multi-line text with mixed (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: review 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/views/controls/styled_label.h"
6
7 #include <vector>
8
9 #include "base/string_util.h"
10 #include "ui/base/resource/resource_bundle.h"
11 #include "ui/base/text/text_elider.h"
12 #include "ui/views/controls/label.h"
13 #include "ui/views/controls/link.h"
14 #include "ui/views/controls/styled_label_listener.h"
15
16 namespace views {
17
18 bool StyledLabel::LinkRange::operator<(const StyledLabel::LinkRange& other)
19 const {
20 // Intentionally reversed so the priority queue is sorted by smallest first.
21 return range.start() > other.range.start();
22 }
23
24 StyledLabel::StyledLabel(const string16& text, StyledLabelListener* listener)
25 : text_(text),
26 listener_(listener) {}
27
28 StyledLabel::~StyledLabel() {}
29
30 void StyledLabel::SetLink(const ui::Range& range) {
31 DCHECK(ui::Range(0, text_.size()).Contains(range));
32 link_ranges_.push(LinkRange(range));
33 }
34
35 int StyledLabel::GetHeightForWidth(int w) {
36 if (w != calculated_size_.width())
37 calculated_size_ = gfx::Size(w, CalculateAndDoLayout(w, true));
38
39 return calculated_size_.height();
40 }
41
42 void StyledLabel::Layout() {
43 CalculateAndDoLayout(GetLocalBounds().width(), false);
44 }
45
46 int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
sky 2013/03/14 14:43:58 Can you also add some tests for coverage of this?
47 width -= GetInsets().width();
48 if (width <= 0)
49 return 0;
50
51 if (!dry_run) {
sky 2013/03/14 14:43:58 Should this be before the early return on 49?
Evan Stade 2013/03/14 19:07:40 Done.
52 RemoveAllChildViews(true);
53 link_targets_.clear();
54 }
55
56 gfx::Font font =
57 ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
58
59 int line_height = font.GetHeight();
60 // The index of the line we're on.
61 int line = 0;
62 // The x position (in pixels) of the line we're on.
63 int x = 0;
sky 2013/03/14 14:43:58 Doesn't this need to be set to GetInsets().left()
Evan Stade 2013/03/14 19:07:40 L132 needs to account for insets, but that's it (f
64
65 string16 remaining_string = text_;
66 std::priority_queue<LinkRange> link_ranges = link_ranges_;
67
68 // Iterate over the text, creating a bunch of labels and links and laying them
69 // out in the appropriate positions.
70 while (!remaining_string.empty()) {
71 // Don't put whitespace at beginning of a line.
72 if (x == 0)
73 TrimWhitespace(remaining_string, TRIM_LEADING, &remaining_string);
74
75 ui::Range range(ui::Range::InvalidRange());
76 if (!link_ranges.empty())
77 range = link_ranges.top().range;
78
79 gfx::Rect chunk_bounds(x, 0, width - x, 2 * line_height);
80 std::vector<string16> substrings;
81 ui::ElideRectangleText(remaining_string,
82 font,
83 chunk_bounds.width(),
84 chunk_bounds.height(),
85 ui::IGNORE_LONG_WORDS,
86 &substrings);
87
88 string16 chunk = substrings[0];
89 if (chunk.empty()) {
90 // Nothing fit on this line. Start a new line. If x is 0, there's no room
91 // for anything. Just abort.
92 if (x == 0)
93 break;
94
95 x = 0;
96 line++;
97 continue;
98 }
99
100 scoped_ptr<View> view;
101 size_t position = text_.size() - remaining_string.size();
102 if (position >= range.start()) {
103 // This chunk is a link.
104 if (chunk.size() < range.length() && x != 0) {
105 // Don't wrap links. Try to fit them entirely on one line.
106 x = 0;
107 line++;
108 continue;
109 }
110
111 chunk = chunk.substr(0, range.length());
112 Link* link = new Link(chunk);
113 link->set_listener(this);
114 if (!dry_run)
115 link_targets_[link] = range;
116 view.reset(link);
117 link_ranges.pop();
118 } else {
119 // This chunk is normal text.
120 if (position + chunk.size() > range.start())
121 chunk = chunk.substr(0, range.start() - position);
122
123 Label* label = new Label(chunk);
124 // Give the label a focus border so that its preferred height matches
125 // links' preferred heights.
126 label->SetHasFocusBorder(true);
127 view.reset(label);
128 }
129
130 gfx::Size view_size = view->GetPreferredSize();
131 if (!dry_run) {
132 view->SetBoundsRect(gfx::Rect(gfx::Point(x, line * line_height),
133 view_size));
134 AddChildView(view.release());
135 }
136 x += view_size.width();
137
138 remaining_string = remaining_string.substr(chunk.size());
139 }
140
141 return (line + 1) * line_height + GetInsets().height();
142 }
143
144 void StyledLabel::LinkClicked(Link* source, int event_flags) {
145 listener_->StyledLabelLinkClicked(link_targets_[source], event_flags);
146 }
147
148 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698