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

Unified Diff: views/widget/tooltip_manager_win.cc

Issue 8562003: Revert "views: Move widget/ directory to ui/views." properly. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 1 month 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_win.h ('k') | views/widget/widget.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: views/widget/tooltip_manager_win.cc
diff --git a/views/widget/tooltip_manager_win.cc b/views/widget/tooltip_manager_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..521fcc028bebfd8f809ef9cdc0086053387ec7d5
--- /dev/null
+++ b/views/widget/tooltip_manager_win.cc
@@ -0,0 +1,391 @@
+// Copyright (c) 2011 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_win.h"
+
+#include <windowsx.h>
+
+#include <limits>
+
+#include "base/bind.h"
+#include "base/i18n/rtl.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "ui/base/l10n/l10n_util_win.h"
+#include "ui/base/win/hwnd_util.h"
+#include "ui/gfx/font.h"
+#include "ui/gfx/screen.h"
+#include "views/view.h"
+#include "views/widget/monitor_win.h"
+#include "views/widget/widget.h"
+
+namespace views {
+
+static int tooltip_height_ = 0;
+
+// Default timeout for the tooltip displayed using keyboard.
+// Timeout is mentioned in milliseconds.
+static const int kDefaultTimeout = 4000;
+
+// static
+int TooltipManager::GetTooltipHeight() {
+ DCHECK_GT(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);
+ if (!window)
+ return gfx::Font();
+ HFONT hfont = reinterpret_cast<HFONT>(SendMessage(window, WM_GETFONT, 0, 0));
+ gfx::Font font = hfont ? gfx::Font(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
+int TooltipManager::GetMaxWidth(int x, int y) {
+ gfx::Rect monitor_bounds =
+ gfx::Screen::GetMonitorAreaNearestPoint(gfx::Point(x, y));
+ // Allow the tooltip to be almost as wide as the screen.
+ // Otherwise, we would truncate important text, since we're not word-wrapping
+ // the text onto multiple lines.
+ return monitor_bounds.width() == 0 ? 800 : monitor_bounds.width() - 30;
+}
+
+TooltipManagerWin::TooltipManagerWin(Widget* widget)
+ : widget_(widget),
+ tooltip_hwnd_(NULL),
+ last_mouse_pos_(-1, -1),
+ tooltip_showing_(false),
+ last_tooltip_view_(NULL),
+ last_view_out_of_sync_(false),
+ tooltip_width_(0),
+ keyboard_tooltip_hwnd_(NULL),
+ ALLOW_THIS_IN_INITIALIZER_LIST(keyboard_tooltip_factory_(this)) {
+ DCHECK(widget);
+ DCHECK(widget->GetNativeView());
+}
+
+TooltipManagerWin::~TooltipManagerWin() {
+ if (tooltip_hwnd_)
+ DestroyWindow(tooltip_hwnd_);
+ if (keyboard_tooltip_hwnd_)
+ DestroyWindow(keyboard_tooltip_hwnd_);
+}
+
+bool TooltipManagerWin::Init() {
+ DCHECK(!tooltip_hwnd_);
+ // Create the tooltip control.
+ tooltip_hwnd_ = CreateWindowEx(
+ WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+ TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0,
+ GetParent(), NULL, NULL, NULL);
+ if (!tooltip_hwnd_)
+ return false;
+
+ 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<int16>::max());
+
+ // Add one tool that is used for all tooltips.
+ toolinfo_.cbSize = sizeof(toolinfo_);
+ toolinfo_.uFlags = TTF_TRANSPARENT | TTF_IDISHWND;
+ toolinfo_.hwnd = GetParent();
+ toolinfo_.uId = reinterpret_cast<UINT_PTR>(GetParent());
+ // Setting this tells windows to call GetParent() back (using a WM_NOTIFY
+ // message) for the actual tooltip contents.
+ toolinfo_.lpszText = LPSTR_TEXTCALLBACK;
+ toolinfo_.lpReserved = NULL;
+ SetRectEmpty(&toolinfo_.rect);
+ SendMessage(tooltip_hwnd_, TTM_ADDTOOL, 0, (LPARAM)&toolinfo_);
+ return true;
+}
+
+gfx::NativeView TooltipManagerWin::GetParent() {
+ return widget_->GetNativeView();
+}
+
+void TooltipManagerWin::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 TooltipManagerWin::TooltipTextChanged(View* view) {
+ if (view == last_tooltip_view_)
+ UpdateTooltip(last_mouse_pos_);
+}
+
+LRESULT TooltipManagerWin::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.
+ View* root_view = widget_->GetRootView();
+ last_tooltip_view_ =
+ root_view->GetEventHandlerForPoint(last_mouse_pos_);
+ 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 its tooltip.
+ gfx::Point view_loc = last_mouse_pos_;
+ View::ConvertPointToView(widget_->GetRootView(),
+ last_tooltip_view_, &view_loc);
+ if (last_tooltip_view_->GetTooltipText(view_loc, &tooltip_text_) &&
+ !tooltip_text_.empty()) {
+ // View has a valid tip, copy it into TOOLTIPINFO.
+ clipped_text_ = tooltip_text_;
+ gfx::Point screen_loc = last_mouse_pos_;
+ View::ConvertPointToScreen(widget_->GetRootView(), &screen_loc);
+ TrimTooltipToFit(&clipped_text_, &tooltip_width_, &line_count_,
+ screen_loc.x(), screen_loc.y());
+ // Adjust the clipped tooltip text for locale direction.
+ base::i18n::AdjustStringForLocaleDirection(&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_pos_;
+ View::ConvertPointToView(widget_->GetRootView(),
+ last_tooltip_view_, &view_loc);
+ if (last_tooltip_view_->GetTooltipTextOrigin(view_loc, &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 TooltipManagerWin::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 =
+ views::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 TooltipManagerWin::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().GetHeight();
+ }
+ // 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 TooltipManagerWin::UpdateTooltip(const gfx::Point& mouse_pos) {
+ View* root_view = widget_->GetRootView();
+ View* view = root_view->GetEventHandlerForPoint(mouse_pos);
+ 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 = mouse_pos;
+ View::ConvertPointToView(root_view, last_tooltip_view_, &view_point);
+ string16 new_tooltip_text;
+ bool has_tooltip_text =
+ last_tooltip_view_->GetTooltipText(view_point, &new_tooltip_text);
+ if (!has_tooltip_text || (new_tooltip_text != tooltip_text_)) {
+ // The text has changed, hide the popup.
+ SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+ if (has_tooltip_text && !new_tooltip_text.empty() && tooltip_showing_) {
+ // New text is valid, show the popup.
+ SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0);
+ }
+ }
+ }
+}
+
+void TooltipManagerWin::OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param) {
+ gfx::Point mouse_pos(l_param);
+
+ if (u_msg >= WM_NCMOUSEMOVE && u_msg <= WM_NCXBUTTONDBLCLK) {
+ // NC message coordinates are in screen coordinates.
+ POINT temp = mouse_pos.ToPOINT();
+ ::MapWindowPoints(HWND_DESKTOP, GetParent(), &temp, 1);
+ mouse_pos.SetPoint(temp.x, temp.y);
+ }
+
+ if (u_msg != WM_MOUSEMOVE || last_mouse_pos_ != mouse_pos) {
+ last_mouse_pos_ = mouse_pos;
+ HideKeyboardTooltip();
+ UpdateTooltip(mouse_pos);
+ }
+ // Forward the message onto the tooltip.
+ MSG msg;
+ msg.hwnd = GetParent();
+ msg.message = u_msg;
+ msg.wParam = w_param;
+ msg.lParam = l_param;
+ SendMessage(tooltip_hwnd_, TTM_RELAYEVENT, 0, (LPARAM)&msg);
+}
+
+void TooltipManagerWin::ShowKeyboardTooltip(View* focused_view) {
+ if (tooltip_showing_) {
+ SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+ tooltip_text_.clear();
+ }
+ HideKeyboardTooltip();
+ string16 tooltip_text;
+ if (!focused_view->GetTooltipText(gfx::Point(), &tooltip_text))
+ return;
+ gfx::Rect focused_bounds = focused_view->bounds();
+ gfx::Point screen_point;
+ focused_view->ConvertPointToScreen(focused_view, &screen_point);
+ keyboard_tooltip_hwnd_ = CreateWindowEx(
+ WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+ TOOLTIPS_CLASS, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+ if (!keyboard_tooltip_hwnd_)
+ return;
+
+ SendMessage(keyboard_tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0,
+ std::numeric_limits<int16>::max());
+ int tooltip_width;
+ int line_count;
+ TrimTooltipToFit(&tooltip_text, &tooltip_width, &line_count,
+ screen_point.x(), screen_point.y());
+ ReplaceSubstringsAfterOffset(&tooltip_text, 0, L"\n", L"\r\n");
+ TOOLINFO keyboard_toolinfo;
+ memset(&keyboard_toolinfo, 0, sizeof(keyboard_toolinfo));
+ keyboard_toolinfo.cbSize = sizeof(keyboard_toolinfo);
+ keyboard_toolinfo.hwnd = GetParent();
+ 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 =
+ views::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,
+ base::Bind(&TooltipManagerWin::DestroyKeyboardTooltipWindow,
+ keyboard_tooltip_factory_.GetWeakPtr(),
+ keyboard_tooltip_hwnd_),
+ kDefaultTimeout);
+}
+
+void TooltipManagerWin::HideKeyboardTooltip() {
+ if (keyboard_tooltip_hwnd_ != NULL) {
+ SendMessage(keyboard_tooltip_hwnd_, WM_CLOSE, 0, 0);
+ keyboard_tooltip_hwnd_ = NULL;
+ }
+}
+
+void TooltipManagerWin::DestroyKeyboardTooltipWindow(HWND window_to_destroy) {
+ if (keyboard_tooltip_hwnd_ == window_to_destroy)
+ HideKeyboardTooltip();
+}
+
+} // namespace views
« no previous file with comments | « views/widget/tooltip_manager_win.h ('k') | views/widget/widget.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698