| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 "views/widget/tooltip_manager_win.h" | 5 #include "views/widget/tooltip_manager_win.h" |
| 6 | 6 |
| 7 #include <windowsx.h> | 7 #include <windowsx.h> |
| 8 #include <limits> | 8 #include <limits> |
| 9 | 9 |
| 10 #include "app/gfx/text_elider.h" | 10 #include "app/gfx/font.h" |
| 11 #include "app/l10n_util.h" | 11 #include "app/l10n_util.h" |
| 12 #include "app/l10n_util_win.h" | 12 #include "app/l10n_util_win.h" |
| 13 #include "app/win_util.h" | 13 #include "app/win_util.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/message_loop.h" | 15 #include "base/message_loop.h" |
| 16 #include "views/view.h" | 16 #include "views/view.h" |
| 17 #include "views/widget/root_view.h" | 17 #include "views/widget/root_view.h" |
| 18 #include "views/widget/widget.h" | 18 #include "views/widget/widget.h" |
| 19 | 19 |
| 20 namespace views { | 20 namespace views { |
| 21 | 21 |
| 22 static int tooltip_height_ = 0; | 22 static int tooltip_height_ = 0; |
| 23 | 23 |
| 24 // Default timeout for the tooltip displayed using keyboard. | 24 // Default timeout for the tooltip displayed using keyboard. |
| 25 // Timeout is mentioned in milliseconds. | 25 // Timeout is mentioned in milliseconds. |
| 26 static const int kDefaultTimeout = 4000; | 26 static const int kDefaultTimeout = 4000; |
| 27 | 27 |
| 28 // Maximum number of lines we allow in the tooltip. | |
| 29 static const int kMaxLines = 6; | |
| 30 | |
| 31 // Maximum number of characters we allow in a tooltip. | |
| 32 static const int kMaxTooltipLength = 1024; | |
| 33 | |
| 34 // Breaks |text| along line boundaries, placing each line of text into lines. | |
| 35 static void SplitTooltipString(const std::wstring& text, | |
| 36 std::vector<std::wstring>* lines) { | |
| 37 size_t index = 0; | |
| 38 size_t next_index; | |
| 39 while ((next_index = text.find(TooltipManagerWin::GetLineSeparator(), index)) | |
| 40 != std::wstring::npos && lines->size() < kMaxLines) { | |
| 41 lines->push_back(text.substr(index, next_index - index)); | |
| 42 index = next_index + TooltipManagerWin::GetLineSeparator().size(); | |
| 43 } | |
| 44 if (next_index != text.size() && lines->size() < kMaxLines) | |
| 45 lines->push_back(text.substr(index, text.size() - index)); | |
| 46 } | |
| 47 | |
| 48 // static | 28 // static |
| 49 int TooltipManager::GetTooltipHeight() { | 29 int TooltipManager::GetTooltipHeight() { |
| 50 DCHECK(tooltip_height_ > 0); | 30 DCHECK(tooltip_height_ > 0); |
| 51 return tooltip_height_; | 31 return tooltip_height_; |
| 52 } | 32 } |
| 53 | 33 |
| 54 static gfx::Font DetermineDefaultFont() { | 34 static gfx::Font DetermineDefaultFont() { |
| 55 HWND window = CreateWindowEx( | 35 HWND window = CreateWindowEx( |
| 56 WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(), | 36 WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(), |
| 57 TOOLTIPS_CLASS, NULL, 0 , 0, 0, 0, 0, NULL, NULL, NULL, NULL); | 37 TOOLTIPS_CLASS, NULL, 0 , 0, 0, 0, 0, NULL, NULL, NULL, NULL); |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 tooltip_text_.clear(); | 154 tooltip_text_.clear(); |
| 175 // Mouse is over a View, ask the View for it's tooltip. | 155 // Mouse is over a View, ask the View for it's tooltip. |
| 176 gfx::Point view_loc(last_mouse_x_, last_mouse_y_); | 156 gfx::Point view_loc(last_mouse_x_, last_mouse_y_); |
| 177 View::ConvertPointToView(widget_->GetRootView(), | 157 View::ConvertPointToView(widget_->GetRootView(), |
| 178 last_tooltip_view_, &view_loc); | 158 last_tooltip_view_, &view_loc); |
| 179 if (last_tooltip_view_->GetTooltipText(view_loc.x(), view_loc.y(), | 159 if (last_tooltip_view_->GetTooltipText(view_loc.x(), view_loc.y(), |
| 180 &tooltip_text_) && | 160 &tooltip_text_) && |
| 181 !tooltip_text_.empty()) { | 161 !tooltip_text_.empty()) { |
| 182 // View has a valid tip, copy it into TOOLTIPINFO. | 162 // View has a valid tip, copy it into TOOLTIPINFO. |
| 183 clipped_text_ = tooltip_text_; | 163 clipped_text_ = tooltip_text_; |
| 164 gfx::Point screen_loc(last_mouse_x_, last_mouse_y_); |
| 165 View::ConvertPointToScreen(widget_->GetRootView(), &screen_loc); |
| 184 TrimTooltipToFit(&clipped_text_, &tooltip_width_, &line_count_, | 166 TrimTooltipToFit(&clipped_text_, &tooltip_width_, &line_count_, |
| 185 last_mouse_x_, last_mouse_y_, tooltip_hwnd_); | 167 screen_loc.x(), screen_loc.y()); |
| 186 // Adjust the clipped tooltip text for locale direction. | 168 // Adjust the clipped tooltip text for locale direction. |
| 187 l10n_util::AdjustStringForLocaleDirection(clipped_text_, | 169 l10n_util::AdjustStringForLocaleDirection(clipped_text_, |
| 188 &clipped_text_); | 170 &clipped_text_); |
| 189 tooltip_info->lpszText = const_cast<WCHAR*>(clipped_text_.c_str()); | 171 tooltip_info->lpszText = const_cast<WCHAR*>(clipped_text_.c_str()); |
| 190 } else { | 172 } else { |
| 191 tooltip_text_.clear(); | 173 tooltip_text_.clear(); |
| 192 } | 174 } |
| 193 } | 175 } |
| 194 *handled = true; | 176 *handled = true; |
| 195 return 0; | 177 return 0; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 // Tooltip is using the system font. Use gfx::Font, which should pick | 254 // Tooltip is using the system font. Use gfx::Font, which should pick |
| 273 // up the system font. | 255 // up the system font. |
| 274 height = gfx::Font().height(); | 256 height = gfx::Font().height(); |
| 275 } | 257 } |
| 276 // Get the margins from the tooltip | 258 // Get the margins from the tooltip |
| 277 RECT tooltip_margin; | 259 RECT tooltip_margin; |
| 278 SendMessage(tooltip_hwnd_, TTM_GETMARGIN, 0, (LPARAM)&tooltip_margin); | 260 SendMessage(tooltip_hwnd_, TTM_GETMARGIN, 0, (LPARAM)&tooltip_margin); |
| 279 return height + tooltip_margin.top + tooltip_margin.bottom; | 261 return height + tooltip_margin.top + tooltip_margin.bottom; |
| 280 } | 262 } |
| 281 | 263 |
| 282 void TooltipManagerWin::TrimTooltipToFit(std::wstring* text, | |
| 283 int* max_width, | |
| 284 int* line_count, | |
| 285 int position_x, | |
| 286 int position_y, | |
| 287 HWND window) { | |
| 288 *max_width = 0; | |
| 289 *line_count = 0; | |
| 290 | |
| 291 // Clamp the tooltip length to kMaxTooltipLength so that we don't | |
| 292 // accidentally DOS the user with a mega tooltip (since Windows doesn't seem | |
| 293 // to do this itself). | |
| 294 if (text->length() > kMaxTooltipLength) | |
| 295 *text = text->substr(0, kMaxTooltipLength); | |
| 296 | |
| 297 // Determine the available width for the tooltip. | |
| 298 gfx::Point screen_loc(position_x, position_y); | |
| 299 View::ConvertPointToScreen(widget_->GetRootView(), &screen_loc); | |
| 300 gfx::Rect monitor_bounds = | |
| 301 win_util::GetMonitorBoundsForRect(gfx::Rect(screen_loc.x(), | |
| 302 screen_loc.y(), | |
| 303 0, 0)); | |
| 304 RECT tooltip_margin; | |
| 305 SendMessage(window, TTM_GETMARGIN, 0, (LPARAM)&tooltip_margin); | |
| 306 const int available_width = monitor_bounds.width() - tooltip_margin.left - | |
| 307 tooltip_margin.right; | |
| 308 if (available_width <= 0) | |
| 309 return; | |
| 310 | |
| 311 // Split the string. | |
| 312 std::vector<std::wstring> lines; | |
| 313 SplitTooltipString(*text, &lines); | |
| 314 *line_count = static_cast<int>(lines.size()); | |
| 315 | |
| 316 // Format each line to fit. | |
| 317 gfx::Font font = GetDefaultFont(); | |
| 318 std::wstring result; | |
| 319 for (std::vector<std::wstring>::iterator i = lines.begin(); i != lines.end(); | |
| 320 ++i) { | |
| 321 std::wstring elided_text = gfx::ElideText(*i, font, available_width); | |
| 322 *max_width = std::max(*max_width, font.GetStringWidth(elided_text)); | |
| 323 if (i == lines.begin() && i + 1 == lines.end()) { | |
| 324 *text = elided_text; | |
| 325 return; | |
| 326 } | |
| 327 if (!result.empty()) | |
| 328 result.append(GetLineSeparator()); | |
| 329 result.append(elided_text); | |
| 330 } | |
| 331 *text = result; | |
| 332 } | |
| 333 | |
| 334 void TooltipManagerWin::UpdateTooltip(int x, int y) { | 264 void TooltipManagerWin::UpdateTooltip(int x, int y) { |
| 335 RootView* root_view = widget_->GetRootView(); | 265 RootView* root_view = widget_->GetRootView(); |
| 336 View* view = root_view->GetViewForPoint(gfx::Point(x, y)); | 266 View* view = root_view->GetViewForPoint(gfx::Point(x, y)); |
| 337 if (view != last_tooltip_view_) { | 267 if (view != last_tooltip_view_) { |
| 338 // NOTE: This *must* be sent regardless of the visibility of the tooltip. | 268 // NOTE: This *must* be sent regardless of the visibility of the tooltip. |
| 339 // It triggers Windows to ask for the tooltip again. | 269 // It triggers Windows to ask for the tooltip again. |
| 340 SendMessage(tooltip_hwnd_, TTM_POP, 0, 0); | 270 SendMessage(tooltip_hwnd_, TTM_POP, 0, 0); |
| 341 last_tooltip_view_ = view; | 271 last_tooltip_view_ = view; |
| 342 } else if (last_tooltip_view_ != NULL) { | 272 } else if (last_tooltip_view_ != NULL) { |
| 343 // Tooltip is showing, and mouse is over the same view. See if the tooltip | 273 // Tooltip is showing, and mouse is over the same view. See if the tooltip |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 SendMessage(tooltip_hwnd_, TTM_POP, 0, 0); | 320 SendMessage(tooltip_hwnd_, TTM_POP, 0, 0); |
| 391 tooltip_text_.clear(); | 321 tooltip_text_.clear(); |
| 392 } | 322 } |
| 393 HideKeyboardTooltip(); | 323 HideKeyboardTooltip(); |
| 394 std::wstring tooltip_text; | 324 std::wstring tooltip_text; |
| 395 if (!focused_view->GetTooltipText(0, 0, &tooltip_text)) | 325 if (!focused_view->GetTooltipText(0, 0, &tooltip_text)) |
| 396 return; | 326 return; |
| 397 gfx::Rect focused_bounds = focused_view->bounds(); | 327 gfx::Rect focused_bounds = focused_view->bounds(); |
| 398 gfx::Point screen_point; | 328 gfx::Point screen_point; |
| 399 focused_view->ConvertPointToScreen(focused_view, &screen_point); | 329 focused_view->ConvertPointToScreen(focused_view, &screen_point); |
| 400 gfx::Point relative_point_coordinates; | |
| 401 focused_view->ConvertPointToWidget(focused_view, &relative_point_coordinates); | |
| 402 keyboard_tooltip_hwnd_ = CreateWindowEx( | 330 keyboard_tooltip_hwnd_ = CreateWindowEx( |
| 403 WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(), | 331 WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(), |
| 404 TOOLTIPS_CLASS, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL); | 332 TOOLTIPS_CLASS, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL); |
| 405 SendMessage(keyboard_tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0, | 333 SendMessage(keyboard_tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0, |
| 406 std::numeric_limits<short>::max()); | 334 std::numeric_limits<short>::max()); |
| 407 int tooltip_width; | 335 int tooltip_width; |
| 408 int line_count; | 336 int line_count; |
| 409 TrimTooltipToFit(&tooltip_text, &tooltip_width, &line_count, | 337 TrimTooltipToFit(&tooltip_text, &tooltip_width, &line_count, |
| 410 relative_point_coordinates.x(), | 338 screen_point.x(), screen_point.y()); |
| 411 relative_point_coordinates.y(), keyboard_tooltip_hwnd_); | |
| 412 TOOLINFO keyboard_toolinfo; | 339 TOOLINFO keyboard_toolinfo; |
| 413 memset(&keyboard_toolinfo, 0, sizeof(keyboard_toolinfo)); | 340 memset(&keyboard_toolinfo, 0, sizeof(keyboard_toolinfo)); |
| 414 keyboard_toolinfo.cbSize = sizeof(keyboard_toolinfo); | 341 keyboard_toolinfo.cbSize = sizeof(keyboard_toolinfo); |
| 415 keyboard_toolinfo.hwnd = GetParent(); | 342 keyboard_toolinfo.hwnd = GetParent(); |
| 416 keyboard_toolinfo.uFlags = TTF_TRACK | TTF_TRANSPARENT | TTF_IDISHWND ; | 343 keyboard_toolinfo.uFlags = TTF_TRACK | TTF_TRANSPARENT | TTF_IDISHWND ; |
| 417 keyboard_toolinfo.lpszText = const_cast<WCHAR*>(tooltip_text.c_str()); | 344 keyboard_toolinfo.lpszText = const_cast<WCHAR*>(tooltip_text.c_str()); |
| 418 SendMessage(keyboard_tooltip_hwnd_, TTM_ADDTOOL, 0, | 345 SendMessage(keyboard_tooltip_hwnd_, TTM_ADDTOOL, 0, |
| 419 reinterpret_cast<LPARAM>(&keyboard_toolinfo)); | 346 reinterpret_cast<LPARAM>(&keyboard_toolinfo)); |
| 420 SendMessage(keyboard_tooltip_hwnd_, TTM_TRACKACTIVATE, TRUE, | 347 SendMessage(keyboard_tooltip_hwnd_, TTM_TRACKACTIVATE, TRUE, |
| 421 reinterpret_cast<LPARAM>(&keyboard_toolinfo)); | 348 reinterpret_cast<LPARAM>(&keyboard_toolinfo)); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 445 keyboard_tooltip_hwnd_ = NULL; | 372 keyboard_tooltip_hwnd_ = NULL; |
| 446 } | 373 } |
| 447 } | 374 } |
| 448 | 375 |
| 449 void TooltipManagerWin::DestroyKeyboardTooltipWindow(HWND window_to_destroy) { | 376 void TooltipManagerWin::DestroyKeyboardTooltipWindow(HWND window_to_destroy) { |
| 450 if (keyboard_tooltip_hwnd_ == window_to_destroy) | 377 if (keyboard_tooltip_hwnd_ == window_to_destroy) |
| 451 HideKeyboardTooltip(); | 378 HideKeyboardTooltip(); |
| 452 } | 379 } |
| 453 | 380 |
| 454 } // namespace views | 381 } // namespace views |
| OLD | NEW |