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

Unified Diff: views/widget/tooltip_manager.cc

Issue 114054: Splits TooltipManager so that it can be ported and stubs out the GTK... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 7 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « views/widget/tooltip_manager.h ('k') | views/widget/tooltip_manager_gtk.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: views/widget/tooltip_manager.cc
===================================================================
--- views/widget/tooltip_manager.cc (revision 17063)
+++ views/widget/tooltip_manager.cc (working copy)
@@ -1,448 +0,0 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "views/widget/tooltip_manager.h"
-
-#include <windowsx.h>
-#include <limits>
-
-#include "app/gfx/text_elider.h"
-#include "app/l10n_util.h"
-#include "app/l10n_util_win.h"
-#include "app/win_util.h"
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "views/view.h"
-#include "views/widget/root_view.h"
-#include "views/widget/widget.h"
-
-namespace views {
-
-//static
-int TooltipManager::tooltip_height_ = 0;
-
-// Default timeout for the tooltip displayed using keyboard.
-// Timeout is mentioned in milliseconds.
-static const int kDefaultTimeout = 4000;
-
-// Maximum number of lines we allow in the tooltip.
-static const int kMaxLines = 6;
-
-// Maximum number of characters we allow in a tooltip.
-static const int kMaxTooltipLength = 1024;
-
-// Breaks |text| along line boundaries, placing each line of text into lines.
-static void SplitTooltipString(const std::wstring& text,
- std::vector<std::wstring>* lines) {
- size_t index = 0;
- size_t next_index;
- while ((next_index = text.find(TooltipManager::GetLineSeparator(), index))
- != std::wstring::npos && lines->size() < kMaxLines) {
- lines->push_back(text.substr(index, next_index - index));
- index = next_index + TooltipManager::GetLineSeparator().size();
- }
- if (next_index != text.size() && lines->size() < kMaxLines)
- lines->push_back(text.substr(index, text.size() - index));
-}
-
-// static
-int TooltipManager::GetTooltipHeight() {
- DCHECK(tooltip_height_ > 0);
- return tooltip_height_;
-}
-
-static gfx::Font DetermineDefaultFont() {
- HWND window = CreateWindowEx(
- WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
- TOOLTIPS_CLASS, NULL, 0 , 0, 0, 0, 0, NULL, NULL, NULL, NULL);
- HFONT hfont = reinterpret_cast<HFONT>(SendMessage(window, WM_GETFONT, 0, 0));
- gfx::Font font = hfont ? gfx::Font::CreateFont(hfont) : gfx::Font();
- DestroyWindow(window);
- return font;
-}
-
-// static
-gfx::Font TooltipManager::GetDefaultFont() {
- static gfx::Font* font = NULL;
- if (!font)
- font = new gfx::Font(DetermineDefaultFont());
- return *font;
-}
-
-// static
-const std::wstring& TooltipManager::GetLineSeparator() {
- static const std::wstring* separator = NULL;
- if (!separator)
- separator = new std::wstring(L"\r\n");
- return *separator;
-}
-
-TooltipManager::TooltipManager(Widget* widget, HWND parent)
- : widget_(widget),
- parent_(parent),
- last_mouse_x_(-1),
- last_mouse_y_(-1),
- tooltip_showing_(false),
- last_tooltip_view_(NULL),
- last_view_out_of_sync_(false),
- tooltip_width_(0),
- keyboard_tooltip_hwnd_(NULL),
-#pragma warning(suppress: 4355)
- keyboard_tooltip_factory_(this) {
- DCHECK(widget && parent);
- Init();
-}
-
-TooltipManager::~TooltipManager() {
- if (tooltip_hwnd_)
- DestroyWindow(tooltip_hwnd_);
- if (keyboard_tooltip_hwnd_)
- DestroyWindow(keyboard_tooltip_hwnd_);
-}
-
-void TooltipManager::Init() {
- // Create the tooltip control.
- tooltip_hwnd_ = CreateWindowEx(
- WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
- TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0,
- parent_, NULL, NULL, NULL);
-
- l10n_util::AdjustUIFontForWindow(tooltip_hwnd_);
-
- // This effectively turns off clipping of tooltips. We need this otherwise
- // multi-line text (\r\n) won't work right. The size doesn't really matter
- // (just as long as its bigger than the monitor's width) as we clip to the
- // screen size before rendering.
- SendMessage(tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0,
- std::numeric_limits<short>::max());
-
- // Add one tool that is used for all tooltips.
- toolinfo_.cbSize = sizeof(toolinfo_);
- toolinfo_.uFlags = TTF_TRANSPARENT | TTF_IDISHWND;
- toolinfo_.hwnd = parent_;
- toolinfo_.uId = reinterpret_cast<UINT_PTR>(parent_);
- // Setting this tells windows to call parent_ back (using a WM_NOTIFY
- // message) for the actual tooltip contents.
- toolinfo_.lpszText = LPSTR_TEXTCALLBACK;
- SetRectEmpty(&toolinfo_.rect);
- SendMessage(tooltip_hwnd_, TTM_ADDTOOL, 0, (LPARAM)&toolinfo_);
-}
-
-void TooltipManager::UpdateTooltip() {
- // Set last_view_out_of_sync_ to indicate the view is currently out of sync.
- // This doesn't update the view under the mouse immediately as it may cause
- // timing problems.
- last_view_out_of_sync_ = true;
- last_tooltip_view_ = NULL;
- // Hide the tooltip.
- SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
-}
-
-void TooltipManager::TooltipTextChanged(View* view) {
- if (view == last_tooltip_view_)
- UpdateTooltip(last_mouse_x_, last_mouse_y_);
-}
-
-LRESULT TooltipManager::OnNotify(int w_param, NMHDR* l_param, bool* handled) {
- *handled = false;
- if (l_param->hwndFrom == tooltip_hwnd_ && keyboard_tooltip_hwnd_ == NULL) {
- switch (l_param->code) {
- case TTN_GETDISPINFO: {
- if (last_view_out_of_sync_) {
- // View under the mouse is out of sync, determine it now.
- RootView* root_view = widget_->GetRootView();
- last_tooltip_view_ = root_view->GetViewForPoint(
- gfx::Point(last_mouse_x_, last_mouse_y_));
- last_view_out_of_sync_ = false;
- }
- // Tooltip control is asking for the tooltip to display.
- NMTTDISPINFOW* tooltip_info =
- reinterpret_cast<NMTTDISPINFOW*>(l_param);
- // Initialize the string, if we have a valid tooltip the string will
- // get reset below.
- tooltip_info->szText[0] = TEXT('\0');
- tooltip_text_.clear();
- tooltip_info->lpszText = NULL;
- clipped_text_.clear();
- if (last_tooltip_view_ != NULL) {
- tooltip_text_.clear();
- // Mouse is over a View, ask the View for it's tooltip.
- gfx::Point view_loc(last_mouse_x_, last_mouse_y_);
- View::ConvertPointToView(widget_->GetRootView(),
- last_tooltip_view_, &view_loc);
- if (last_tooltip_view_->GetTooltipText(view_loc.x(), view_loc.y(),
- &tooltip_text_) &&
- !tooltip_text_.empty()) {
- // View has a valid tip, copy it into TOOLTIPINFO.
- clipped_text_ = tooltip_text_;
- TrimTooltipToFit(&clipped_text_, &tooltip_width_, &line_count_,
- last_mouse_x_, last_mouse_y_, tooltip_hwnd_);
- // Adjust the clipped tooltip text for locale direction.
- l10n_util::AdjustStringForLocaleDirection(clipped_text_,
- &clipped_text_);
- tooltip_info->lpszText = const_cast<WCHAR*>(clipped_text_.c_str());
- } else {
- tooltip_text_.clear();
- }
- }
- *handled = true;
- return 0;
- }
- case TTN_POP:
- tooltip_showing_ = false;
- *handled = true;
- return 0;
- case TTN_SHOW: {
- *handled = true;
- tooltip_showing_ = true;
- // The tooltip is about to show, allow the view to position it
- gfx::Point text_origin;
- if (tooltip_height_ == 0)
- tooltip_height_ = CalcTooltipHeight();
- gfx::Point view_loc(last_mouse_x_, last_mouse_y_);
- View::ConvertPointToView(widget_->GetRootView(),
- last_tooltip_view_, &view_loc);
- if (last_tooltip_view_->GetTooltipTextOrigin(
- view_loc.x(), view_loc.y(), &text_origin) &&
- SetTooltipPosition(text_origin.x(), text_origin.y())) {
- // Return true, otherwise the rectangle we specified is ignored.
- return TRUE;
- }
- return 0;
- }
- default:
- // Fall through.
- break;
- }
- }
- return 0;
-}
-
-bool TooltipManager::SetTooltipPosition(int text_x, int text_y) {
- // NOTE: this really only tests that the y location fits on screen, but that
- // is good enough for our usage.
-
- // Calculate the bounds the tooltip will get.
- gfx::Point view_loc;
- View::ConvertPointToScreen(last_tooltip_view_, &view_loc);
- RECT bounds = { view_loc.x() + text_x,
- view_loc.y() + text_y,
- view_loc.x() + text_x + tooltip_width_,
- view_loc.y() + line_count_ * GetTooltipHeight() };
- SendMessage(tooltip_hwnd_, TTM_ADJUSTRECT, TRUE, (LPARAM)&bounds);
-
- // Make sure the rectangle completely fits on the current monitor. If it
- // doesn't, return false so that windows positions the tooltip at the
- // default location.
- gfx::Rect monitor_bounds =
- win_util::GetMonitorBoundsForRect(gfx::Rect(bounds.left,bounds.right,
- 0, 0));
- if (!monitor_bounds.Contains(gfx::Rect(bounds))) {
- return false;
- }
-
- ::SetWindowPos(tooltip_hwnd_, NULL, bounds.left, bounds.top, 0, 0,
- SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
- return true;
-}
-
-int TooltipManager::CalcTooltipHeight() {
- // Ask the tooltip for it's font.
- int height;
- HFONT hfont = reinterpret_cast<HFONT>(
- SendMessage(tooltip_hwnd_, WM_GETFONT, 0, 0));
- if (hfont != NULL) {
- HDC dc = GetDC(tooltip_hwnd_);
- HFONT previous_font = static_cast<HFONT>(SelectObject(dc, hfont));
- int last_map_mode = SetMapMode(dc, MM_TEXT);
- TEXTMETRIC font_metrics;
- GetTextMetrics(dc, &font_metrics);
- height = font_metrics.tmHeight;
- // To avoid the DC referencing font_handle_, select the previous font.
- SelectObject(dc, previous_font);
- SetMapMode(dc, last_map_mode);
- ReleaseDC(NULL, dc);
- } else {
- // Tooltip is using the system font. Use gfx::Font, which should pick
- // up the system font.
- height = gfx::Font().height();
- }
- // Get the margins from the tooltip
- RECT tooltip_margin;
- SendMessage(tooltip_hwnd_, TTM_GETMARGIN, 0, (LPARAM)&tooltip_margin);
- return height + tooltip_margin.top + tooltip_margin.bottom;
-}
-
-void TooltipManager::TrimTooltipToFit(std::wstring* text,
- int* max_width,
- int* line_count,
- int position_x,
- int position_y,
- HWND window) {
- *max_width = 0;
- *line_count = 0;
-
- // Clamp the tooltip length to kMaxTooltipLength so that we don't
- // accidentally DOS the user with a mega tooltip (since Windows doesn't seem
- // to do this itself).
- if (text->length() > kMaxTooltipLength)
- *text = text->substr(0, kMaxTooltipLength);
-
- // Determine the available width for the tooltip.
- gfx::Point screen_loc(position_x, position_y);
- View::ConvertPointToScreen(widget_->GetRootView(), &screen_loc);
- gfx::Rect monitor_bounds =
- win_util::GetMonitorBoundsForRect(gfx::Rect(screen_loc.x(),
- screen_loc.y(),
- 0, 0));
- RECT tooltip_margin;
- SendMessage(window, TTM_GETMARGIN, 0, (LPARAM)&tooltip_margin);
- const int available_width = monitor_bounds.width() - tooltip_margin.left -
- tooltip_margin.right;
- if (available_width <= 0)
- return;
-
- // Split the string.
- std::vector<std::wstring> lines;
- SplitTooltipString(*text, &lines);
- *line_count = static_cast<int>(lines.size());
-
- // Format each line to fit.
- gfx::Font font = GetDefaultFont();
- std::wstring result;
- for (std::vector<std::wstring>::iterator i = lines.begin(); i != lines.end();
- ++i) {
- std::wstring elided_text = gfx::ElideText(*i, font, available_width);
- *max_width = std::max(*max_width, font.GetStringWidth(elided_text));
- if (i == lines.begin() && i + 1 == lines.end()) {
- *text = elided_text;
- return;
- }
- if (!result.empty())
- result.append(GetLineSeparator());
- result.append(elided_text);
- }
- *text = result;
-}
-
-void TooltipManager::UpdateTooltip(int x, int y) {
- RootView* root_view = widget_->GetRootView();
- View* view = root_view->GetViewForPoint(gfx::Point(x, y));
- if (view != last_tooltip_view_) {
- // NOTE: This *must* be sent regardless of the visibility of the tooltip.
- // It triggers Windows to ask for the tooltip again.
- SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
- last_tooltip_view_ = view;
- } else if (last_tooltip_view_ != NULL) {
- // Tooltip is showing, and mouse is over the same view. See if the tooltip
- // text has changed.
- gfx::Point view_point(x, y);
- View::ConvertPointToView(root_view, last_tooltip_view_, &view_point);
- std::wstring new_tooltip_text;
- if (last_tooltip_view_->GetTooltipText(view_point.x(), view_point.y(),
- &new_tooltip_text) &&
- new_tooltip_text != tooltip_text_) {
- // The text has changed, hide the popup.
- SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
- if (!new_tooltip_text.empty() && tooltip_showing_) {
- // New text is valid, show the popup.
- SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0);
- }
- }
- }
-}
-
-void TooltipManager::OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param) {
- int x = GET_X_LPARAM(l_param);
- int y = GET_Y_LPARAM(l_param);
-
- if (u_msg >= WM_NCMOUSEMOVE && u_msg <= WM_NCXBUTTONDBLCLK) {
- // NC message coordinates are in screen coordinates.
- gfx::Rect frame_bounds;
- widget_->GetBounds(&frame_bounds, true);
- x -= frame_bounds.x();
- y -= frame_bounds.y();
- }
-
- if (u_msg != WM_MOUSEMOVE || last_mouse_x_ != x || last_mouse_y_ != y) {
- last_mouse_x_ = x;
- last_mouse_y_ = y;
- HideKeyboardTooltip();
- UpdateTooltip(x, y);
- }
- // Forward the message onto the tooltip.
- MSG msg;
- msg.hwnd = parent_;
- msg.message = u_msg;
- msg.wParam = w_param;
- msg.lParam = l_param;
- SendMessage(tooltip_hwnd_, TTM_RELAYEVENT, 0, (LPARAM)&msg);
-}
-
-void TooltipManager::ShowKeyboardTooltip(View* focused_view) {
- if (tooltip_showing_) {
- SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
- tooltip_text_.clear();
- }
- HideKeyboardTooltip();
- std::wstring tooltip_text;
- if (!focused_view->GetTooltipText(0, 0, &tooltip_text))
- return;
- gfx::Rect focused_bounds = focused_view->bounds();
- gfx::Point screen_point;
- focused_view->ConvertPointToScreen(focused_view, &screen_point);
- gfx::Point relative_point_coordinates;
- focused_view->ConvertPointToWidget(focused_view, &relative_point_coordinates);
- keyboard_tooltip_hwnd_ = CreateWindowEx(
- WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
- TOOLTIPS_CLASS, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
- SendMessage(keyboard_tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0,
- std::numeric_limits<short>::max());
- int tooltip_width;
- int line_count;
- TrimTooltipToFit(&tooltip_text, &tooltip_width, &line_count,
- relative_point_coordinates.x(),
- relative_point_coordinates.y(), keyboard_tooltip_hwnd_);
- TOOLINFO keyboard_toolinfo;
- memset(&keyboard_toolinfo, 0, sizeof(keyboard_toolinfo));
- keyboard_toolinfo.cbSize = sizeof(keyboard_toolinfo);
- keyboard_toolinfo.hwnd = parent_;
- keyboard_toolinfo.uFlags = TTF_TRACK | TTF_TRANSPARENT | TTF_IDISHWND ;
- keyboard_toolinfo.lpszText = const_cast<WCHAR*>(tooltip_text.c_str());
- SendMessage(keyboard_tooltip_hwnd_, TTM_ADDTOOL, 0,
- reinterpret_cast<LPARAM>(&keyboard_toolinfo));
- SendMessage(keyboard_tooltip_hwnd_, TTM_TRACKACTIVATE, TRUE,
- reinterpret_cast<LPARAM>(&keyboard_toolinfo));
- if (!tooltip_height_)
- tooltip_height_ = CalcTooltipHeight();
- RECT rect_bounds = {screen_point.x(),
- screen_point.y() + focused_bounds.height(),
- screen_point.x() + tooltip_width,
- screen_point.y() + focused_bounds.height() +
- line_count * tooltip_height_ };
- gfx::Rect monitor_bounds =
- win_util::GetMonitorBoundsForRect(gfx::Rect(rect_bounds));
- rect_bounds = gfx::Rect(rect_bounds).AdjustToFit(monitor_bounds).ToRECT();
- ::SetWindowPos(keyboard_tooltip_hwnd_, NULL, rect_bounds.left,
- rect_bounds.top, 0, 0,
- SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- keyboard_tooltip_factory_.NewRunnableMethod(
- &TooltipManager::DestroyKeyboardTooltipWindow, keyboard_tooltip_hwnd_),
- kDefaultTimeout);
-}
-
-void TooltipManager::HideKeyboardTooltip() {
- if (keyboard_tooltip_hwnd_ != NULL) {
- SendMessage(keyboard_tooltip_hwnd_, WM_CLOSE, 0, 0);
- keyboard_tooltip_hwnd_ = NULL;
- }
-}
-
-void TooltipManager::DestroyKeyboardTooltipWindow(HWND window_to_destroy) {
- if (keyboard_tooltip_hwnd_ == window_to_destroy)
- HideKeyboardTooltip();
-}
-
-} // namespace views
« no previous file with comments | « views/widget/tooltip_manager.h ('k') | views/widget/tooltip_manager_gtk.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698