[SyncFS] Initialize SyncWorker when sync is enabled.
[chromium-blink-merge.git] / ui / views / corewm / tooltip_aura.cc
blob900031e0b37502f9a3feca929fcbd226404f3165
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.
5 #include "ui/views/corewm/tooltip_aura.h"
7 #include "base/strings/string_split.h"
8 #include "ui/aura/window.h"
9 #include "ui/aura/window_tree_host.h"
10 #include "ui/gfx/screen.h"
11 #include "ui/gfx/text_elider.h"
12 #include "ui/gfx/text_utils.h"
13 #include "ui/native_theme/native_theme.h"
14 #include "ui/views/background.h"
15 #include "ui/views/border.h"
16 #include "ui/views/widget/widget.h"
18 namespace {
20 const int kTooltipHorizontalPadding = 3;
22 // Max visual tooltip width. If a tooltip is greater than this width, it will
23 // be wrapped.
24 const int kTooltipMaxWidthPixels = 400;
26 const size_t kMaxLines = 10;
28 // TODO(derat): This padding is needed on Chrome OS devices but seems excessive
29 // when running the same binary on a Linux workstation; presumably there's a
30 // difference in font metrics. Rationalize this.
31 const int kTooltipVerticalPadding = 2;
33 // FIXME: get cursor offset from actual cursor size.
34 const int kCursorOffsetX = 10;
35 const int kCursorOffsetY = 15;
37 // Creates a widget of type TYPE_TOOLTIP
38 views::Widget* CreateTooltipWidget(aura::Window* tooltip_window) {
39 views::Widget* widget = new views::Widget;
40 views::Widget::InitParams params;
41 // For aura, since we set the type to TYPE_TOOLTIP, the widget will get
42 // auto-parented to the right container.
43 params.type = views::Widget::InitParams::TYPE_TOOLTIP;
44 params.context = tooltip_window;
45 DCHECK(params.context);
46 params.keep_on_top = true;
47 params.accept_events = false;
48 widget->Init(params);
49 return widget;
52 } // namespace
54 namespace views {
55 namespace corewm {
57 TooltipAura::TooltipAura(gfx::ScreenType screen_type)
58 : screen_type_(screen_type),
59 widget_(NULL),
60 tooltip_window_(NULL) {
61 label_.set_owned_by_client();
62 label_.SetMultiLine(true);
65 TooltipAura::~TooltipAura() {
66 DestroyWidget();
69 // static
70 void TooltipAura::TrimTooltipToFit(const gfx::FontList& font_list,
71 int max_width,
72 base::string16* text,
73 int* width,
74 int* line_count) {
75 *width = 0;
76 *line_count = 0;
78 // Determine the available width for the tooltip.
79 int available_width = std::min(kTooltipMaxWidthPixels, max_width);
81 std::vector<base::string16> lines;
82 base::SplitString(*text, '\n', &lines);
83 std::vector<base::string16> result_lines;
85 // Format each line to fit.
86 for (std::vector<base::string16>::iterator l = lines.begin();
87 l != lines.end(); ++l) {
88 // We break the line at word boundaries, then stuff as many words as we can
89 // in the available width to the current line, and move the remaining words
90 // to a new line.
91 std::vector<base::string16> words;
92 base::SplitStringDontTrim(*l, ' ', &words);
93 int current_width = 0;
94 base::string16 line;
95 for (std::vector<base::string16>::iterator w = words.begin();
96 w != words.end(); ++w) {
97 base::string16 word = *w;
98 if (w + 1 != words.end())
99 word.push_back(' ');
100 int word_width = gfx::GetStringWidth(word, font_list);
101 if (current_width + word_width > available_width) {
102 // Current width will exceed the available width. Must start a new line.
103 if (!line.empty())
104 result_lines.push_back(line);
105 current_width = 0;
106 line.clear();
108 current_width += word_width;
109 line.append(word);
111 result_lines.push_back(line);
114 // Clamp number of lines to |kMaxLines|.
115 if (result_lines.size() > kMaxLines) {
116 result_lines.resize(kMaxLines);
117 // Add ellipses character to last line.
118 result_lines[kMaxLines - 1] = gfx::TruncateString(
119 result_lines.back(), result_lines.back().length() - 1, gfx::WORD_BREAK);
121 *line_count = result_lines.size();
123 // Flatten the result.
124 base::string16 result;
125 for (std::vector<base::string16>::iterator l = result_lines.begin();
126 l != result_lines.end(); ++l) {
127 if (!result.empty())
128 result.push_back('\n');
129 int line_width = gfx::GetStringWidth(*l, font_list);
130 // Since we only break at word boundaries, it could happen that due to some
131 // very long word, line_width is greater than the available_width. In such
132 // case, we simply truncate at available_width and add ellipses at the end.
133 if (line_width > available_width) {
134 *width = available_width;
135 result.append(gfx::ElideText(*l, font_list, available_width,
136 gfx::ELIDE_TAIL));
137 } else {
138 *width = std::max(*width, line_width);
139 result.append(*l);
142 *text = result;
145 int TooltipAura::GetMaxWidth(const gfx::Point& location) const {
146 // TODO(varunjain): implementation duplicated in tooltip_manager_aura. Figure
147 // out a way to merge.
148 gfx::Screen* screen = gfx::Screen::GetScreenByType(screen_type_);
149 gfx::Rect display_bounds(screen->GetDisplayNearestPoint(location).bounds());
150 return (display_bounds.width() + 1) / 2;
153 void TooltipAura::SetTooltipBounds(const gfx::Point& mouse_pos,
154 int tooltip_width,
155 int tooltip_height) {
156 gfx::Rect tooltip_rect(mouse_pos.x(), mouse_pos.y(), tooltip_width,
157 tooltip_height);
159 tooltip_rect.Offset(kCursorOffsetX, kCursorOffsetY);
160 gfx::Screen* screen = gfx::Screen::GetScreenByType(screen_type_);
161 gfx::Rect display_bounds(screen->GetDisplayNearestPoint(mouse_pos).bounds());
163 // If tooltip is out of bounds on the x axis, we simply shift it
164 // horizontally by the offset.
165 if (tooltip_rect.right() > display_bounds.right()) {
166 int h_offset = tooltip_rect.right() - display_bounds.right();
167 tooltip_rect.Offset(-h_offset, 0);
170 // If tooltip is out of bounds on the y axis, we flip it to appear above the
171 // mouse cursor instead of below.
172 if (tooltip_rect.bottom() > display_bounds.bottom())
173 tooltip_rect.set_y(mouse_pos.y() - tooltip_height);
175 tooltip_rect.AdjustToFit(display_bounds);
176 widget_->SetBounds(tooltip_rect);
179 void TooltipAura::DestroyWidget() {
180 if (widget_) {
181 widget_->RemoveObserver(this);
182 widget_->Close();
183 widget_ = NULL;
187 void TooltipAura::SetText(aura::Window* window,
188 const base::string16& tooltip_text,
189 const gfx::Point& location) {
190 tooltip_window_ = window;
191 int max_width, line_count;
192 base::string16 trimmed_text(tooltip_text);
193 TrimTooltipToFit(label_.font_list(), GetMaxWidth(location), &trimmed_text,
194 &max_width, &line_count);
195 label_.SetText(trimmed_text);
197 int width = max_width + 2 * kTooltipHorizontalPadding;
198 int height = label_.GetHeightForWidth(max_width) +
199 2 * kTooltipVerticalPadding;
201 if (!widget_) {
202 widget_ = CreateTooltipWidget(tooltip_window_);
203 widget_->SetContentsView(&label_);
204 widget_->AddObserver(this);
207 SetTooltipBounds(location, width, height);
209 ui::NativeTheme* native_theme = widget_->GetNativeTheme();
210 label_.set_background(
211 views::Background::CreateSolidBackground(
212 native_theme->GetSystemColor(
213 ui::NativeTheme::kColorId_TooltipBackground)));
215 label_.SetAutoColorReadabilityEnabled(false);
216 label_.SetEnabledColor(native_theme->GetSystemColor(
217 ui::NativeTheme::kColorId_TooltipText));
220 void TooltipAura::Show() {
221 if (widget_) {
222 widget_->Show();
223 widget_->StackAtTop();
227 void TooltipAura::Hide() {
228 tooltip_window_ = NULL;
229 if (widget_)
230 widget_->Hide();
233 bool TooltipAura::IsVisible() {
234 return widget_ && widget_->IsVisible();
237 void TooltipAura::OnWidgetDestroying(views::Widget* widget) {
238 DCHECK_EQ(widget_, widget);
239 widget_ = NULL;
240 tooltip_window_ = NULL;
243 } // namespace corewm
244 } // namespace views