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

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: add tests 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)
msw 2013/03/14 23:24:30 nit: move the arg onto the next line so const isn'
Evan Stade 2013/03/15 02:42:27 is this really a part of our style guide? I see 89
sky 2013/03/15 03:32:18 It was in Google's c++ style guide, but was remove
msw 2013/03/15 08:38:02 Sorry about that, i'm behind the times!
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::AddLink(const ui::Range& range) {
31 DCHECK(!range.is_reversed());
32 DCHECK(!range.is_empty());
33 DCHECK(ui::Range(0, text_.size()).Contains(range));
34 link_ranges_.push(LinkRange(range));
msw 2013/03/14 23:24:30 Should this InvalidateLayout? I don't think it nee
Evan Stade 2013/03/15 02:42:27 it does need to do both because adding a link may
35 }
36
37 gfx::Insets StyledLabel::GetInsets() const {
38 gfx::Insets insets = View::GetInsets();
39 gfx::Insets focus_border_padding(1, 1, 1, 1);
msw 2013/03/14 23:24:30 nit: const
Evan Stade 2013/03/15 02:42:27 Done.
40 insets += focus_border_padding;
41 return insets;
42 }
43
44 int StyledLabel::GetHeightForWidth(int w) {
45 if (w != calculated_size_.width())
46 calculated_size_ = gfx::Size(w, CalculateAndDoLayout(w, true));
47
48 return calculated_size_.height();
49 }
50
51 void StyledLabel::Layout() {
52 CalculateAndDoLayout(GetLocalBounds().width(), false);
53 }
54
55 void StyledLabel::LinkClicked(Link* source, int event_flags) {
56 listener_->StyledLabelLinkClicked(link_targets_[source], event_flags);
57 }
58
59 int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
60 if (!dry_run) {
61 RemoveAllChildViews(true);
62 link_targets_.clear();
63 }
64
65 width -= GetInsets().width();
66 if (width <= 0)
67 return 0;
68
69 int line_height = CalculateLineHeight();
msw 2013/03/14 23:24:30 nit: const
Evan Stade 2013/03/15 02:42:27 Done.
70 // The index of the line we're on.
71 int line = 0;
72 // The x position (in pixels) of the line we're on, relative to content
73 // bounds.
74 int x = 0;
75
76 string16 remaining_string = text_;
77 std::priority_queue<LinkRange> link_ranges = link_ranges_;
78
79 // Iterate over the text, creating a bunch of labels and links and laying them
80 // out in the appropriate positions.
81 while (!remaining_string.empty()) {
82 // Don't put whitespace at beginning of a line.
83 if (x == 0)
84 TrimWhitespace(remaining_string, TRIM_LEADING, &remaining_string);
85
86 ui::Range range(ui::Range::InvalidRange());
87 if (!link_ranges.empty())
88 range = link_ranges.top().range;
89
90 gfx::Rect chunk_bounds(x, 0, width - x, 2 * line_height);
msw 2013/03/14 23:24:30 nit: const
Evan Stade 2013/03/15 02:42:27 Done.
91 std::vector<string16> substrings;
92 const gfx::Font& font =
msw 2013/03/14 23:24:30 nit: Remove this Font init and the resource_bundle
Evan Stade 2013/03/15 02:42:27 Done.
93 ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
94 ui::ElideRectangleText(remaining_string,
95 font,
96 chunk_bounds.width(),
97 chunk_bounds.height(),
98 ui::IGNORE_LONG_WORDS,
99 &substrings);
100
101 string16 chunk = substrings[0];
102 if (chunk.empty()) {
103 // Nothing fit on this line. Start a new line. If x is 0, there's no room
104 // for anything. Just abort.
105 if (x == 0)
106 break;
107
108 x = 0;
109 line++;
110 continue;
111 }
112
113 scoped_ptr<View> view;
114 size_t position = text_.size() - remaining_string.size();
msw 2013/03/14 23:24:30 nit: const
Evan Stade 2013/03/15 02:42:27 Done.
115 if (position >= range.start()) {
116 // This chunk is a link.
117 if (chunk.size() < range.length() && x != 0) {
118 // Don't wrap links. Try to fit them entirely on one line.
119 x = 0;
120 line++;
121 continue;
122 }
123
124 chunk = chunk.substr(0, range.length());
125 Link* link = new Link(chunk);
126 link->set_listener(this);
127 if (!dry_run)
128 link_targets_[link] = range;
129 view.reset(link);
130 link_ranges.pop();
131 } else {
132 // This chunk is normal text.
133 if (position + chunk.size() > range.start())
134 chunk = chunk.substr(0, range.start() - position);
135
136 Label* label = new Label(chunk);
137 // Give the label a focus border so that its preferred size matches
138 // links' preferred sizes.
139 label->SetHasFocusBorder(true);
140 view.reset(label);
141 }
142
143 // Lay out the views to overlap by 1 pixel to compensate for their border
144 // spacing. Otherwise, "<a>link</a>," will render as "link ,".
145 const int overlap = 1;
146 gfx::Size view_size = view->GetPreferredSize();
msw 2013/03/14 23:24:30 nit: const
Evan Stade 2013/03/15 02:42:27 Done.
147 DCHECK_EQ(line_height, view_size.height() - 2 * overlap);
msw 2013/03/14 23:24:30 nit: should line_height remove the focus border in
Evan Stade 2013/03/15 02:42:27 not sure I understand the question, but no, the li
msw 2013/03/15 08:38:02 Ah, I misread and thought that the lines were stac
148 if (!dry_run) {
149 view->SetBoundsRect(gfx::Rect(
150 gfx::Point(GetInsets().left() + x - overlap,
151 GetInsets().top() + line * line_height - overlap),
152 view_size));
153 AddChildView(view.release());
154 }
155 x += view_size.width() - 2 * overlap;
156
157 remaining_string = remaining_string.substr(chunk.size());
158 }
159
160 return (line + 1) * line_height + GetInsets().height();
161 }
162
163 int StyledLabel::CalculateLineHeight() {
164 Label label;
msw 2013/03/14 23:24:30 nit: static
Evan Stade 2013/03/15 02:42:27 class type statics are forbidden.
165 return label.GetPreferredSize().height();
166 }
167
168 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698