| Index: ui/views/controls/tree/tree_view.cc
|
| diff --git a/ui/views/controls/tree/tree_view.cc b/ui/views/controls/tree/tree_view.cc
|
| index 8a10bbdcef7e4aeee9f8940da22c27a8f3f8726a..10a17b05fb8eb37ab73c3f783b1255b04ee11fb2 100644
|
| --- a/ui/views/controls/tree/tree_view.cc
|
| +++ b/ui/views/controls/tree/tree_view.cc
|
| @@ -25,6 +25,7 @@
|
| #include "ui/views/controls/textfield/textfield.h"
|
| #include "ui/views/controls/tree/tree_view_controller.h"
|
| #include "ui/views/resources/grit/views_resources.h"
|
| +#include "ui/views/style/platform_style.h"
|
|
|
| using ui::TreeModel;
|
| using ui::TreeModelNode;
|
| @@ -68,6 +69,12 @@ ui::NativeTheme::ColorId text_color_id(bool has_focus, bool is_selected) {
|
| return ui::NativeTheme::kColorId_TreeText;
|
| }
|
|
|
| +bool EventIsDoubleTapOrClick(const ui::LocatedEvent& event) {
|
| + if (event.type() == ui::ET_GESTURE_TAP)
|
| + return event.AsGestureEvent()->details().tap_count() == 2;
|
| + return !!(event.flags() & ui::EF_IS_DOUBLE_CLICK);
|
| +}
|
| +
|
| } // namespace
|
|
|
| TreeView::TreeView()
|
| @@ -243,7 +250,7 @@ void TreeView::SetSelectedNode(TreeModelNode* model_node) {
|
| }
|
|
|
| if (selected_node_)
|
| - ScrollRectToVisible(GetBoundsForNode(selected_node_));
|
| + ScrollRectToVisible(GetForegroundBoundsForNode(selected_node_));
|
|
|
| // Notify controller if the old selection was empty to handle the case of
|
| // remove explicitly resetting selected_node_ before invoking this.
|
| @@ -392,13 +399,7 @@ void TreeView::ShowContextMenu(const gfx::Point& p,
|
| // ContextMenuController) if over a node.
|
| gfx::Point local_point(p);
|
| ConvertPointFromScreen(this, &local_point);
|
| - int row = (local_point.y() - kVerticalInset) / row_height_;
|
| - int depth = 0;
|
| - InternalNode* node = GetNodeByRow(row, &depth);
|
| - if (!node)
|
| - return;
|
| - gfx::Rect bounds(GetBoundsForNodeImpl(node, row, depth));
|
| - if (!bounds.Contains(local_point))
|
| + if (!GetNodeAtPoint(local_point))
|
| return;
|
| }
|
| View::ShowContextMenu(p, source_type);
|
| @@ -536,7 +537,7 @@ base::string16 TreeView::GetTextForRow(int row) {
|
| gfx::Point TreeView::GetKeyboardContextMenuLocation() {
|
| int y = height() / 2;
|
| if (selected_node_) {
|
| - gfx::Rect node_bounds(GetBoundsForNode(selected_node_));
|
| + gfx::Rect node_bounds(GetForegroundBoundsForNode(selected_node_));
|
| gfx::Rect vis_bounds(GetVisibleBounds());
|
| if (node_bounds.y() >= vis_bounds.y() &&
|
| node_bounds.y() < vis_bounds.bottom()) {
|
| @@ -643,39 +644,19 @@ bool TreeView::OnClickOrTap(const ui::LocatedEvent& event) {
|
| CommitEdit();
|
| RequestFocus();
|
|
|
| - int row = (event.y() - kVerticalInset) / row_height_;
|
| - int depth = 0;
|
| - InternalNode* node = GetNodeByRow(row, &depth);
|
| - if (node) {
|
| - gfx::Rect bounds(GetBoundsForNodeImpl(node, row, depth));
|
| - if (bounds.Contains(event.location())) {
|
| - int relative_x = event.x() - bounds.x();
|
| - if (base::i18n::IsRTL())
|
| - relative_x = bounds.width() - relative_x;
|
| - if (relative_x < kArrowRegionSize &&
|
| - model_->GetChildCount(node->model_node())) {
|
| - if (node->is_expanded())
|
| - Collapse(node->model_node());
|
| - else
|
| - Expand(node->model_node());
|
| - } else if (relative_x > kArrowRegionSize) {
|
| - SetSelectedNode(node->model_node());
|
| - bool should_toggle = false;
|
| - if (event.type() == ui::ET_GESTURE_TAP) {
|
| - const ui::GestureEvent& gesture =
|
| - static_cast<const ui::GestureEvent&>(event);
|
| - should_toggle = gesture.details().tap_count() == 2;
|
| - } else {
|
| - should_toggle = (event.flags() & ui::EF_IS_DOUBLE_CLICK) != 0;
|
| - }
|
| - if (should_toggle) {
|
| - if (node->is_expanded())
|
| - Collapse(node->model_node());
|
| - else
|
| - Expand(node->model_node());
|
| - }
|
| - }
|
| - }
|
| + InternalNode* node = GetNodeAtPoint(event.location());
|
| + if (!node)
|
| + return true;
|
| +
|
| + bool hits_arrow = IsPointInExpandControl(node, event.location());
|
| + if (!hits_arrow)
|
| + SetSelectedNode(node->model_node());
|
| +
|
| + if (hits_arrow || EventIsDoubleTapOrClick(event)) {
|
| + if (node->is_expanded())
|
| + Collapse(node->model_node());
|
| + else
|
| + Expand(node->model_node());
|
| }
|
| return true;
|
| }
|
| @@ -728,7 +709,7 @@ void TreeView::LayoutEditor() {
|
|
|
| DCHECK(selected_node_);
|
| // Position the editor so that its text aligns with the text we drew.
|
| - gfx::Rect row_bounds = GetBoundsForNode(selected_node_);
|
| + gfx::Rect row_bounds = GetForegroundBoundsForNode(selected_node_);
|
| row_bounds.set_x(
|
| GetMirroredXWithWidthInView(row_bounds.x(), row_bounds.width()));
|
| row_bounds.set_x(row_bounds.x() + text_offset_);
|
| @@ -745,7 +726,7 @@ void TreeView::LayoutEditor() {
|
| void TreeView::SchedulePaintForNode(InternalNode* node) {
|
| if (!node)
|
| return; // Explicitly allow NULL to be passed in.
|
| - SchedulePaintInRect(GetBoundsForNode(node));
|
| + SchedulePaintInRect(GetBackgroundBoundsForNode(node));
|
| }
|
|
|
| void TreeView::PaintRows(gfx::Canvas* canvas,
|
| @@ -771,7 +752,15 @@ void TreeView::PaintRow(gfx::Canvas* canvas,
|
| InternalNode* node,
|
| int row,
|
| int depth) {
|
| - gfx::Rect bounds(GetBoundsForNodeImpl(node, row, depth));
|
| + gfx::Rect bounds(GetForegroundBoundsForNodeImpl(node, row, depth));
|
| + const SkColor selected_row_bg_color = GetNativeTheme()->GetSystemColor(
|
| + text_background_color_id(HasFocus() || editing_));
|
| +
|
| + // Paint the row background.
|
| + if (PlatformStyle::kTreeViewSelectionPaintsEntireRow &&
|
| + selected_node_ == node) {
|
| + canvas->FillRect(GetBackgroundBoundsForNode(node), selected_row_bg_color);
|
| + }
|
|
|
| if (model_->GetChildCount(node->model_node()))
|
| PaintExpandControl(canvas, bounds, node->is_expanded());
|
| @@ -795,29 +784,34 @@ void TreeView::PaintRow(gfx::Canvas* canvas,
|
| icon, icon_x,
|
| bounds.y() + (bounds.height() - icon.height()) / 2);
|
|
|
| - if (!editing_ || node != selected_node_) {
|
| - gfx::Rect text_bounds(bounds.x() + text_offset_, bounds.y(),
|
| - bounds.width() - text_offset_, bounds.height());
|
| - if (base::i18n::IsRTL())
|
| - text_bounds.set_x(bounds.x());
|
| - if (node == selected_node_) {
|
| - const SkColor bg_color = GetNativeTheme()->GetSystemColor(
|
| - text_background_color_id(HasFocus()));
|
| - canvas->FillRect(text_bounds, bg_color);
|
| - if (HasFocus())
|
| - canvas->DrawFocusRect(text_bounds);
|
| - }
|
| - const ui::NativeTheme::ColorId color_id =
|
| - text_color_id(HasFocus(), node == selected_node_);
|
| - const gfx::Rect internal_bounds(
|
| - text_bounds.x() + kTextHorizontalPadding,
|
| - text_bounds.y() + kTextVerticalPadding,
|
| - text_bounds.width() - kTextHorizontalPadding * 2,
|
| - text_bounds.height() - kTextVerticalPadding * 2);
|
| - canvas->DrawStringRect(node->model_node()->GetTitle(), font_list_,
|
| - GetNativeTheme()->GetSystemColor(color_id),
|
| - internal_bounds);
|
| + // Paint the text background and text. In edit mode, the selected node is a
|
| + // separate editing control, so it does not need to be painted here.
|
| + if (editing_ && selected_node_ == node)
|
| + return;
|
| +
|
| + gfx::Rect text_bounds(GetTextBoundsForNode(node));
|
| + if (base::i18n::IsRTL())
|
| + text_bounds.set_x(bounds.x());
|
| +
|
| + // Paint the background on the selected row.
|
| + if (!PlatformStyle::kTreeViewSelectionPaintsEntireRow &&
|
| + node == selected_node_) {
|
| + canvas->FillRect(text_bounds, selected_row_bg_color);
|
| + if (HasFocus())
|
| + canvas->DrawFocusRect(text_bounds);
|
| }
|
| +
|
| + // Paint the text.
|
| + const ui::NativeTheme::ColorId color_id =
|
| + text_color_id(HasFocus(), node == selected_node_);
|
| + const gfx::Rect internal_bounds(
|
| + text_bounds.x() + kTextHorizontalPadding,
|
| + text_bounds.y() + kTextVerticalPadding,
|
| + text_bounds.width() - kTextHorizontalPadding * 2,
|
| + text_bounds.height() - kTextVerticalPadding * 2);
|
| + canvas->DrawStringRect(node->model_node()->GetTitle(), font_list_,
|
| + GetNativeTheme()->GetSystemColor(color_id),
|
| + internal_bounds);
|
| }
|
|
|
| void TreeView::PaintExpandControl(gfx::Canvas* canvas,
|
| @@ -868,15 +862,31 @@ TreeView::InternalNode* TreeView::GetInternalNodeForModelNode(
|
| model_->GetIndexOf(parent_internal_node->model_node(), model_node));
|
| }
|
|
|
| -gfx::Rect TreeView::GetBoundsForNode(InternalNode* node) {
|
| +gfx::Rect TreeView::GetBackgroundBoundsForNode(InternalNode* node) {
|
| + if (!PlatformStyle::kTreeViewSelectionPaintsEntireRow)
|
| + return GetForegroundBoundsForNode(node);
|
| +
|
| + int row, ignored_depth;
|
| + row = GetRowForInternalNode(node, &ignored_depth);
|
| + return gfx::Rect(bounds().x(), row * row_height_ + kVerticalInset,
|
| + bounds().width(), row_height_);
|
| +}
|
| +
|
| +gfx::Rect TreeView::GetForegroundBoundsForNode(InternalNode* node) {
|
| int row, depth;
|
| row = GetRowForInternalNode(node, &depth);
|
| - return GetBoundsForNodeImpl(node, row, depth);
|
| + return GetForegroundBoundsForNodeImpl(node, row, depth);
|
| }
|
|
|
| -gfx::Rect TreeView::GetBoundsForNodeImpl(InternalNode* node,
|
| - int row,
|
| - int depth) {
|
| +gfx::Rect TreeView::GetTextBoundsForNode(InternalNode* node) {
|
| + gfx::Rect bounds(GetForegroundBoundsForNode(node));
|
| + bounds.Inset(text_offset_, 0, 0, 0);
|
| + return bounds;
|
| +}
|
| +
|
| +gfx::Rect TreeView::GetForegroundBoundsForNodeImpl(InternalNode* node,
|
| + int row,
|
| + int depth) {
|
| gfx::Rect rect(depth * kIndent + kHorizontalInset,
|
| row * row_height_ + kVerticalInset,
|
| text_offset_ + node->text_width() +
|
| @@ -906,6 +916,21 @@ int TreeView::GetRowForInternalNode(InternalNode* node, int* depth) {
|
| return row;
|
| }
|
|
|
| +TreeView::InternalNode* TreeView::GetNodeAtPoint(const gfx::Point& point) {
|
| + int row = (point.y() - kVerticalInset) / row_height_;
|
| + int depth = -1;
|
| + InternalNode* node = GetNodeByRow(row, &depth);
|
| + if (!node)
|
| + return nullptr;
|
| +
|
| + // If the entire row gets a selected background, clicking anywhere in the row
|
| + // serves to hit this node.
|
| + if (PlatformStyle::kTreeViewSelectionPaintsEntireRow)
|
| + return node;
|
| + gfx::Rect bounds(GetForegroundBoundsForNodeImpl(node, row, depth));
|
| + return bounds.Contains(point) ? node : nullptr;
|
| +}
|
| +
|
| TreeView::InternalNode* TreeView::GetNodeByRow(int row, int* depth) {
|
| int current_row = root_row();
|
| *depth = 0;
|
| @@ -1014,6 +1039,23 @@ PrefixSelector* TreeView::GetPrefixSelector() {
|
| return selector_.get();
|
| }
|
|
|
| +bool TreeView::IsPointInExpandControl(InternalNode* node,
|
| + const gfx::Point& point) {
|
| + if (!model_->GetChildCount(node->model_node()))
|
| + return false;
|
| +
|
| + int depth = -1;
|
| + int row = GetRowForInternalNode(node, &depth);
|
| +
|
| + int arrow_dx = depth * kIndent + kHorizontalInset;
|
| + gfx::Rect arrow_bounds(bounds().x() + arrow_dx,
|
| + row * row_height_ + kVerticalInset, kArrowRegionSize,
|
| + row_height_);
|
| + if (base::i18n::IsRTL())
|
| + arrow_bounds.set_x(bounds().width() - arrow_dx - kArrowRegionSize);
|
| + return arrow_bounds.Contains(point);
|
| +}
|
| +
|
| // InternalNode ----------------------------------------------------------------
|
|
|
| TreeView::InternalNode::InternalNode()
|
|
|