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

Side by Side Diff: ui/views/corewm/tooltip_aura.cc

Issue 924433002: Use RenderText directly to draw tooltip (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: set_owned_by_client Created 5 years, 10 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
« no previous file with comments | « ui/views/corewm/tooltip_aura.h ('k') | ui/views/corewm/tooltip_aura_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/corewm/tooltip_aura.h" 5 #include "ui/views/corewm/tooltip_aura.h"
6 6
7 #include "base/strings/string_split.h" 7 #include "base/strings/string_split.h"
8 #include "base/strings/string_util.h"
8 #include "ui/aura/window.h" 9 #include "ui/aura/window.h"
9 #include "ui/aura/window_tree_host.h" 10 #include "ui/aura/window_tree_host.h"
11 #include "ui/gfx/canvas.h"
12 #include "ui/gfx/render_text.h"
10 #include "ui/gfx/screen.h" 13 #include "ui/gfx/screen.h"
11 #include "ui/gfx/text_elider.h" 14 #include "ui/gfx/text_elider.h"
12 #include "ui/gfx/text_utils.h" 15 #include "ui/gfx/text_utils.h"
13 #include "ui/native_theme/native_theme.h" 16 #include "ui/native_theme/native_theme.h"
14 #include "ui/views/background.h" 17 #include "ui/views/background.h"
15 #include "ui/views/border.h" 18 #include "ui/views/border.h"
19 #include "ui/views/view.h"
16 #include "ui/views/widget/widget.h" 20 #include "ui/views/widget/widget.h"
17 21
18 namespace { 22 namespace {
19 23
20 // Max visual tooltip width. If a tooltip is greater than this width, it will 24 // Max visual tooltip width. If a tooltip is greater than this width, it will
21 // be wrapped. 25 // be wrapped.
22 const int kTooltipMaxWidthPixels = 400; 26 const int kTooltipMaxWidthPixels = 400;
23 27
24 const size_t kMaxLines = 10;
25
26 // FIXME: get cursor offset from actual cursor size. 28 // FIXME: get cursor offset from actual cursor size.
27 const int kCursorOffsetX = 10; 29 const int kCursorOffsetX = 10;
28 const int kCursorOffsetY = 15; 30 const int kCursorOffsetY = 15;
29 31
30 // Creates a widget of type TYPE_TOOLTIP 32 // Creates a widget of type TYPE_TOOLTIP
31 views::Widget* CreateTooltipWidget(aura::Window* tooltip_window) { 33 views::Widget* CreateTooltipWidget(aura::Window* tooltip_window) {
32 views::Widget* widget = new views::Widget; 34 views::Widget* widget = new views::Widget;
33 views::Widget::InitParams params; 35 views::Widget::InitParams params;
34 // For aura, since we set the type to TYPE_TOOLTIP, the widget will get 36 // For aura, since we set the type to TYPE_TOOLTIP, the widget will get
35 // auto-parented to the right container. 37 // auto-parented to the right container.
36 params.type = views::Widget::InitParams::TYPE_TOOLTIP; 38 params.type = views::Widget::InitParams::TYPE_TOOLTIP;
37 params.context = tooltip_window; 39 params.context = tooltip_window;
38 DCHECK(params.context); 40 DCHECK(params.context);
39 params.keep_on_top = true; 41 params.keep_on_top = true;
40 params.accept_events = false; 42 params.accept_events = false;
41 widget->Init(params); 43 widget->Init(params);
42 return widget; 44 return widget;
43 } 45 }
44 46
45 } // namespace 47 } // namespace
46 48
47 namespace views { 49 namespace views {
48 namespace corewm { 50 namespace corewm {
49 51
52 // TODO(oshima): Consider to use views::Label.
53 class TooltipAura::TooltipView : public views::View {
54 public:
55 TooltipView()
56 : render_text_(gfx::RenderText::CreateInstance()),
57 max_width_(0) {
58 set_owned_by_client();
59 render_text_->SetMultiline(true);
60 ResetDisplayRect();
61 }
62
63 ~TooltipView() override {}
64
65 // views:View:
66 void OnPaint(gfx::Canvas* canvas) override {
67 OnPaintBackground(canvas);
68 render_text_->SetDisplayRect(gfx::Rect(size()));
69 render_text_->Draw(canvas);
70 OnPaintBorder(canvas);
71 }
72
73 gfx::Size GetPreferredSize() const override {
74 return render_text_->GetStringSize();
75 }
76
77 const char* GetClassName() const override {
78 return "TooltipView";
79 }
80
81 void SetText(const base::string16& text) {
82 render_text_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
83 render_text_->SetText(text);
84 }
85
86 void SetForegroundColor(SkColor color) {
87 render_text_->SetColor(color);
88 }
89
90 void SetMaxWidth(int width) {
91 max_width_ = width;
92 ResetDisplayRect();
93 }
94
95 private:
96 void ResetDisplayRect() {
97 render_text_->SetDisplayRect(gfx::Rect(0, 0, max_width_, 100000));
98 }
99
100 scoped_ptr<gfx::RenderText> render_text_;
101 int max_width_;
102
103 DISALLOW_COPY_AND_ASSIGN(TooltipView);
104 };
105
50 TooltipAura::TooltipAura() 106 TooltipAura::TooltipAura()
51 : widget_(NULL), 107 : tooltip_view_(new TooltipView),
108 widget_(NULL),
52 tooltip_window_(NULL) { 109 tooltip_window_(NULL) {
53 label_.set_owned_by_client();
54 label_.SetMultiLine(true);
55 label_.SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
56 110
57 const int kHorizontalPadding = 3; 111 const int kHorizontalPadding = 3;
58 const int kVerticalPadding = 2; 112 const int kVerticalPadding = 2;
59 label_.SetBorder(Border::CreateEmptyBorder( 113 tooltip_view_->SetBorder(Border::CreateEmptyBorder(
60 kVerticalPadding, kHorizontalPadding, 114 kVerticalPadding, kHorizontalPadding,
61 kVerticalPadding, kHorizontalPadding)); 115 kVerticalPadding, kHorizontalPadding));
62 } 116 }
63 117
64 TooltipAura::~TooltipAura() { 118 TooltipAura::~TooltipAura() {
65 DestroyWidget(); 119 DestroyWidget();
66 } 120 }
67 121
68 // static
69 void TooltipAura::TrimTooltipToFit(const gfx::FontList& font_list,
70 int max_width,
71 base::string16* text,
72 int* width,
73 int* line_count) {
74 *width = 0;
75 *line_count = 0;
76
77 // Determine the available width for the tooltip.
78 int available_width = std::min(kTooltipMaxWidthPixels, max_width);
79
80 std::vector<base::string16> lines;
81 base::SplitString(*text, '\n', &lines);
82 std::vector<base::string16> result_lines;
83
84 // Format each line to fit.
85 for (std::vector<base::string16>::iterator l = lines.begin();
86 l != lines.end(); ++l) {
87 // We break the line at word boundaries, then stuff as many words as we can
88 // in the available width to the current line, and move the remaining words
89 // to a new line.
90 std::vector<base::string16> words;
91 base::SplitStringDontTrim(*l, ' ', &words);
92 int current_width = 0;
93 base::string16 line;
94 for (std::vector<base::string16>::iterator w = words.begin();
95 w != words.end(); ++w) {
96 base::string16 word = *w;
97 if (w + 1 != words.end())
98 word.push_back(' ');
99 int word_width = gfx::GetStringWidth(word, font_list);
100 if (current_width + word_width > available_width) {
101 // Current width will exceed the available width. Must start a new line.
102 if (!line.empty())
103 result_lines.push_back(line);
104 current_width = 0;
105 line.clear();
106 }
107 current_width += word_width;
108 line.append(word);
109 }
110 result_lines.push_back(line);
111 }
112
113 // Clamp number of lines to |kMaxLines|.
114 if (result_lines.size() > kMaxLines) {
115 result_lines.resize(kMaxLines);
116 // Add ellipses character to last line.
117 result_lines[kMaxLines - 1] = gfx::TruncateString(
118 result_lines.back(), result_lines.back().length() - 1, gfx::WORD_BREAK);
119 }
120 *line_count = result_lines.size();
121
122 // Flatten the result.
123 base::string16 result;
124 for (std::vector<base::string16>::iterator l = result_lines.begin();
125 l != result_lines.end(); ++l) {
126 if (!result.empty())
127 result.push_back('\n');
128 int line_width = gfx::GetStringWidth(*l, font_list);
129 // Since we only break at word boundaries, it could happen that due to some
130 // very long word, line_width is greater than the available_width. In such
131 // case, we simply truncate at available_width and add ellipses at the end.
132 if (line_width > available_width) {
133 *width = available_width;
134 result.append(gfx::ElideText(*l, font_list, available_width,
135 gfx::ELIDE_TAIL));
136 } else {
137 *width = std::max(*width, line_width);
138 result.append(*l);
139 }
140 }
141 *text = result;
142 }
143
144 void TooltipAura::SetTooltipBounds(const gfx::Point& mouse_pos, 122 void TooltipAura::SetTooltipBounds(const gfx::Point& mouse_pos,
145 const gfx::Size& tooltip_size) { 123 const gfx::Size& tooltip_size) {
146 gfx::Rect tooltip_rect(mouse_pos, tooltip_size); 124 gfx::Rect tooltip_rect(mouse_pos, tooltip_size);
147 tooltip_rect.Offset(kCursorOffsetX, kCursorOffsetY); 125 tooltip_rect.Offset(kCursorOffsetX, kCursorOffsetY);
148 gfx::Screen* screen = gfx::Screen::GetScreenFor(tooltip_window_); 126 gfx::Screen* screen = gfx::Screen::GetScreenFor(tooltip_window_);
149 gfx::Rect display_bounds(screen->GetDisplayNearestPoint(mouse_pos).bounds()); 127 gfx::Rect display_bounds(screen->GetDisplayNearestPoint(mouse_pos).bounds());
150 128
151 // If tooltip is out of bounds on the x axis, we simply shift it 129 // If tooltip is out of bounds on the x axis, we simply shift it
152 // horizontally by the offset. 130 // horizontally by the offset.
153 if (tooltip_rect.right() > display_bounds.right()) { 131 if (tooltip_rect.right() > display_bounds.right()) {
(...skipping 22 matching lines...) Expand all
176 aura::Window* context) const { 154 aura::Window* context) const {
177 gfx::Screen* screen = gfx::Screen::GetScreenFor(context); 155 gfx::Screen* screen = gfx::Screen::GetScreenFor(context);
178 gfx::Rect display_bounds(screen->GetDisplayNearestPoint(location).bounds()); 156 gfx::Rect display_bounds(screen->GetDisplayNearestPoint(location).bounds());
179 return std::min(kTooltipMaxWidthPixels, (display_bounds.width() + 1) / 2); 157 return std::min(kTooltipMaxWidthPixels, (display_bounds.width() + 1) / 2);
180 } 158 }
181 159
182 void TooltipAura::SetText(aura::Window* window, 160 void TooltipAura::SetText(aura::Window* window,
183 const base::string16& tooltip_text, 161 const base::string16& tooltip_text,
184 const gfx::Point& location) { 162 const gfx::Point& location) {
185 tooltip_window_ = window; 163 tooltip_window_ = window;
186 int max_width = 0; 164 tooltip_view_->SetMaxWidth(GetMaxWidth(location, window));
187 int line_count = 0; 165 tooltip_view_->SetText(tooltip_text);
188 base::string16 trimmed_text(tooltip_text);
189 TrimTooltipToFit(label_.font_list(), GetMaxWidth(location, window),
190 &trimmed_text, &max_width, &line_count);
191 label_.SetText(trimmed_text);
192 166
193 if (!widget_) { 167 if (!widget_) {
194 widget_ = CreateTooltipWidget(tooltip_window_); 168 widget_ = CreateTooltipWidget(tooltip_window_);
195 widget_->SetContentsView(&label_); 169 widget_->SetContentsView(tooltip_view_.get());
196 widget_->AddObserver(this); 170 widget_->AddObserver(this);
197 } 171 }
198 172
199 label_.SizeToFit(max_width + label_.GetInsets().width()); 173 SetTooltipBounds(location, tooltip_view_->GetPreferredSize());
200 SetTooltipBounds(location, label_.size());
201 174
202 ui::NativeTheme* native_theme = widget_->GetNativeTheme(); 175 ui::NativeTheme* native_theme = widget_->GetNativeTheme();
203 label_.set_background( 176 tooltip_view_->set_background(
204 views::Background::CreateSolidBackground( 177 views::Background::CreateSolidBackground(
205 native_theme->GetSystemColor( 178 native_theme->GetSystemColor(
206 ui::NativeTheme::kColorId_TooltipBackground))); 179 ui::NativeTheme::kColorId_TooltipBackground)));
207 180 tooltip_view_->SetForegroundColor(native_theme->GetSystemColor(
208 label_.SetAutoColorReadabilityEnabled(false);
209 label_.SetEnabledColor(native_theme->GetSystemColor(
210 ui::NativeTheme::kColorId_TooltipText)); 181 ui::NativeTheme::kColorId_TooltipText));
211 } 182 }
212 183
213 void TooltipAura::Show() { 184 void TooltipAura::Show() {
214 if (widget_) { 185 if (widget_) {
215 widget_->Show(); 186 widget_->Show();
216 widget_->StackAtTop(); 187 widget_->StackAtTop();
217 } 188 }
218 } 189 }
219 190
220 void TooltipAura::Hide() { 191 void TooltipAura::Hide() {
221 tooltip_window_ = NULL; 192 tooltip_window_ = NULL;
222 if (widget_) 193 if (widget_)
223 widget_->Hide(); 194 widget_->Hide();
224 } 195 }
225 196
226 bool TooltipAura::IsVisible() { 197 bool TooltipAura::IsVisible() {
227 return widget_ && widget_->IsVisible(); 198 return widget_ && widget_->IsVisible();
228 } 199 }
229 200
230 void TooltipAura::OnWidgetDestroying(views::Widget* widget) { 201 void TooltipAura::OnWidgetDestroying(views::Widget* widget) {
231 DCHECK_EQ(widget_, widget); 202 DCHECK_EQ(widget_, widget);
232 widget_ = NULL; 203 widget_ = NULL;
233 tooltip_window_ = NULL; 204 tooltip_window_ = NULL;
234 } 205 }
235 206
236 } // namespace corewm 207 } // namespace corewm
237 } // namespace views 208 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/corewm/tooltip_aura.h ('k') | ui/views/corewm/tooltip_aura_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698